I have been battling with this for some time and my noob brain can’t quite work it out. I have a standard tile map and currently use the following code to move my enemy sprite around the map
-(void) movePlayer:(ccTime)deltaTime {
if (CGPointEqualToPoint(self.position, requestedPosition))
return;
float step = kPlayerSpeed * deltaTime;
float dist = ccpDistance(self.position, requestedPosition);
CGPoint vectorBetweenAB = ccpSub(self.position, requestedPosition);
if (dist <= step) {
self.position = requestedPosition;
[self popPosition];
} else {
CGPoint normVectorBetweenAB = ccpNormalize(vectorBetweenAB);
CGPoint movementVectorForThisFrame = ccpMult(normVectorBetweenAB, step);
if (abs(vectorBetweenAB.x) > abs(vectorBetweenAB.y)) {
if (vectorBetweenAB.x > 0) {
[self runAnimation:walkLeft];
} else {
[self runAnimation:walkRight];
}
} else {
if (vectorBetweenAB.y > 0) {
[self runAnimation:walkDown];
} else {
[self runAnimation:walkUp];
}
}
if (self.position.x > movementVectorForThisFrame.x) {
movementVectorForThisFrame.x = -movementVectorForThisFrame.x;
}
if (self.position.y > movementVectorForThisFrame.y) {
movementVectorForThisFrame.y = -movementVectorForThisFrame.y;
}
self.position = ccpAdd(self.position, movementVectorForThisFrame);
}
}
movePlayer: is called by the classes updateWithDeltaTime: method. the ivar requestedPosition is set in the updateWithDeltaTime method as well, it basically gets the next point out of a queue to move to. These points can be anywhere on the map, so if they are in a diagonal direction from the enemy the enemy sprite will move directly to that point. But how do I change the above code to restrict the movement to vertical and horizontal movement only so that the enemies movement ‘staircases’ its way along a diagonal path, taking the manhattan distance (I think its called). As shown by my crude drawing below… S being the start point F being the finish and the numbers being each intermediate point along its path to create a staircase type diagonal movement. Finally I intend to be able to toggle this behaviour on and off, so that I can choose whether or not I want the enemy to move free around the map or be restricted to this horizontal / vertical movement only.
| | | | | | | | | |
| | | | | | | | | |
| |F| | | | | | | |
| |5|4| | | | | | |
| | |3|2| | | | | |
| | | |1|S| | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
So the current solution I have found is as follows…
So to begin with, I have the path of tile coordinates for the character saved in an ivar array for example…
So as you can see this has some points which would require so form of diagonal movement. I then call the pathfind method and this iterates over the requestedPositionQueue and adds all the intermediate tile coordinates ensuring it always picks a tile either vertically or horizontally but never diagonally next to the current tile until it completes the entire path.
Then in the update: method I iterate over the requestedPositionArray, taking the next tile coordinate from it, convert it to a pixel position then assign that to my requestedPosition ivar and then run the movePlayer: method (code in the original post).
I have put comments in the pathfind method for my own benefit and thus may not be that comprehensive but they may help your understanding of my thinking.
Finally this is the best I have come up with which allows me to ensure I can either move my character to a pixel position without restrictions or if I want move them there but confine them to only moving vertically or horizontally via tile centres. So if you can see a way to refine and optimise this code please do, or any constructive criticism will always be appreciated.
EDIT: The FIXME: in there highlights a potential bug that I haven’t had time to look at yet. I will repost once I have investigated and fixed if required.