In this tutorial we are going to create the class that will handle the creation of our waves, update our waves, and then move the player onto the next wave when the previous one has finished.
This will be one of the most important classes in our game. We are going to store all our waves in one big queue, and just move through them one by one with a short period of time in-between waves so the player has time to breath and make new towers. This class will also determine how many enemies we create per wave, so we can make the waves harder as time progresses.
So, let’s get started, start off by creating a new class called “WaveManager.cs” and add the following fields and properties :
private int numberOfWaves; // How many waves the game will haveprivate float timeSinceLastWave; // How long since the last wave ended
private Queue<Wave> waves = new Queue<Wave>(); // A queue of all our waves
private Texture2D enemyTexture; // The texture used to draw the enemies
private bool waveFinished = false; // Is the current wave over?
private Level level; // A reference to our level class
public Wave CurrentWave // Get the wave at the front of the queue
{
get { return waves.Peek(); }
}
public List<Enemy> Enemies // Get a list of the current enemeies
{
get { return CurrentWave.Enemies; }
}
public int Round // Returns the wave number
{
get { return CurrentWave.RoundNumber + 1; }
}
public WaveManager(Level level, int numberOfWaves, Texture2D enemyTexture)
{
this.numberOfWaves = numberOfWaves;
this.enemyTexture = enemyTexture;
this.level = level;
for (int i = 0; i < numberOfWaves; i++)
{
int initialNumerOfEnemies = 6;
int numberModifier = (i / 6) + 1;
Wave wave = new Wave(i, initialNumerOfEnemies *
numberModifier, level, enemyTexture);
waves.Enqueue(wave);
}
}
private void StartNextWave()
{
if (waves.Count > 0) // If there are still waves left
{
waves.Peek().Start(); // Start the next one
timeSinceLastWave = 0; // Reset timer
waveFinished = false;
}
}
Here we just check if there is a wave to start, and if there is we start it, and reset our timer. We need to add a call to this method in our constructor otherwise our waves will never start! At the bottom of the constructor add this :
StartNextWave();
All that is left to do now is to update our waves and then draw them, let’s start by updating them :
public void Update(GameTime gameTime)
{
CurrentWave.Update(gameTime); // Update the wave
if (CurrentWave.RoundOver) // Check if it has finished
{
waveFinished = true;
}
if (waveFinished) // If it has finished
{
timeSinceLastWave += (float)gameTime.ElapsedGameTime.TotalSeconds; // Start the timer
}
if (timeSinceLastWave > 30.0f) // If 30 seconds has passed
{
waves.Dequeue(); // Remove the finished wave
StartNextWave(); // Start the next wave
}
}
public void Draw(SpriteBatch spriteBatch)
{
CurrentWave.Draw(spriteBatch);
}
//Wave wave;
WaveManager waveManager;
Then in our LoadContent() method instead of initializing a single wave, initialize our wave manager :
//wave = new Wave(0, 10, level, enemyTexture);
//wave.Start();
waveManager = new WaveManager(level, 24, enemyTexture);
protected override void Update(GameTime gameTime)
{
waveManager.Update(gameTime);
player.Update(gameTime, waveManager.Enemies);
base.Update(gameTime);
}
//wave.Draw(spriteBatch);
waveManager.Draw(spriteBatch);
And we are finished, we now have multiple waves!!
Awesome! Whats next?
ReplyDeletePlease continue this is a great set of examples. Thanks much!
ReplyDeleteamazing information for everybody looking forward to start a tower defense game.
ReplyDeletegood job!
how long till the second wave comes? I only waited 1 minute but that seems too long
ReplyDeletenevermind found it :)
ReplyDelete(timeSinceLastWave > 10.0f) // If 30 seconds has passed
Yea that's the line that needs to be changed :D
ReplyDeletewhere are we supposed to set the number of waves? I want 100 waves. So where do I put that?
ReplyDeleteHi Chicken,
ReplyDeleteYou would need to change this line in the Game1.cs LoadContent() method :
waveManager = new WaveManager(level, 24, enemyTexture);
to this :
waveManager = new WaveManager(level, 100, enemyTexture);
ah, ok thanks. Also, how do you draw the towers so amazingly? They are awesome and I want to learn how to do that.
ReplyDeleteAnd another thing too, if I want to make the bullet turn to face the enemy. My bullet is an arrow, not a ball and I want it to turn to the enemy when shot at it.
Just as a note: I'm not following the tutorial exactly, because I am actually going to add some stuff and put it on the Xbox Live Indie Games Marketplace, because I don't want to infringe on copyright or anything. But still, this tutorial is helping a lot. I will be sure to give you credit and a free download code FireFly!
I am glad you like my towers!!! I just started by drawing a square body for the base of the tower, and then kept tweaking the shape / symmetry of it until I was satisfied with it. Then to finish them off I added a radial gradient colour!
ReplyDeleteAs for the rotating bullets, they should already work with the code I posted in Tutorial 7. As long as your arrow points up, it should get rotated to the right direction!
It would be awesome to see some Tower Defences on the Xbox! It will be interesting to see what kind of control scheme you have created. I can't wait to see what you have come up with!
Ok thanks. 2 more things (sorry for so much asking XD)
ReplyDelete1) what photo editing program do you use?
2) I tried the rotation thing, but it freezes as soon as it shoots.
It's ok. I use Paint.Net to do all my drawing / editing.
ReplyDeleteWhat do you mean it freezes as soon as it shoots?
If you mean the bullet stops rotating when it is shot, make sure you are calling this line :
bullet.SetRotation(rotation);
somewhere in your tower Update() code.
I mean the game freezes and it gives me some error. I will try that line of code and get back to you. thanks.
ReplyDeleteAh ok, if you post the error I may be able to be more help.
ReplyDeleteedit:
ReplyDeleteIt works, i found out that the bullet was actually titled to the left, so it looked wrong. Thanks for your help though!
How would I go about making it so that you had to press a "ready" button before the next round started? I've almost got it now but when I press the button nothing happens. Its like the system is only checking if its ready instantly after the round is over, and after that never checking again.
ReplyDeleteHow can I change it to send another wave every 20 seconds regardless of the first wave is still running?
ReplyDeleteJust change:
ReplyDeleteif (CurrentWave.RoundOver) // Check if it has finished
{
waveFinished = true;
}
if (waveFinished) // If it has finished
{
timeSinceLastWave += (float)gameTime.ElapsedGameTime.TotalSeconds; // Start the timer
}
to:
timeSinceLastWave += (float)gameTime.ElapsedGameTime.TotalSeconds;
I already tried. So it probably will not be easy.
DeleteI'm not sure why that wouldn't work, what happened when you tried it? What went wrong?
ReplyDeleteThat not working because we using queue. Queue get only first wave. When we want to start new wave. Last wave disappear.
ReplyDeleteSo :) do you know how to do it ? :D
ReplyDeleteAh ok, then you will need to switch the queue to a list, and store an int which is an index into that list that tells you which the current wave.
ReplyDeleteThen in update you will probably need to replace:
CurrentWave.Update(gameTime);
with:
for(int i = 0; i <= currentWaveIndex; i++)
{
waves[i].Update(gameTime);
}
I also decided to use list but do not know how. So thank you. :)
DeleteAlso you would increment currentWaveIndex in the StartNextWave method and instead of doing:
ReplyDeleteif (waves.Count > 0)
do:
if (currentWaveIndex < waves.Count)
So now i am stuck :D how do I do with currentWaveIndex
ReplyDeleteYou would change:
ReplyDeleteQueue waves...
to:
List waves = new List();
int currentWaveIndex;
Then:
public Wave CurrentWave // Get the wave at the front of the queue
{
get { return waves.Peek(); }
}
to:
public Wave CurrentWave // Get the wave at the front of the queue
{
get { return waves[currentWaveIndex]; }
}
Then:
waves.Enqueue(wave);
to
waves.Add(wave)
Then:
if (waves.Count > 0) // If there are still waves left
{
waves.Peek().Start(); // Start the next one
timeSinceLastWave = 0; // Reset timer
waveFinished = false;
}
to:
if (currentWaveIndex < waves.Count) // If there are still waves left
{
waves[currentWaveIndex].Start(); // Start the next one
timeSinceLastWave = 0; // Reset timer
waveFinished = false;
}
Then:
if (timeSinceLastWave > 30.0f) // If 30 seconds has passed
{
waves.Dequeue(); // Remove the finished wave
StartNextWave(); // Start the next wave
}
to:
if (timeSinceLastWave > 30.0f) // If 30 seconds has passed
{
currentWaveIndex += 1;
StartNextWave(); // Start the next wave
}
Then:
CurrentWave.Update(gameTime);
with:
for(int i = 0; i <= currentWaveIndex; i++)
{
if (waves[i].WaveOver == false)
waves[i].Update(gameTime);
}
And finally:
CurrentWave.Draw(...
with:
for(int i = 0; i <= currentWaveIndex; i++)
{
if (waves[i].WaveOver == false)
waves[i].Draw(...
}
Yes :) this is what i want :) thank you very very much :)
ReplyDeleteNo worries :)
ReplyDeleteSorry but I need help again :( Now it is working and sending new wave on time but when it start new wave a tower stop shooting at last wave And shoot only on new. I think a bug is in CurrentWave. Tower shooting only on CurrentWave and that is changing when we change CurrentWaveIndex.
ReplyDeleteIf I were you I would probably just scrap the current wave system and maybe roll your own.
ReplyDeleteInstead of having the wave class store the enemies, maybe let the WaveManger store them and just let the Wave class add enemies to the master WaveManager.Enemies list.
Error 1 Inconsistent accessibility: property type 'tower_defence_1._0.Wave' is less accessible than property 'tower_defence_1._0.WaveManager.CurrentWave
ReplyDeletepublic Wave CurrentWave // Get the wave at the front of the queue Inconsistent accessibility: property type 'tower_defence_1._0.Wave' is less accessible than property please help
ReplyDeleteMake sure they are both public classes:
ReplyDeletepublic class Wave
public class WaveManager
Reviving an old thread here but just to let you know these tutorials are brilliant! thanks very much
ReplyDeleteThey are really helpful, though I'm now having trouble trying to add different kinds of enemies since Firefly doesn't seem to cover that, I've finished this tutorial series.
ReplyDeleteI was hoping that Wave or Wavemanager would make it simple to add new types of enemies but I just can't seem to figure it out.