Article: Scripting on the Xbox 360, Windows Phone, and Beyond!
by UberGeekGames

Scripting. It’s a recurring theme on the XNA forums: “Can I use Lua?” “Can I script on the Xbox 360?” “Scripting FTW! No, scripting FTL!”. Do a quick search for “scripting” on the XNA forums and you’ll find many threads with the preceding themes. There’s a lot of information about scripting, and it usually ends with “no, you can’t do scripting on the Xbox, and it’s probably not a good idea anyway”.
In this tutorial, I’m going to show you what scripting is, a very useful type of scripting that I’ve been using more and more, and how you can make your own scripting system and use it effectively.
What is Scripting?
First, let’s back up a little and define what scripting really is. New programmers sometimes have very misinformed ideas as to what scripting is, thinking it’s a magic way of being able to do lots of cool things without having to learn programming. Scripting is not a replacement for being able to write C#. In fact, you’ll need a pretty good grasp of lists, inheritance, interfaces, value types and string parsing in order to make your own scripting system and make it useful. That’s because your scripting language is only as powerful as you make it.
Once your scripting system is finished, it’s entirely possible for artists and other non-programmers to use it, depending on how you make it. With good documentation, simple commands, and dedication on the part of the script-writer, it’s entirely possible for non-programmers to make useful scripts for your game. This was my main goal when I created my scripting system – I needed non-programmers to be able to make changes to the script, without needing the entire solution and having to recompile the source code each time they made a change.
That leads us to the next big plus of scripting: you can make changes to the game without needing its source code, and without needing to recompile the project each time you change it. Depending on the size of your project, it can also make tweaking things much, much faster if it takes several minutes to rebuild.
Scripting does have it’s drawbacks. One, it’s more complicated to maintain since you need to add another layer of abstraction between your game and the scripting language. Two, this is likely to make it less efficient than straight C# code, especially in very high-frequency areas. However, I’ve been using scripting in BulletAsylum and it runs at 60FPS on the Xbox while using my scripting system to handle the spawn waves, so the performance hit shouldn’t deter you that much. ![]()
So, now that we have a firm grasp of the pros and cons of scripting, let’s make our own scripting system!
The Game
Load up the sample program and run it. It’s a bare bones, no frills twin stick shooter. It randomly spawns powerups and enemies, which if it were a real game, wouldn’t make for very interesting gameplay. Our scripting system will allow the designer to craft each level for the game, and determine when and where powerups and enemies appear.
First off, we need to determine exactly what we need to expose in the script. For our game, we’ll be controlling the enemy spawn system. For larger games you will probably need more for things like powerups, NPCs, particles, and anything else you can think of.
A sample script will look like this:
wave 1:
spawn enemy ( 100, 200, White )
spawn enemy( 100, 400, Red )
End wave
Wave 2:
Loop(10)
{
Spawn enemy(random(0, 50), random(50, 650), Blue)
}
Loop(20)
{
Spawn enemy(random(1000, 1100), random(50,650), Red)
}
End wave
Keep in mind that this is just an example; in a real game you would probably need many more parameters and commands.
Creating the Scripting Engine
At its core, the scripting system is just taking the raw text file, figuring out what command is on each line, and adding them to a list of command objects that will be executed later. Those commands will have names like Wave and SpawnEnemy, and have parameters such as position and velocity. We can even add modifiers like Random so we can add some pseudorandomness to the game, or Loop which will execute the same statement more than once.
Let’s begin.
Let’s define what the commands are first:
//interface that all commands use
interface IScriptCommand
{
void Do(Wave wave);
}
//spawns a new enemy
struct ScriptCommand_SpawnEnemy : IScriptCommand
{
//holds the position, velocity, and color
private Vector2 pos, vel;
private Color color;
public ScriptCommand_SpawnEnemy(Vector2 position, Vector2 velocity, Color color)
{
this.pos = position;
this.vel = velocity;
this.color = color;
}
public new void Do(Wave wave)
{
//tells the Wave to spawn this enemy.
wave.SpawnEnemy(pos, vel, color);
}
}
Each script command is a struct that implements the IScriptCommand interface. They do little more than take the command’s parameters in their constructors, and executre the command in the Do method.
You’ve probably noticed that we’re missing the Wave class. This is the class that holds each Wave. A Wave consists of a list of IScriptCommands, and the methods which the commands can call when they are executed (the SpawnEnemy class in the case of ScriptCommand_SpawnEnemy):
class Wave
{
//list of commands in this wave
List<IScriptCommand> commands = new List<IScriptCommand>();
//adds a new command to the list
public void AddCommand(IScriptCommand command)
{
commands.Add(command);
}
//hold on to a reference of the game so that we can interact with it's elements
GameManager gameManager;
//index of current command we're at
int currentCommandIndex = 0;
public void Reset()
{
currentCommandIndex = 0;
}
//executes the next command. Not literally, mind you. That would be... messy.
public bool Run(GameManager theGameManager)
{
this.gameManager = theGameManager;
//next command
currentCommandIndex++;
//if we're at the end of the line exit
if (currentCommandIndex > commands.Count - 1)
return true;
else
{
//otherwise run this command
commands[currentCommandIndex].Do(this);
return false;
}
}
//spawns an enemy. all commands access the Wave class, so it acts as
//an intermediary to the rest of the game. This is useful if you add things
//like spawn timer modifiers.
public void SpawnEnemy(Vector2 pos, Vector2 vel, Color color)
{
gameManager.enemyManager.Spawn(pos, vel, color);
}
}
Most notable here is the reference to the Game Manager class. This is needed for most commands, as they usually interact with objects in the Game Manager (the EnemyManager in this case). So why not directly pass a reference of Game Manager to the script commands? Well, there’s no reason you couldn’t, but I chose to because A) it made more sense to me to add an abstraction layer so I’d never have to worry about some command doing something with the GameManager that I had forgotten about, and B) it keeps every part of the game that the script commands interact with in one place.
Lastly, we have the real meat of the program: the Script Manager. I’m not going to paste all of the code here because it’s 267 lines.
I’ll briefly go over the important parts here. I highly encourage you to go through the second (finished) project in the download and look through its code.
//parses a command. This is the real meat of the script parsing engine.
private void ParseCommand(Wave wave, string line, string[] lines, int currentLine, out int linesToSkip)
{
//make sure we're in lowercase
line = line.ToLower();
linesToSkip = 0;
//this is where you would place your commands and parse them.
if (line.Contains("spawnenemy"))
{
This is the most important function in the entire class. After the script is loaded from your hard drive (either from a physical location such as C:\Projects\script.txt or the game’s content folder), this method actually converts the script into commands that the game understands. In this example, let’s go over the spawnenemy command, as it’s a great template to start from and make your own commands.
//get the contents of the command
string parms = GetContents("(", ")", line);
parms = ParseMath(parms);
string[] parmz = parms.Split(',');
This semi-cryptic bit of code uses some helper function to convert the command’s parameters into actual variables. Take the following example command:
spawnEnemy (100, 200, White)
parms would now contain “100, 200, white”. ParseMath() does nothing to it since there aren’t any special variables in it. After it’s split into a string array by its commas, parmz will now contain
“100”
“200”
“white”
These can be quite easily parsed into actual integer values and a Color variable:
//xy coords are the first two
int x = Int32.Parse(parmz[0]);
int y = Int32.Parse(parmz[1]);
//color is the third
string colorStr = parmz[2];
//trim any useless whitespace
colorStr = colorStr.TrimStart(' ');
//sadly there's no easy way to get a color from text, so we'll parse it manually.
Color color = Color.White;
if (colorStr == "red")
color = Color.Red;
else if (colorStr == "blue")
color = Color.Blue;
else if (colorStr == "cornflowerblue")
color = Color.CornflowerBlue;
And we can now take those values and use them to create a ScriptCommand_SpawnEntity:
//add the command to the length wave.AddCommand(new ScriptCommand_SpawnEnemy(new Vector2(x,y), vel, color));
Repeating the above for each type of command that you have in your scripting language, you’ll end up with a dictionary of Waves which each contain a list of commands to be executed. In this case, they’re commands for spawning enemies! Let’s update the code in GameManager so that we can see it in action:
//----------------------
//| Level spawn stuff! |
//----------------------
int Level = 1;
int TimeSinceSpawn = 0;
//update our spawning system
void UpdateSpawns()
{
if (System.Environment.TickCount >= TimeSinceSpawn + 1000)
{
TimeSinceSpawn = System.Environment.TickCount;
//run the current wave
bool finished = scriptManager.waveDict[Level].Run(this);
//if the wave finished go to the next one
if (finished)
{
//reset it for later use
scriptManager.waveDict[Level].Reset();
Level++;
if (!scriptManager.waveDict.ContainsKey(Level))
{
Level = 1;
}
}
}
}
The End
Run the program and check out it’s output! (Note that you’ll have to use the second solution in the download, since some code was omitted from the script manager for brevity)

Okay, so it’s a bunch of blocks moving around. What makes this special? You created those blocks from a scripting language! Go ahead, open the script and change the positions, or the number of loops, or even the color, and see how it updates in game without ever touching a line of C# code.
Now that you have the base system in place, it will be easy to expand this and add more commands for things like spawning powerups, triggering cinematics, or anything else your game can do that you want to expose in the scripting language! The sky is the limit.
And best of all, this code will run on the Xbox 360 and WP7 (with some changes and upgrades to the latter to account for XNA 4.0, of course) because it doesn’t rely on reflection, interop, or any other such tomfoolery that scripting systems traditionally use.
Download code:
XboxScriptingSampleGame.ZIP
XboxScriptingSampleGame_Finished.ZIP
September 3rd, 2010 - 20:26
To convert a color to a string, consider
static Microsoft.Xna.Framework.Graphics.Color GetColorFromString(String Name)
{
System.Type CType = typeof(Microsoft.Xna.Framework.Graphics.Color);
var ColorMember = CType.GetProperty(Name,
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
if (ColorMember == null) throw new InvalidOperationException(“No color by that name.”);
return (Microsoft.Xna.Framework.Graphics.Color)ColorMember.GetValue(null, null);
}
With this, you will be able to use all the color constants defined in Graphics.Color within your script.
September 4th, 2010 - 01:30
damn, you beat me to it blecki
September 4th, 2010 - 11:45
While cool, that code reeks of garbage and slowness.
Thanks for the suggestion; it might be useful for some since it would only run at load times. Personally I’d rather spend a few more minutes coding to reduce load times by a few tenths of a second!
September 4th, 2010 - 11:52
Run it at content-build time, not load time.
September 5th, 2010 - 01:44
All you need to do is create a Dictionary and run the above code once at load time. From then on it’s just a quick dictionary look up to convert string to color.
September 5th, 2010 - 01:50
Actually, I’d wrap that up in some nice helper class that also let you define new named colors. Something like this: http://www.pasteall.org/15456/csharp. Then you can easily query for named colors without the perf hit of reflection each time.
September 8th, 2010 - 12:29
Good idea! I’d probably do that for my own system, but I was trying to keep it simple for the tutorial.