Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm wondering how objects follow each other where they move over the previous position of the object in front of them. When the leading object stops, all that are following should stop at their position. So how is this achieved?

Like so:

enter image description here

Edit:
What I want to achieve is that all the following objects "walk" the path the leading object in front is taking. All the other objects just move at the speed of the leading object ( this would be by passing the velocity vector to all the following objects). But how do I let all the objects move/pause over the path while maintaining their distance from each other as well.

share|improve this question

3 Answers 3

up vote 11 down vote accepted

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 be implemented. Be aware that this might not be the most elegant solution in terms of distribution of responsibilities and 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 becomes bigger and bigger the longer the game goes on. If your Snake exists for quite some time, you need to delete the last WayPoint whenever the last element of the Snake has passed the second-to-last WayPoint of Path. Remember to also reduce distanceFromEnd in all MovingObjects of Snake accordingly.

share|improve this answer
    
Let's say I would want to drag my leading object with my mouse( not that I want to, but let's say that I do ). How would that work with your example? –  Sidar Aug 24 '12 at 14:03
    
The list of objects could move by first letting the first element move from its current position in a given direction (with a given speed), and then letting all the other elements move from their current positions in a direction specified by their current position and $this->previousElement->getPosition(). If you drag your first element somewhere, you just have to call its setPosition() method. When the list is rendered, the other objects will change their path to follow their predecessors. –  BerndBrot Aug 24 '12 at 14:11
    
Correct me if I'm wrong but wouldn't that also result in the objects following taking shortcuts as they change direction? ( like in the lower part of the image i've given). It sounds like they wouldn't follow the path of the object up front. Instead they would go into the direction of the leading object infront of them as much as possible. Causing the objects going off path and taking shortcuts? –  Sidar Aug 24 '12 at 14:26
    
Yes, that would indeed happen with this particular implementation. I posted the answer before you added your pictures, so let's try again ... –  BerndBrot Aug 24 '12 at 14:35
    
Alright. What about this? –  BerndBrot Aug 24 '12 at 15:29

Lookup A* pathfinding. This is a general & easy way to have your game entities / objects go to/follow a position.

share|improve this answer
    
I know what A* is, not what I'm looking for and far too heavy for something that seems rather far more simple. –  Sidar Aug 24 '12 at 13:57
    
your answer is not even close to what the correct answer is. A* is an algorithm to find a path. While he doesn't want to find anything, he just wants object to follow each other exactly in every position last object was. –  Ali.S Aug 24 '12 at 21:52
    
When I originally answered the question it wasn't fixed to clarify more / there wasn't a picture to show what he meant. I just read the first 2 sentences and figured he was having multiple entities trying to track something, not follow a path. Sorry for the bad answer I guess –  thedeadlybutter Aug 25 '12 at 6:05
    
I did say follow each other =P not move to a point. –  Sidar Aug 25 '12 at 17:08
    
I know, my apologies. –  thedeadlybutter Aug 26 '12 at 0:10

Essentially you'll need two data structures (logical, intrusive, or real, depending on the rest of your code). The first will track the chains of objects, and the other the path.

Chain Simply you need to know which objects are following other objects. In the simplest case this will simply be A follows B, but could include more followers. There is a designated leader in the chain.

Path For each chain you'll need a path. Depending on how your game works will determine how this is structured. In most cases it will be some kind of linked list. This will track the positions that everybody in the chain needs to follow.

Now, the leader in the chain will be adding items to the path. Each time it moves it will add something to the head of the list. Each object in the chain remembers where on the list it is. When it comes to moving it simply moves to the next item in the list (interpolated appropriately if necessary). As the last item in the chain moves past an item in the list, that item can be dropped (it will be at the tail).

Metaphorically the leader leaves a breadcrumb trail for its followers. The last follower in the list consumes the breadcrumb.

Whether your list contains individual points, or just the vertices of a path, or something else, is determined entirely by your game engine. But in any case I don't see that you'll be able to avoid the list itself.

share|improve this answer
    
Yeah I figured such thing. It's the implementation that usually implodes my mind. Thanks for the answer though. Approved berndBrots answer but upvoted yours. –  Sidar Aug 24 '12 at 16:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.