Building Tower defence World

Started by
14 comments, last by rinkuhero 16 years, 10 months ago
Ok, so I have like 50 little circles created *being enemies* which are instances of an Enemy class held in an Enemy ** array. Now i need to build the world in which they are attacked and they travel, and where the towers will be built. I have absolutely no idea where to begin or what i need to do. On first thoughts it seemed as if I could just do if enemy->x is near to tower->x and run thrugh every single enemy on every single iteration of the game loop etc and the same with y but i dont know if thats a good idea! Can you let me know of any better ideas and explain them to me easily, I am using c++ with SDL. Thanks Andy
Advertisement
Quote:Original post by Renegadeandy
On first thoughts it seemed as if I could just do if enemy->x is near to tower->x and run thrugh every single enemy on every single iteration of the game loop etc and the same with y but i dont know if thats a good idea!

That should work out fine. Provided there won't be thousands of towers on the go, the tests will go faster than you'd guess. If you do have zillions of towers (or critters, or both) then some level of spatial partitioning will be necessary to cut out unnecessary tests on the macro-scale, but I doubt this will be necessary. Profile first, optimise later.

Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
STL containers > arrays

First, I'd throw away the array approach and go with a dynamically resizeable container, like std::vector or std::deque. Basically, these allow you to add and remove objects whenever you want, so you don't have to know how many objects you'll need beforehand. You may want to read up on how they work, but for now that should be all you need to know.


Building grid and movement path

Second, the world. I'd split up the movement and the building part: the building is probably best done using a grid, where a building can occupy one or more tiles. The monster movement can be done by creating a nodegraph: a path that consists of multiple nodes, each pointing to the next one.

So, for the building process, you can keep a simple 2D array (or a vector containing a vector) of booleans. Whenever you want to place a building, you check if the tile at the given coordinate has already been occupied. If it is, then you can't build there. If it isn't, then you can. Then when you build a building, you change the value of those tiles.
That doesn't deal with the buildings themselves however, just with where you can build them. You'll need to keep track of the buildings you've built so far, and run through them every cycle so they can target enemies, fire their stuff and so on. Oh, and each tower would need to know what tiles it occupies, so that when you sell it, you can reset those tiles in the grid.

For the movement, I'd create a list of linked nodes, each containing a position and a reference to the next node. Whenever a new monster appears, you simply set it's position to that of the first node, and also set this node as it's current destination. For the movement, a monster should check it's position agains that of it's destination node, and if it's the same (or within a very small radius - floating point isn't that precise ;)), then it should set it's destination to the node that it's current destination node points to.


Finding a target

A note about the attacking: you should write a function that goes through the list of monsters and returns a reference to the monster that is closest to the given point. Towers that are looking for a new target can then call this function, giving their location, to retreive the closest target. If the distance is less than their radius, they should store this monster reference as their current target, and start firing.

You may want to change this function though: weak towers may want to know about the weakest enemy in a certain range, while high damage towers should focus on the strongest enemy within their range. Or the most efficient target: the monster that can be killed with a single shot, with as little damage waste as possible. Anyway, just some things to consider for the target picking algorithm in relation to the tower and monster types.

Good luck! :)
Create-ivity - a game development blog Mouseover for more information.
Quote:Original post by Captain P
STL containers > arrays

...

So, for the building process, you can keep a simple 2D array (or a vector containing a vector) of booleans.


My recommendation would be boost::multi_array, since the storage should be rectangular.

Quote:
For the movement, I'd create a list of linked nodes, each containing a position and a reference to the next node.


Or you could, you know, keep up the good advice, and toss these in a standard library container as well. I don't see why not use a vector for these as well: these "waypoints" aren't likely to change often, so it makes sense to use a more compact representation.

Quote:Whenever a new monster appears, you simply set it's position to that of the first node, and also set this node as it's current destination. For the movement, a monster should check it's position agains that of it's destination node, and if it's the same (or within a very small radius - floating point isn't that precise ;)), then it should set it's destination to the node that it's current destination node points to.


If you represent the monster's velocity internally as a speed and angle (as opposed to x and y components), and limit its "turning radius", and set a fairly generous tolerance for the waypoints, you can cause the monsters to follow fairly nice, smoothly curved paths automatically - but it will take a bit more work to position the waypoints in a way that makes them stay on a "road", if you care about that.

Anyway, with the waypoints in a container, you set the destination to the next node in the container, rather than looking up some pointer value. One way to do this is to store an iterator over the container in the monster's structure, and increment it each time until it reaches the .end().



Otherwise, good post overall. You just got The Nod(TM); enjoy the ratings bump (from me, it's significant, apparently). [smile]

Right ,well i guess the place to start is show you what I currently have!

The file can be downloaded from here :

http://files-upload.com/246061/TowerDefence1.rar.html

Now.

I have been looking at boost::multiarray - is this just a multi dimensional array?

I dont understand how to use it , could you possibly implement a snippet of it which would be relevant to me as I use SDL which i could base my world upon?

Thanks all very much for such super advice you are a great help!

Also - enemy.cpp and enemy.h should really be using a linked list or vector or something other than a straight array but i dont know again how to use other data structures - any code help would be awesome!

Andy
Good calls, Zahlman. Thanks. :)

Yeah, for these nodes, I didn't meant to use a linked list, just to link them to each other using references. And yes, a container of positions would do the job just as well, as long as there's a way to retreive the next position when the current destination is reached. :)

And of course, vector math comes highly recommended.


As for using boost::multiarray or std::vector, this is what Google turned up: boost::multiarray and std::vector. Shouldn't be too hard to get used to. :)

As for SDL, it shouldn't really matter how you store your map data. You just tell SDL where to render those images and you're done with it.
Create-ivity - a game development blog Mouseover for more information.
Ok so this is what i have so far - but i dont really understand how to use this structure with a vector - ideally i would like instances of a class called Enemy to be stored in the vector - how would i do this.

If thats not possible - how on earth would i use the code i scrapped together below to make it work!

#include <vector>#include "generator2.h"using namespace std;typedef vector<Enemy> enemy*;{string name;float hp;float speed;string type;float direction;unsigned int colour;float x;float y;}generator2::generate(){}


Thanks guys!
You shouldn't mix up vector with the definition of your Enemy class or struct. You store Enemy instances in a vector, similar to how you would store them in an array.

A quick example:

class Enemy{public:	Enemy(string n) { name = n; }	string Name() { return name; }private:	string name;}// Elsewhere, we create a vector that can contain Enemy instances:vector<Enemy> enemies;// Add a new Enemy instance to the vector:enemies.push_back(Enemy("grunt"));// Accessing an Enemy instance inside the vector:enemies[0].Name(); // This call should return "grunt"// Or, if you want boundary checks:enemies.at(0).Name(); // Same here: this should return "grunt"


I would really recommend you to read up on these container classes. There's written more than enough about them. :)
Create-ivity - a game development blog Mouseover for more information.
How in an array did i need to hold an array of Enemy * then, as in Enemy**?


so far I have

Generator.h

#include "enemy.h"
#include <vector>
#include <string>



class Generator2{


public:

static vector<Enemy> generator2();


private:


}


and Generator2.cpp

#include <vector>
#include "generator2.h"



vector<Enemy> Generator2::generator2(){

vector<Enemy> enemies;

enemies.push_back(Enemy("grag",1000,5,"grang",50,50,0xff000ff));

return enemies;

}



but my usual trackload of errors lol, Nearly there i thikn - your help helps more than documentation and tutorials which i find i cannot relate to and are very un user friendly!

Thanks capitain!

Andy
What is this generator class supposed to do? What is it's function? The name is unclear (what does it generate?), and so is that function name. Tell me what you want with it and I can probably give better advice, as I think your design can also be a bit flawed at this point.
Create-ivity - a game development blog Mouseover for more information.

This topic is closed to new replies.

Advertisement