Windows 7 ScriptTD: Tower Defense Made Easy

News

Extraordinary Robot
Robot
ScriptTD is an open source project that allows anyone to easily create a new Tower Defense game for the Windows Phone 7 platform, without any prior programming knowledge. The project lets you create new art & audio and edit some XML files to bring it all together into a polished game without having to write all of the code required to make the game work.
If you are looking to just create a game without coding, this article isn’t for you, head to http://scripttd.codeplex.com and follow the instructions there to get started.

[h=3]Extending the Code[/h]You can easily get away with editing the XML and adding new assets to make a whole new Tower Defense game with ScriptTD as it is. If you know a bit of C#, however, you can take it further and extend the game to make a unique creation. The entire source code for the project is available for free on Codeplex (see links above), so feel free to download that and change any part of it that you want.
There are three key areas that are easy to change in ScriptTD:

  • Weapons
  • The GUI
  • The Game Screens (Menus)
In this article we are going to focus on the main one you might want to edit—the weapons.
[h=3]Straight from the Labs[/h]The game already has a number of different weapon types, ranging from projectiles to earthquake generators; the laser included with the project, however, only fires along one of the four cardinal directions (N, S, E, W).
We will extend the code to add in a new type of laser, one that follows a target as it shoots. Remember that the code simply defines the behavior of the weapon, so you could change the art into flame images and create a flamethrower, without changing any of the code you are about to create.
[h=3]Getting Started[/h]This first thing you need to do before you can start creating your custom weapon is grab the source code for ScriptTD from Codeplex.
Every weapon in the game implements the IWeapon interface, which is provided by the engine. This allows the game to interface in a common way with each weapon type. Once you implement that, simply register the weapon type when the game starts up, and then refer to it in the XML data files when you need to. For the purposes of this article we will work with the sample game, though everything you learn here can easily be applied to your own version of the game.
First begin by creating a new class in the Coding4Fun.ScriptTD.Sample project and name it TrackingWeapon. Once you are done you should have an empty class that looks like this:


using System.Collections.Generic; using Coding4Fun.ScriptTD.Engine.Data; using Coding4Fun.ScriptTD.Engine.Data.Abstracts; using Coding4Fun.ScriptTD.Engine.Logic; using Coding4Fun.ScriptTD.Engine.Logic.Instances; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Coding4Fun.ScriptTD.Sample { public class TrackingWeapon : IWeapon { public Texture2D Texture { get; set; } public TowerData TowerData { get; set; } public bool CanFire() { throw new System.NotImplementedException(); } public bool TargetAndFire(ref List enemies, ref Vector2 towerPos, float gridCellSize) { throw new System.NotImplementedException(); } public void Update(float elapsedSeconds, ref GameSession session) { } public void Draw(GraphicsDevice device, SpriteBatch sb) { } } } When working with weapons in this project, you need to remember that weapons act purely as logic operating on the provided data. Accordingly, the game will provide the texture and specifications for the tower, and you need to make use of that to make the weapon behave as it should. Inside the base class above, we have two properties that are set by the game: Texture and TowerData. These will be set automatically upon creation, so you can generally ignore those unless you want to get info from the texture whenever it changes.
Next we have the CanFire method; this is usually used to check if the tower has finished reloading. Depending on your tower, however, you could do other checks here. The key thing is that this is just telling the game if the tower is ready to fire, rather than if it has any targets.
Finding targets is done in the next method, TargetAndFire. This is where you have access to the list of enemies that you can test against for range/suitability, and based on that choose a target and fire.
After that we have the usual Update and Draw methods, which let you manage shots in flight as well as keeping track of reloading.
For this weapon, we won’t worry about reloading. Instead the weapon will constantly fire at its closest target.
[h=3]1, 2, 3, Fire![/h]First we need to tell the game it is ok to fire at any time, so simply make CanFire() return true:


public bool CanFire() { return true; } Once that is done, we can begin with the code of the weapon, the TargetAndFire() method. And so we will we doing the following:

  • Check which enemy is the closest
  • Make sure we are allowed to shoot at the enemy
  • Make that enemy the target
First we need a variable to keep track of the closest enemy, and their distance, so we need an EnemyInstance variable and a float. I have named them closest and distSq, respectively, and initialised distSq to float.MaxValue (you’ll see why shortly):


EnemyInstance closest = null; float distSq = float.MaxValue; Once we do that, we need to prepare our Min and Max ranges so that we can ensure we only target enemies within that area. To do so, we need to add the following code:


float maxRange = TowerData.MaxRange * gridCellSize; maxRange *= maxRange; float minRange = TowerData.MinRange * gridCellSize; minRange *= minRange; The MaxRange is stored as the number of cells, so we need to expand this into the actual distance by multiplying with the provided cell size. Then we square it because we will be doing all of our distance tests using the squared length values. We do this to save on performance, and since a square root operation (as required by the Length formula) can be costly, we instead use the squared distance, and as long as everything uses squared distance, it will all be correct.
Next we need to loop through every enemy and check the following:

  • Can we target the enemy?
    • Is it a flyer or land enemy, can we target either?
  • Is it the closest?
  • Is it within the Min/Max range
If all of the above is true, we set the enemy to be our closest, and continue iterating through the list of enemies:


for (int i = 0; i < enemies.Count; ++i) { if ((TowerData.CanShootFlyers && enemies.Data.CanFly) || (TowerData.CanShootLand && !enemies.Data.CanFly)) { float d = (enemies.Position - towerPos).LengthSquared(); if (d
 
Back
Top