Use a List called "Path" to store the way-points that describe your path, and a doubly-linked list called "Snake" to store the moving objects and Path.
The leading object defines new way-points as it travels. The following objects move along the path as defined by these way-points.
Each object has a security zone defined by some distance. If the leading object stops, the following objects move on only until they would touch the security zone of their predecessor.
Here's some pseudo-code for how these things could interact:be implemented. Be aware that this is not by any means the most elegant solution in terms of distribution of responsibilities and encapsulation.
class Path extends List {
property WayPoints = array();
property securityDistance = 10;
function moveAlong(currentPosition, distance, nextWayPoint, positionInTheSnake) {
distanceToEndOfPath = ... // something involving this->getDistanceToEnd()
if(distanceToEndOfPath < positionInTheSnake * this->securityDistance) {
return this->getPositionFromEnd(positionInTheSnake * this->securityDistance);
}
return (currentPosition + distance on the path)
}
// Finds out the distance to the end of the path recursively
function getDistanceToEnd(WayPoint, distanceCarriedOver = 0) {
if(WayPoint == this->last()) {
return distanceCarriedOver;
}
distanceCarriedOver += this->getDistance(WayPoint, WayPoint->next());
return getDistanceToEnd(WayPoint->next(), distanceCarriedOver);
}
function getPositionFromEnd(distance) {
return (some position);
}
}
class Snake extends DoublyLinkedList {
property Path;
property MovingObjects = array();
}
abstract class MovingObject {
property Snake; // shared among all moving objects of the same snake
property position;
abstract function move() { }
// + stuff for doubly-linked list elements
}
class MovingObjectLeader {
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 {
function move(alreadyTraveled = 0) {
this->position = this->Snake->Path->moveAlong(this->Snake->speed);
if(this->hasFollower()) {
this->follower->move();
}
}
}
The leading object defines new way-points as it travels. The following objects move along the path as defined by these way-points.
Each object has a security zone defined by some distance. If the leading object stops, the following objects move on only until they would touch the security zone of their predecessor.