Use uma lista chamada "Caminho" para armazenar os pontos de referência que descrevem o seu caminho, e uma lista duplamente vinculada chamada "Cobra" para armazenar os objetos em movimento e o Caminho.
O objeto principal define novos pontos de referência à medida que viaja. Os seguintes objetos se movem ao longo do caminho, conforme definido por esses pontos de referência.
Cada objeto tem uma zona de segurança definida por alguma distância. Se o objeto principal parar, os objetos a seguir serão movidos apenas até que toquem na zona de segurança de seu predecessor.
Aqui está um pseudocódigo de como essas coisas podem ser implementadas. Esteja ciente de que essa pode não ser a solução mais elegante em termos de distribuição de responsabilidades e encapsulamento.
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();
}
}
}
Caminho-> WayPoints se torna cada vez maior quanto mais o jogo continuar. Se o seu Snake existir há algum tempo, você precisará excluir o último WayPoint sempre que o último elemento do Snake tiver passado o penúltimo WayPoint do caminho. Lembre-se de reduzir também o distanceFromEnd em todos os MovingObjects of Snake.
Essencialmente, você precisará de duas estruturas de dados (lógicas, intrusivas ou reais, dependendo do restante do seu código). O primeiro rastreará as cadeias de objetos e o outro o caminho.
Cadeia Simplesmente você precisa saber quais objetos estão seguindo outros objetos. No caso mais simples, isso será simplesmente A segue B, mas pode incluir mais seguidores. Existe um líder designado na cadeia.
Caminho Para cada cadeia, você precisará de um caminho. Dependendo de como o jogo funciona, determinará como isso está estruturado. Na maioria dos casos, será algum tipo de lista vinculada. Isso rastreará as posições que todos na cadeia precisam seguir.
Agora, o líder da cadeia estará adicionando itens ao caminho . Cada vez que se move, adiciona algo ao cabeçalho da lista. Cada objeto na cadeia lembra onde está a lista. Quando se trata de mover, simplesmente passa para o próximo item da lista (interpolado adequadamente, se necessário). À medida que o último item da cadeia passa por um item da lista, esse item pode ser descartado (estará na cauda).
Metaforicamente, o líder deixa uma trilha de migalhas para seus seguidores. O último seguidor na lista consome a trilha de navegação.
Se sua lista contém pontos individuais, ou apenas os vértices de um caminho, ou qualquer outra coisa, é determinado inteiramente pelo seu mecanismo de jogo. Mas, de qualquer forma, não vejo que você consiga evitar a própria lista.
fonte
Pesquisa A * pathfinding. Esta é uma maneira geral e fácil de fazer com que suas entidades / objetos do jogo sigam / sigam uma posição.
fonte