Utilisez une liste appelée "Chemin" pour stocker les points de cheminement qui décrivent votre chemin, et une liste à double lien appelée "Serpent" pour stocker les objets en mouvement et le Chemin.
L'objet principal définit de nouveaux points de cheminement lors de son déplacement. Les objets suivants se déplacent le long du chemin défini par ces points de cheminement.
Chaque objet a une zone de sécurité définie par une certaine distance. Si l'objet principal s'arrête, les objets suivants se déplacent uniquement jusqu'à ce qu'ils touchent la zone de sécurité de leur prédécesseur.
Voici un pseudo-code pour savoir comment ces choses pourraient être implémentées. Sachez que ce n'est peut-être pas la solution la plus élégante en termes de répartition des responsabilités et d'encapsulation.
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 devient de plus en plus grand plus le jeu se poursuit. Si votre serpent existe depuis un certain temps, vous devez supprimer le dernier WayPoint chaque fois que le dernier élément du serpent a passé l'avant-dernier WayPoint du chemin. N'oubliez pas de réduire également distanceFromEnd dans tous les MovingObjects of Snake en conséquence.
Essentiellement, vous aurez besoin de deux structures de données (logique, intrusive ou réelle, selon le reste de votre code). Le premier suivra les chaînes d'objets et l'autre le chemin.
Chaîne Il vous suffit de savoir quels objets suivent d'autres objets. Dans le cas le plus simple, ce sera simplement A suit B, mais pourrait inclure plus de followers. Il y a un leader désigné dans la chaîne.
Chemin Pour chaque chaîne, vous aurez besoin d'un chemin. En fonction de la façon dont votre jeu fonctionne, cela déterminera la façon dont cela sera structuré. Dans la plupart des cas, il s'agira d'une sorte de liste chaînée. Cela permettra de suivre les positions que tout le monde dans la chaîne doit suivre.
Maintenant, le leader de la chaîne ajoutera des éléments au chemin . Chaque fois qu'il se déplace, il ajoute quelque chose en tête de liste. Chaque objet de la chaîne se souvient où il se trouve sur la liste. Lorsqu'il s'agit de se déplacer, il passe simplement à l'élément suivant de la liste (interpolé de manière appropriée si nécessaire). Lorsque le dernier élément de la chaîne passe devant un élément de la liste, cet élément peut être supprimé (ce sera à la queue).
Métaphoriquement, le leader laisse un fil d'Ariane à ses partisans. Le dernier suiveur de la liste consomme le fil d'Ariane.
Que votre liste contienne des points individuels, ou simplement les sommets d'un chemin, ou autre chose, est entièrement déterminé par votre moteur de jeu. Mais en tout cas, je ne vois pas que vous pourrez éviter la liste elle-même.
la source
Recherche A * pathfinding. C'est un moyen général et facile pour que vos entités / objets de jeu se rendent / suivent une position.
la source