Technika dla obiektów poruszających się w pełnym ruchu?

14

Zastanawiam się, jak obiekty podążają za sobą w miejscu, w którym poruszają się nad poprzednią pozycją obiektu przed sobą. Kiedy wiodący obiekt się zatrzyma, wszyscy, którzy podążają za nim, powinni zatrzymać się w swoim położeniu. Jak to się osiąga?

Tak jak:

wprowadź opis zdjęcia tutaj

Edycja:
Chcę osiągnąć to, aby wszystkie następujące obiekty „kroczyły” ścieżką wiodącą przed sobą. Wszystkie pozostałe obiekty poruszają się z prędkością obiektu wiodącego (byłoby to przez przekazanie wektora prędkości do wszystkich następujących obiektów). Ale w jaki sposób mogę pozwolić wszystkim przedmiotom przesuwać się / zatrzymywać na ścieżce, jednocześnie zachowując ich odległość od siebie.

Sidar
źródło

Odpowiedzi:

11

Użyć Listy o nazwie „Ścieżka”, aby zapisać punkty, które opisują Twoją ścieżkę, oraz podwójnie połączonej listy o nazwie „Wąż”, aby zapisać poruszające się obiekty i Ścieżkę.

Obiekt wiodący określa nowe punkty orientacyjne podczas podróży. Następujące obiekty poruszają się wzdłuż ścieżki zdefiniowanej przez te punkty trasy.

Każdy obiekt ma strefę bezpieczeństwa określoną przez pewną odległość. Jeśli wiodący obiekt się zatrzyma, następujące obiekty będą się poruszać tylko do momentu dotknięcia strefy bezpieczeństwa swojego poprzednika.

Oto pseudo-kod dla tego, jak te rzeczy mogą być zaimplementowane. Pamiętaj, że może to nie być najbardziej eleganckie rozwiązanie pod względem podziału obowiązków i hermetyzacji.

class Position {
    property x;
    property y;
}
class WayPoint extends ListNode {
    property position;
}
class Path extends List { 
    property WayPoints = array();

    // Find out the x, y coordinates given the distance traveled on the path
    function getPositionFromDistanceFromEnd(distance) {
        currentWayPoint = this->first();
        while(distance > 0) {
            distanceBetweenWayPoints = this->getDistance(currentWayPoint, currentWayPoint->next());
            if(distanceBetweenWayPoints > distance) {
                position = ... // travel remaining distance between currentWayPoint and currentWayPoint->next();
                return position;
            } else {
                distance -= distanceBetweenWayPoints;
                currentWayPoint = currentWayPoint->next();
            }
        }
    }
    function addWayPoint(position) {
        // Vector describing the current and new direction of movement
        currentDirection = this->first() - this->second();
        newDirection = position - this->first();
        // If the direction has not changed, there is no need to add a new WayPoint
        if( this->sameDirection(currentDirection, newDirection) {
            this->first->setPosition(position);
        } else {
            this->add(position);
        }
    }
}
class Snake extends DoublyLinkedList {
    property Path;
    property MovingObjects = array();
}
abstract class MovingObject extends DoublyLinkedListNode {
    property Snake; // shared among all moving objects of the same snake
    property position;
    const securityDistance = 10;
    abstract function move() { }
}
class MovingObjectLeader extends MovingObject {
    property direction;
    function move() {
        this->position += this->direction * this->Snake->speed;
        this->Snake->Path->addWayPoint(this->position);
        if(this->hasFollower()) {
            this->follower->move();
        }
    }
}
class MovingObjectFollower extends MovingObject {
    property distanceFromEnd;
    function move() {
        this->distanceFromEnd += this->Snake->speed;

        // If too close to leader: stop in order to respect security distance
        if(this->distanceFromEnd > this->leader()->distanceFromEnd - this->securityDistance) {
            this->distanceFromEnd = this->leader()->distanceFromEnd - this->securityDistance;
        }

        this->position = this->Snake->getPositionFromDistanceFromEnd(this->distanceFromEnd);

        if(this->hasFollower()) {
            this->follower->move();
        }
    }
}

Ścieżka-> WayPoints staje się tym większa, im dłużej gra trwa. Jeśli twój Wąż istnieje od dłuższego czasu, musisz usunąć ostatni WayPoint, ilekroć ostatni element Węża przekroczy drugi przedostatni WayPoint. Pamiętaj również, aby odpowiednio zmniejszyć distanceFromEnd we wszystkich MovingObjects of Snake.

BerndBrot
źródło
Powiedzmy, że chciałbym przeciągnąć mój wiodący obiekt za pomocą myszy (nie żebym tego chciał, ale powiedzmy, że tak). Jak by to działało z twoim przykładem?
Sidar
Lista obiektów może się poruszać, najpierw pozwalając pierwszemu elementowi przesunąć się z bieżącej pozycji w danym kierunku (z określoną prędkością), a następnie pozwalając wszystkim pozostałym elementom poruszać się z ich bieżących pozycji w kierunku określonym przez ich bieżącą pozycję i $ this-> previousElement-> getPosition (). Jeśli przeciągniesz gdzieś swój pierwszy element, wystarczy wywołać jego metodę setPosition (). Po wyrenderowaniu listy inne obiekty zmienią ścieżkę, aby podążać za swoimi poprzednikami.
BerndBrot
Popraw mnie, jeśli się mylę, ale czy nie spowodowałoby to, że obiekty podążałyby za skrótami podczas zmiany kierunku? (jak w dolnej części obrazu, który podałem). Wygląda na to, że nie podążą ścieżką obiektu z przodu. Zamiast tego poszliby w jak największym kierunku w kierunku prowadzącego obiektu przed nimi. Powodować, że przedmioty schodzą ze ścieżki i robią skróty?
Sidar
Tak, rzeczywiście tak by się stało z tym konkretnym wdrożeniem. Odpowiedziałem, zanim dodałeś swoje zdjęcia, więc spróbujmy jeszcze raz ...
BerndBrot
W porządku. A co z tym?
BerndBrot
6

Zasadniczo będziesz potrzebować dwóch struktur danych (logicznych, natrętnych lub rzeczywistych, w zależności od reszty kodu). Pierwszy będzie śledził łańcuchy obiektów, a drugi ścieżkę.

Łańcuch Po prostu musisz wiedzieć, które obiekty podążają za innymi obiektami. W najprostszym przypadku będzie to po prostu A po B, ale może obejmować więcej obserwujących. Jest wyznaczony lider łańcuchu .

Ścieżka Dla każdego łańcucha potrzebujesz ścieżki. W zależności od tego, jak działa twoja gra, określisz, jak to będzie zorganizowane. W większości przypadków będzie to jakaś połączona lista. Spowoduje to śledzenie pozycji, które musi przestrzegać każdy w łańcuchu.

Teraz lider w łańcuchu będzie dodawał przedmioty do ścieżki . Za każdym razem, gdy się poruszy, doda coś do nagłówka listy. Każdy obiekt w łańcuchu pamięta, gdzie jest na liście. Jeśli chodzi o przenoszenie, po prostu przechodzi do następnego elementu na liście (odpowiednio interpolowanego, jeśli to konieczne). Gdy ostatni element w łańcuchu przesuwa się obok elementu na liście, element ten można upuścić (będzie na ogonie).

Metaforycznie przywódca pozostawia ślad swoim partnerom. Ostatni obserwujący na liście zużywa bułkę tartą.

To, czy twoja lista zawiera pojedyncze punkty, czy tylko wierzchołki ścieżki, czy coś innego, zależy całkowicie od twojego silnika gry. Ale w każdym razie nie widzę, że będziesz w stanie ominąć samą listę.

edA-qa mort-ora-y
źródło
Tak, wymyśliłem coś takiego. To implementacja zwykle wszczepia mi się w pamięć. Dziękuję za odpowiedź. Zatwierdzona odpowiedź berndBrots, ale pozytywnie oceniona.
Sidar
-3

Wyszukaj ścieżkę *. Jest to ogólny i łatwy sposób, aby twoje podmioty / obiekty gry trafiły / podążały za pozycją.

thedeadlybutter
źródło
Wiem, co to jest A *, a nie to, czego szukam i zdecydowanie za ciężkie na coś, co wydaje się o wiele prostsze.
Sidar
twoja odpowiedź nie jest nawet bliska prawidłowej odpowiedzi. * Jest algorytmem do znalezienia ścieżki. Chociaż nie chce niczego znaleźć, po prostu chce, aby obiekt podążał za sobą dokładnie w każdej pozycji, w jakiej znajdował się ostatni obiekt.
Ali1S232,
Kiedy pierwotnie odpowiedziałem na pytanie, nie było wyjaśnienia więcej / nie było zdjęcia pokazującego, co miał na myśli. Właśnie przeczytałem pierwsze 2 zdania i doszedłem do wniosku, że wiele osób próbuje coś wyśledzić, a nie podąża ścieżką. Przepraszam za złą odpowiedź, jak sądzę
thedeadlybutter
Powiedziałem, że podążajcie za sobą = P nie przechodź do punktu.
Sidar,
Wiem, przepraszam.
thedeadlybutter