In this, the last tutorial in the series, I will show you how to add a bit of polish to the game by adding a few key features to our game :
- Giving the player money when he kills an enemy.
- Removing a life when one of the enemies reaches the end of the path.
Both of these things will be implemented in the wave class, however before we make any changes to that we must first make some of the player’s properties settable!
So go to the Player class and find the Money and Lives properties and a set statement to both of them :
public int Money
{
get { return money; }
set { money = value; }
}
public int Lives
{
get { return lives; }
set { lives = value; }
}
This will allow us to make changes to these properties outside of the player class. We are now ready to add our two key features! Go to the Wave class and somewhere with the fields add a Player field :
private Player player; // A reference to the player.
Now we need to pass a reference to the player via the constructor, so change the Wave constructor to accept a player reference :
public Wave(int waveNumber, int numOfEnemies,
Player player, Level level, Texture2D enemyTexture)
{
this.waveNumber = waveNumber;
this.numOfEnemies = numOfEnemies;
this.player = player; // Reference the player.
this.level = level;
this.enemyTexture = enemyTexture;
}
if (enemy.IsDead)
{
if (enemy.CurrentHealth > 0) // Enemy is at the end
{
enemyAtEnd = true;
player.Lives -= 1;
}
else
{
player.Money += enemy.BountyGiven;
}
Simple huh? I can’t beleive I left it until the end to add these features in that actually make our game playable! With those changes made, that if statement should look like this :
if (enemy.IsDead)
{
if (enemy.CurrentHealth > 0) // Enemy is at the end
{
enemyAtEnd = true;
player.Lives -= 1;
}
else
{
player.Money += enemy.BountyGiven;
}
enemies.Remove(enemy);
i--;
}
All that is left now is to pass the player reference to the Wave class. So go to the WaveManager class and modify the constructor so that it takes in a reference to the Player class and then passes it to the Wave class :
public WaveManager(Player player, 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;
// Pass the reference to the player, to the wave class.
Wave wave = new Wave(i, initialNumerOfEnemies *
numberModifier, player, level, enemyTexture);
waves.Enqueue(wave);
}
StartNextWave();
}
Now go back to Game1 and find the LoadContent method, and in it find where we initialize the WaveManager.We need to move this initialization code to underneath where we initialize the Player and then pass in the Player to the WaveManager, like so :
Texture2D bulletTexture = Content.Load<Texture2D>("bullet");
Texture2D[] towerTextures = new Texture2D[]
{
Content.Load<Texture2D>("arrow tower"),
Content.Load<Texture2D>("spike tower"),
Content.Load<Texture2D>("slow tower"),
};
player = new Player(level, towerTextures, bulletTexture);
Texture2D enemyTexture = Content.Load<Texture2D>("enemy");
waveManager = new WaveManager(player, level, 24, enemyTexture);
- The art is only placeholder, be creative and make your own!
- Currently there is only 1 type of enemy, how dull is that? Be creative and add new types, it is basically the same process as adding a new tower!
- Wouldn’t it be nice if enemies didn’t have to just follow a path? Let A-Star guide you...
- Add a timer that appears in between levels to let the player know how long he has before the next wave.
- Add in bonus rounds for extra gold.
- The current UI is so dull, wouldn’t it be nice if you could see some more information about each tower?
Well that’s it for me, thank you so much for the kind words, reporting bugs, and for just reading this blog!
Happy Coding!
"Wouldn’t it be nice if enemies didn’t have to just follow a path? Let A-Star guide you."
ReplyDeletewhat do you mean about A-Star guiding us?
A-Star is a pathfinding algorithm that would be perfect in this type of game.
ReplyDeleteSweet man!! Thanks for making this, I still found it impossible lol (I commented on your other tutorial), great :)
ReplyDelete"Now we need to pass a reference to the player via the constructor" .. that was the thing catching me out! :(
I followed this as closely as I could but still get the same error as before, unfortunately.
ReplyDeleteIn the Wave class, when trying to add money or lose a life, I get:
NullReferenceException was unhandled
Object reference not set to an instance of an object.
I have the reference to the player class etc, and there are no build errors.. I still have no idea why it gives me this because your tutorial fixed the build error I was getting! :( Any ideas?
Argh, very sorry to have spammed your page but woot! I don't know what happened but it works now, must have been early morning fail syndrome. Sorry, best tutorial series ever and just what I've been looking for ;)
ReplyDeleteIf you're looking for some more I'd suggest:
- How to add a circle/square around the towers placed, so they have a 'damage zone' people can see (which is their radius)
- When you click a button, it gives you a picture of the tower wherever you move your cursor, (looking like drag and drop).
Just some suggestions, sorry for spamming again :P
Just an hint to everyone, Switch (waveNumber % 10) returns an value between 1 and 10, depending on the wave between steps of 10, so 1 will be 1, 10 will be 0 and 11 will be 1 again, I used this to make 10 different enemies, so if you add case 1= easy enemy, case 2 = normal enemy, case 0 = boss, etc. It's really handy.
ReplyDelete~Arjan.
Could you explain how I would go about making my towers shoot the enemy which is closest to the end instead of closest to the tower itself, I've tried for a while but I'm getting stuck with the incompatibility of floats and vector2's..
ReplyDeleteAny advice would be great, thanks in advance :)
Hey,
ReplyDeleteThe first thing you would need to do is make a property in the enemy class that gets the enemy's waypoints.
Then in your towers GetClosestEnemy method instead of finding the smallest distance to an enemy, find the enemy that has the lowest number of waypoints left and that has the smallest DistanceToDestination.
I hope that helps, feel free to ask if you need more help!
FireFly, do you want to concider a tutorial about making it multiplayer? That would be really awesome. I followed your tutorials since the beginning and I love them. I made my own version of it which is starting to look like a great game. But the art of game design is being different I guess. Thanks for everything, you already have a neat basis here for a full game! Thanks man.
ReplyDelete~Arjan.
Hey Firefly, Thanks for this really sweet tutorial. It was just the start I needed with XNA.
ReplyDeleteA lot of TD games are also available on smartphones. Is it possible to do a tutorial part on the scaling part of the game? How nice would it be to see your own perfect sprite upclose. ;-)
Cheers, Tim
Thank you both for your kind words!
ReplyDeleteUnfortunately I don't have enough experience with networking to write a tutorial on making the game multi-player :(.
Tim, i'm not sure what you mean when you say the scaling part? And yes TDs are awesome on when played on portable devices (watch this space ;)! )
Hi FireFly,
ReplyDeleteSorry, I meant "2D zooming". My focus is a small device platform e.d. smartphone.
Cheers, Tim
Great tutorials! Theyre very helpful to me. In the first tutorials, you said you would make a map editor for at the end of all the tutorials? I think this would help our everyone loads because, well, Ive never seen a tutorial for a map editor before. I think it would be nice. Could you possibly consider making a map editor tutorial?
ReplyDeleteThanks,
Davis
"Anonymous said...
ReplyDeleteI followed this as closely as I could but still get the same error as before, unfortunately.
In the Wave class, when trying to add money or lose a life, I get:
NullReferenceException was unhandled
Object reference not set to an instance of an object.
I have the reference to the player class etc, and there are no build errors.. I still have no idea why it gives me this because your tutorial fixed the build error I was getting! :( Any ideas?"
Hi,
i got the same error, please can anyone tell me what to do because everything i've done is not working.
by the way,FireFly, your tutorials are simply the best, thanks a lot doing such a good work.
I figured it out, now it's working and no bugs at all !
ReplyDeleteCheers,
Adrian
Thanks for the kind words Adrian, I'm glad you got it working! Just out of interest was it something missing in my code, or had you missed something out?
ReplyDeleteHi FireFly, there was my couple mistakes but i'll fixed. I tried to change your code a little bit and missed something in the game class. Your code works perfectly...thanks again for your kind to share it with rest of as.
ReplyDeleteBest regards,
Adrian
FireFly, it would be great if you'll post a tutorial of how to upgrade towers and especially how to drag and drop a tower. These things are hard from my point of view.
ReplyDeleteYour work is great.
Thanks.
Hey Firefly, i want to have a healthbar or some sort of marker near the enemy of how much health it has. (maybe even X%). How would i go about doing this? I have tried multiple ways, but no result.
ReplyDeleteHey I am considering writing a tutorial on how to do this because it is pretty simple to do.
ReplyDeleteBut until I post that you should have a read of this : http://www.xnadevelopment.com/tutorials/notsohealthy/NotSoHealthy.shtml
I would put the health bar drawing code in the Wave.cs draw method inside of the foreach loop.
Let me know if this helps!
i have been following that tutorial, but i have not tried putting it in the foreach loop. ill try that
ReplyDeleteI'm a total TD addict, having created some in StarCraft and Warcraft III.
ReplyDeleteI've dedicated my entire working day to completing these tutorials (don't tell my chief), and as a .NET developer, I found it very easy to follow. You've really inspired me to create a few TD's of my own.
I'm hoping the A-Star stuff doesn't blow my head off, as it's essential to getting my idea(s) off the ground.
Thanks a lot for taking the time to write these tutorials.
"Anonymous said...
ReplyDeleteI followed this as closely as I could but still get the same error as before, unfortunately.
In the Wave class, when trying to add money or lose a life, I get:
NullReferenceException was unhandled
Object reference not set to an instance of an object.
I have the reference to the player class etc, and there are no build errors.. I still have no idea why it gives me this because your tutorial fixed the build error I was getting! :( Any ideas?"
I got the same error :(
It works now :D
ReplyDeleteExcellent tutorials!
ReplyDeleteHowever, I'm still having issues with this error:
"In the Wave class, when trying to add money or lose a life, I get:
NullReferenceException was unhandled
Object reference not set to an instance of an object."
To those of you who fixed this, what needs to be done?
Same problem as the anno above, can anyone please enligthen me? :]
ReplyDeleteAlso Thanks to you FireFly for posting this great Tutorial! has helped me out alot :]
For all the people who are getting the NullReferenceException: On which line of code are you getting this exception? Have you tried putting a break point on this line to see what is actually null?
ReplyDeleteAre you sure you are actually setting a reference to the player class and not just defining the field ie. have you got something like :
this.player = player; (The THIS is very important)
Let me know if this helps!
Hi there,
ReplyDeletegreat Tut, totaly loved it :)
I have made my own TD from it and it works like a charm! Only have one little Issue left:
Once the last wave is through, the game crashes. VS highlights the get { return CurrentWave.Peek();} in the CurrentWave Property. Stating: There is no more Element left in the Queue - NullReference
Is there anyway to fix this somehow? I tried adding some if clause to the get{ } but that only helped until like wave 9 and then it crahsed again with some other Null-Reference :(
My code looked like:
public Wave CurrentWave
{
get
{
if(waves.Count > 0){
return waves.Peek();
}else{
return null;
}
}
}
But as mentioned, it didn't work :(
Any ideas on your end maybe?
Cheers
Hiro
Hello, this is a rather old guide but I'm getting the same error everyone else was getting, I've checked my code against the tutorial many times and its identical, yet I'm getting the error:
ReplyDeleteNullReferenceException was unhandled
Object reference not set to an instance of an object.
Are you sure you are calling:
ReplyDeleteplayer = new Player(level, towerTextures, bulletTexture);
before:
waveManager = new WaveManager(player, level, 24, enemyTexture);
Hello thanks for the reply, I got it working now :)
ReplyDeleteI was wondering if you could help me.
I'm trying to make it so after every round, the game pauses, and the user has to press a button to start the next round.
The first thing I would do is add an event to the top of the WaveManager class:
ReplyDeletepublic event EventHandler OnWaveFinished;
Next I would go to the update method and in the conditional that checks if the current wave is finished I would replace:
waveFinished = true;
with:
if (OnWaveFinished != null)
{
OnWaveFinished(CurrentWave, EventArgs.Empty);
}
This will fire the OnFinished event. I would then move:
waves.Dequeue(); to the top of the StartNextWave method and make the method public.
Then just remove the other code from the update method that starts waves based on a timer if you don't want that.
In the game class when the OnWaveFinished event gets fired I would show the start next wave button, and when that is clicked simply call the waveManager.StartNextWave method.
Hope that helps!
So what exactly should I write in the game class? :S Sorry I'm kinda new with this.
ReplyDeleteOk nevermind I got it with the way I was trying to do at the start... I was really frustrated yesterday when I couldnt get it to work thinking I was doing it majorly wrong, when I just realised right now, when I copy pasted the previous Clicked EventHandler from the last button I made, I didnt actually change the name.. >_______<
ReplyDeleteAnyway thanks! :p
If you were to use my method then in the game class you could use the wave event the same way you would use a button event.
ReplyDeleteAnd to start a wave you would do something like:
Button button = new Button(...);
button.Click += new EventHandler(StartNextWave_Clicked);
void StartNextWave_Clicked(object sender, EventArgs e)
{
waveManager.StartNextWave
}
I'm glad you got it sorted!
Hey again, now to my next problem.
ReplyDeleteI'm trying to make it when i hover over my towers that have been placed, a circle is drawn to show their firing radius. I have everything set up and working as follows:
Basically its the same as the button hover thing, the texture changes when i hover over the tower, but the texture for the radius is 160x160 and it seems to cram itself into the 32*32 square.. not really sure whats making it do that. Any enlightenment? :)
Do you have MSN / Skype etc because I'm sure it would be easier to contact on that! :P I know I'm gonna have more problems because I'm trying to make my game really unique from yours.
Thanks in advanced!
I wish you continued these tutorials because they were helping me so much! Now I just need to know how to show the radius on the towers when mouseover and also when placing them, also was wanting to add upgrades to towers also, but I havent really put much thought into that. Praying for a new tutorial <3 But I understand if you can't :p
ReplyDeleteHow are you drawing the circle texture? At I guess you are doing:
ReplyDeletespriteBatch.Draw(circleTex, new Rectangle(posX, posY, 32, 32), Color.White);
You need to change the width of the rectangle from 32 to the texture size, or even better use the other spriteBatch overload:
spriteBatch.Draw(circleTex, new Vector2(posX, posY) - new Vector2(circleRadius), Color.White);
Hope that helps!
Hey there, thanks again! Its working good, only small problem when I subtract the circle radius vector it doesnt center the circle around the tower, it seems lopsided somehow... Not sure whats wrong with the maths
ReplyDeleteNvm I got it :)
ReplyDeleteThanks again for all your help!
Ok now I have a new problem >_> Never ending problems I know..
ReplyDeleteIts working great for my arrow tower, but for any of my other towers the hoverTexture doesnt seem to show up and I'm not sure why..
Hi, I've just noticed that my waves arent actually going higher than the 2nd wave, nothing happens after the 2nd wave finishes.. even though I have 20 waves in the game1.cs
ReplyDeleteNvm fixed the wave problem.
ReplyDeleteMeh been trying to make the hoverTextures show up on my slow and aoe towers but they just dont, I really dont get it... any idea? :S
ReplyDeleteI want to show the number of waves i've finished, how do i do that?
ReplyDelete@iSekz
ReplyDeletein the ToolBar.cs class, when drawing the font and string of text,
just add another value
string.Format("Gold: {0}, Lives: {1}, Wave Number: {2}",player.Money, player.Lives, waveManager.RoundNumber);
something like that