Use una Lista llamada "Ruta" para almacenar los puntos de ruta que describen su ruta, y una lista doblemente vinculada llamada "Serpiente" para almacenar los objetos en movimiento y la Ruta.
El objeto principal define nuevos puntos de referencia a medida que viaja. Los siguientes objetos se mueven a lo largo de la ruta tal como se define en estos puntos intermedios.
Cada objeto tiene una zona de seguridad definida por cierta distancia. Si el objeto principal se detiene, los siguientes objetos se mueven solo hasta que toquen la zona de seguridad de su predecesor.
Aquí hay un pseudocódigo de cómo se podrían implementar estas cosas. Tenga en cuenta que esta podría no ser la solución más elegante en términos de distribución de responsabilidades y encapsulación.
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();
}
}
}
Path-> WayPoints se hace más y más grande cuanto más tiempo transcurre el juego. Si su Snake existe desde hace bastante tiempo, debe eliminar el último WayPoint cada vez que el último elemento de la Snake haya pasado el penúltimo WayPoint of Path. Recuerde reducir también distanceFromEnd en todos los MovingObjects of Snake en consecuencia.
Esencialmente, necesitará dos estructuras de datos (lógico, intrusivo o real, dependiendo del resto de su código). El primero rastreará las cadenas de objetos, y el otro el camino.
Cadena Simplemente necesita saber qué objetos siguen a otros objetos. En el caso más simple, esto será simplemente A sigue a B, pero podría incluir más seguidores. Hay un líder designado en la cadena.
Ruta Para cada cadena necesitarás una ruta. Dependiendo de cómo funcione su juego, determinará cómo está estructurado. En la mayoría de los casos, será algún tipo de lista vinculada. Esto hará un seguimiento de las posiciones que todos en la cadena deben seguir.
Ahora, el líder de la cadena agregará elementos a la ruta . Cada vez que se mueve, agregará algo al encabezado de la lista. Cada objeto en la cadena recuerda en qué parte de la lista está. Cuando se trata de moverlo, simplemente se mueve al siguiente elemento de la lista (interpolado de manera apropiada si es necesario). A medida que el último elemento de la cadena se mueve más allá de un elemento de la lista, ese elemento se puede soltar (estará en la cola).
Metafóricamente, el líder deja un rastro de migas de pan para sus seguidores. El último seguidor de la lista consume la miga de pan.
Si su lista contiene puntos individuales, o solo los vértices de un camino, o algo más, está determinado completamente por su motor de juego. Pero, en cualquier caso, no veo que puedas evitar la lista en sí.
fuente
Búsqueda A * pathfinding. Esta es una forma general y fácil de hacer que sus entidades / objetos del juego vayan / sigan una posición.
fuente