I’m looking for advice on how to approach this problem:
a variable number of “follower” sprites that queue behind the player: sprite 1 behind the player, sprite 2 behind sprite 1 and so on
the player and the sprite move across a top-down tiled map
followers should avoid obstacle tiles between them and the next sprite
the player and followers move orthogonally (no diagonals)
What would be the best approach? Raycasting, path finding or something else?
Thanks for any suggestions
Edit: to clarify my worry is that path finding (A* or breath-first search) are too expensive for this case and, before I invest in learning them, I want to be sure they are a viable solution
Yes, all obstacles are static (walls and such) and yes, I want my followers just to do what player does only delayed. I plan to have max 10-20 followers. So should I look into pathfinding or are there simpler solutions? Thanks
Just store your player actions.
Player goes right → up → up → right → left
Follower1 goes … right → up → up → right
Follower2 goes … … right → up → up
etc.
No need for pathfinding since you know exactly what to do.
That’s an option, but you can’t be sure your velocity and direction result in the same position. Physics is not very deterministic.
I would just store the actual player position every frame, for 10 seconds or so, which gives an array of 600 positions (at 60Hz). Push the new player position, and shift the array.
Follower1 then reads position[570],
Follower2 then reads position[540],
Follower3 then reads position[510],
etc.
No need for timers.Every follower is just 0.5 sec (30 frames) behind its leader.
Thank you! That’s a clever idea. It’s like building a timeline or history of positions and the followers are always 0.5s late. I’ve spent some hours yesterday and today trying to implement it, but I’m not getting everything right. If I keep pushing and shifting every frame my array is stuck at 1 position, but if I log all the position once at the beginning (like I’m doing now) obviously I don’t get the followers to move until the the arrays has reached a length of 600 (I now get an error when trying to access this.currentPosition too early)
export default class Play extends Phaser.Scene {
create() {
this.currentPosition = [];
this.timer = 0;
//create player, followers and so on
}
update(time, delta) {
if(this.timer < 10000) {
this.currentPosition.push([this.player.container.x, this.player.container.y]);
this.timer += delta;
}
if(this.player.container.body.velocity.x != 0 || this.player.container.body.velocity.y != 0) {
this.currentPosition.shift();
this.currentPosition.push([this.player.container.x, this.player.container.y]);
}
for (var i = this.followers.getLength() - 1; i >= 0; i--) {
var p = this.currentPosition[this.currentPosition.length - 30 * i];
var pp = new Phaser.Math.Vector2(p[0],p[1])
this.scene.physics.moveToObject(followers[i].container, pp);
}
}
}
Thank you for taking the time, I appreciate that. Now it works how I wanted. I kept the player movement check, otherwise all the followers would overlap the player once it stopped moving. With the check they queue behind the player if it stops.
export default class Play extends Phaser.Scene {
create() {
this.currentPosition = [];
this.currentPosition[600] = [this.player.container.x, this.player.container.y];
}
update(time,delta) {
if(this.player.container.body.velocity.x != 0 || this.player.container.body.velocity.y != 0) {
this.currentPosition.shift();
this.currentPosition.push([this.player.container.x, this.player.container.y]);
for (var i = 0; i < this.enemies.getChildren().length; i++) {
var p = this.currentPosition[this.currentPosition.length - 30 * (i+1)];
if(p != null) {
this.enemies.getChildren()[i].container.body.x = p[0];
this.enemies.getChildren()[i].container.body.y = p[1];
}
}
}
}
You’re very welcome.
Help the community by showing your results, if you can
Btw, this only works for 60Hz, if you run this on tablets or a 144Hz or so monitor you’ll run into problems, but that’s for later I guess
PS. You just shouldn’t use the last 30 frames. Now if the player stops, the followers stop. Lose the player movement check, and let them bunch up 30 frames behind…
Thanks for the heads up, I’m not planning to go on tablets, but I assume I could read the current frame rate and adjust the values accordingly.
I’m not sure I follow. I want them to stop when the player stops, otherwise they’ll reach the player’s position and overlap with the player, hiding it.
Btw, I don’t know what’s Discourse’s etiquette and if I should mark as solution one of your posts or one of mine with the code, let me know what you prefer
I think the easiest way is something like this:
If the player is not moving:
positions.splice(570, 0, positions[570]); positions.shift();
This copies 570 and moves the last 30 positions right, and then shifts like normal.
That way all the followers bunch up at follower1. They never reach the player.
Once the player moves again, go back to push and shift.
Whichever you feel answers your question best. If you feel your code is more clear then my abstract It’s just for the convenience of those after us.
@Milton I finally published the game that uses your solution for the queue we are discussing here. Your user name is in the credits and links to your Discourse profile.
It’s a free browser game of about 10 minutes of gameplay. The mechanic that uses the queue solution is a bit hidden, but it’s there: The Lives of Others by Piotr.one