I was thinking of making of a tower defense but I am curious of how the attackers follow a certain path like in Bloons Tower Defense , how do they make the balloons follow the path? Thanks in advance
If I were to make something like this I’d probably create an array of (X,Y) coords which would outline the entire path. As the sprites appear on the screen I’d just make the sprite go towards point 1, then 2, then 3, etc… It shouldn’t be too difficult if you think about it for a bit.
A common solution is to implement A* pathfinding. You can find many many examples of this online. Here is one I pulled from the interwebs:
http://old.cokeandcode.com/pathfinding
Here’s an example from wikipedia of how it works:
This allows the player more challenge in setting up their towers to cause the enemies to move in a different path than they originally did. Otherwise, you can simply have a 2d array of bools defining the grid, where true is the path they follow. Start them on the edge, check each direction and when you find a true, go that way and store the OPPOSITE of your last directional move (UL, U, UR, L, R, DL, D, DR) and make sure you skip that direction on the next tile check.
Just make a chain of coordinates to move to, each one only containing the coordinates of the next, then tell the sprites to move through the coordinates in the order of the chain.
How would I tell the spirits to move through a set of coordinates?
@LunaticEdit I think he’s asking for predetermined paths/routes that the enemies run through, not pathfinding.
@wreed12345 You can use a linked list or something to store the coordinates, you can use Bresenham’s line algorithm to find the tiles that are in between the points (not sure if bresenham’s is necessarily a good idea, only experimented with it very briefly).
Think about it. Think about it very carefully. If you are still stuck, use Google. If that doesn’t help, ask here again.
It completely depends on how your map is organized, but I’m going to assume you have a map filled with tiles on a double array. In this example, I’ll use a play field that has 10x10 tiles in length and width.
[icode] int[][] tiles = new int[10][10]; [/icode]
To make this pretty easy, you’ll want to make a predetermined path for the units to follow. For this example, I’ll make the object travel along a straight line. You want to make a basic enemy object that will correspond to your map.
public class Enemy{
public int x;//The x-axis position of the enemy
public int y;//The y-axis position of the enemy
}
In the place where you update the code, you’ll want to make sure you take timed steps in between each movement. For this object, I’ll have him move from [icode] (5, 10) [/icode] to [icode] (5, 0) [/icode].
public Enemy enemy;
public void init(){
enemy = new Enemy();
enemy.x = 5;
enemy.y = 10;
}
public void update( ... ){
//Have a certain amount of time elapse before each movement.
if(enemy > 0)
enemy.y -= 1;
}
If you want more advanced movements though, the easiest way would be to put the path into an array. Like…
[icode] int[] xPath; [/icode]
[icode] int[] yPath; [/icode]
You can then traverse each array like a group to have a perfect predetermined path. Here is the same example using this method.
public Enemy enemy;
public int counter;
public int[] xPath;
public int[] yPath;
public void init(){
enemy = new Enemy();
enemy.x = 5;
enemy.y = 10;
counter = 0;
xPath = new int[]{ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
yPath = new int[]{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
}
...
public void update( ... ){
//Have a certain amount of time elapse before each movement.
if(counter < xPath.length()){
enemy.x = xPath[counter];
enemy.y = yPath[counter];
counter++;
}
}
These are two valid ways of achieving exact movement along a path. There are more ways to do it of course, and these are very basic. Pac-Man source is pretty helpful when dealing with paths if you needed some deeper knowledge.
So many of you seem to never have played Bloons TD! I liked that game so much when I way younger… yes even younger.
ctomni231 and LunaticEdit, the examples you gave better fit to a tower defense game like Warzone TD. (I personally find this much more cool but yeah…)
Anyways, here is how you’d do it:
You define a set of points. I use a class called [icode]Vec2[/icode], which is basically a class with [icode]public float x, y;[/icode] fields.
I then use this to create a path:
public ArrayList<Vec2> createPath() {
ArrayList<Vec2> path = new ArrayList<>();
path.add(new Vec2(0, 0));
path.add(new Vec2(10.5f, 20.3f));
path.add(new Vec2(2.4f, 50.2f));
// ...
// ...
// and even more ...
// and finally:
path.trimToSize(); // <- optional
return path; // <- definitely not optional ;D
}
Then you have your entity (I have no idea how your “balloon” class looks like, so I just use a class called [icode]Entity[/icode]):
public class Entity() {
private ArrayList<Vec2> path;
private Vec2 position;
// I know the names a pretty long, but I try
// to make them descriptive. In the end you
// might want to make them a bit more
// compact.
// the distance you already traveled
// (only between the current and next
// point. This variable is reset to 0, when
// you reach the next point)
private float distanceTraveled;
// distance between the current and next
// point.
private float distanceBetweenCurrentPoints;
// the index of the current point.
private int currentPointIndex = 0;
public Entity(ArrayList<Vec2> pathToFollow) {
this.path = pathToFollow; // <- Ah. Here it is again :)
this.position = new Vec2(path.get(currentPointIndex));
distanceTraveled = 0f;
distanceBetweenCurrentPoints = distance(path.get(currentPointIndex), path.get(currentPointIndex+1));
}
public void tick() {
Vec2 lastPoint = path.get(currentPointIndex);
Vec2 nextPoint = path.get(currentPointIndex+1);
distanceTraveled = distance(position, lastPoint);
// So we now got the last Point we wanted to pass
// and the next point we need to go to.
// We also have the distance we traveled from the
// last point in the direction of the next point.
// We also have the distance between the points
// we are about to travel along.
// We now move "forward" by simply adding
// a little number of pixels to the "distanceTraveled"
// and then compute a weight from them to update
// our current position.
distanceTraveled += /* Speed in pixels */ 1f;
// But what if we've reached the next point now :O
if (distanceTraveled > distanceBetweenCurrentPoints) {
// !!! Could cause ArrayIndexOutOfBoundsException (AIOOBE),
// if we are at the end of the path ...
currentPointIndex++;
// In case we moved 50 pixels, but the distance was
// only 49 pixels, we already move 1 pixel forward.
// That looks better in the end.
distanceTraveled -= distanceBetweenCurrentPoints;
} else {
float weight = distanceTraveled / distanceBetweenCurrentPoints;
// Phew. we've got this.
position = interpolate(lastPoint, nextPoint, weight, position);
}
}
// This has to be optimized, but that is better
// done after one has done writing the algorithm.
// Hint: Use squared distances.
public float distance(Vec2 point0, Vec2 point1) {
float dx = point1.x-point0.x;
float dy = point1.y-point0.y;
// Hello pythagoras :)
return Math.sqrt(dx * dx + dy * dy);
}
// The heart of all methods in this code example!
// This takes to points and gives you a point on
// the line from point0 to point1. To define where
// the point should be on the line, we give the method
// a weight. This weight should have values between
// 0 and 1. 0.5 gives the point exact between point0 and point1.
// positionDst is there, so we don't have to create a new Vec2();
// everytime we want to get out position. This would increase
// the memory usage drastically.
public Vec2 interpolate(Vec2 point0, Vec2 point1, float weight, Vec2 positionDst) {
// This is just a somehow slightly changed version of getting
// the average from two numbers. We include weights here.
positionDst.x = (point0.x * weight) + (point1.x * (1f - weight));
positionDst.y = (point0.y * weight) + (poitn1.y * (1f - weight));
return positionDst;
}
}
This is of course missing a lot of optimization. Especially in the distance part.
This would also cause a AIOOBE when the Entity reaches the end of the path, as described in the code.