1. Game Development
  2. Programming

Make a Neon Vector Shooter in XNA: Basic Gameplay

This post is part of a series called Cross-Platform Vector Shooter: XNA.
Make a Neon Vector Shooter in XNA: More Gameplay

In this series of tutorials, I'll show you how to make a neon twin stick shooter like Geometry Wars, which we will call Shape Blaster, in XNA. The goal of these tutorials is not to leave you with an exact replica of Geometry Wars, but rather to go over the necessary elements that will allow you to create your own high-quality variant.

I encourage you to expand upon and experiment with the code given in these tutorials. We'll cover these topics across the series:

  1. Set up the basic gameplay, creating the player's ship and handling input, sound and music.
  2. Finish implementing the gameplay mechanics by adding enemies, handling collision detection, and tracking the player's score and lives.
  3. Add a bloom filter, which is the effect that will give the graphics a neon glow.
  4. Add crazy, over-the-top particle effects.
  5. Add the warping background grid.

Here's what we'll have by the end of the series:

Warning: Loud!

And here's what we'll have by the end of this first part:

Warning: Loud!

The music and sound effects you can hear in these videos were created by RetroModular, and you can read about how he did so over at Audiotuts+.

The sprites are by Jacob Zinman-Jeanes, our resident Tuts+ designer. All the artwork can be found in the source file download zip.

The font is Nova Square, by Wojciech Kalinowski.

Let's get started.


In this tutorial we will create a twin-stick shooter; the player will control the ship with the keyboard, the keyboard and mouse, or the two thumbsticks of a gamepad. 

We use a number of classes to accomplish this:

  • Entity: The base class for enemies, bullets, and the player's ship. Entities can move and be drawn.
  • Bullet and PlayerShip.
  • EntityManager: Keeps track of all entities in the game and performs collision detection.
  • Input: Helps manage input from keyboard, mouse, and gamepad.
  • Art: Loads and holds references to the textures needed for the game.
  • Sound: Loads and holds references to the sounds and music.
  • MathUtil and Extensions: Contains some helpful static methods and extension methods.
  • GameRoot: Controls the main loop of the game. This is the Game1 class XNA automatically generates, renamed.

The code in this tutorial aims to be simple and easy to understand. It will not have every feature or a complicated architecture designed to support every possible need. Rather, it will do only what it needs to do. Keeping it simple will make it easier for you to understand the concepts, and then modify and expand them into your own unique game.

Entities and the Player's Ship

Create a new XNA project. Rename the Game1 class to something more suitable. I called it GameRoot.

Now let's start by creating a base class for our game entities.

All our entities (enemies, bullets and the player's ship) have some basic properties such as an image and a position. IsExpired will be used to indicate that the entity has been destroyed and should be removed from any lists holding a reference to it.

Next we create an EntityManager to track our entities and to update and draw them.

Remember, if you modify a list while iterating over it, you will get an exception. The above code takes care of this by queuing up any entities added during updating in a separate list, and adding them after it finishes updating the existing entities.

Making Them Visible

We will need to load some textures if we want to draw anything. We'll make a static class to hold references to all our textures.

Load the art by calling Art.Load(Content) in GameRoot.LoadContent(). Also, a number of classes will need to know the screen dimensions, so add the following properties to GameRoot:

And in the GameRoot constructor, add:

Now we'll start writing the PlayerShip class.

We made PlayerShip a singleton, set its image, and placed it in the center of the screen.

Finally, let's add the player ship to the EntityManager and update and draw it. Add the following code in GameRoot:

We draw the sprites with additive blending, which is part of what will give them their neon look. If you run the game at this point you should see your ship in the center of the screen. However, it doesn't yet respond to input. Let's fix that.


For movement, the player can use WASD on the keyboard, or the left thumbstick on a gamepad. For aiming, they can use the arrow keys, the right thumbstick, or the mouse. We won't require the player to hold the mouse button to shoot because it's uncomfortable to continuously hold the button. This leaves us with a little problem: how do we know whether the player is aiming with the mouse, keyboard, or gamepad?

We'll use the following system: we'll add keyboard and gamepad input together. If the player moves the mouse, we switch to mouse aiming. If the player presses the arrow keys or uses the right thumbstick, we turn off mouse aiming.

One thing to note: pushing a thumbstick forward will return a positive y value. In screen coordinates, y values increase going downwards. We want to invert the y axis on the controller so that pushing the thumbstick up will aim or move us towards the top of the screen.

We'll make a static class to keep track of the various input devices and take care of switching between the different types of aiming.

Call Input.Update() at the beginning of GameRoot.Update() for the input class to work.

Tip: You may notice I included a method for bombs. We won't implement bombs now but that method is there for future use.

You may also notice in GetMovementDirection() I wrote direction.LengthSquared() > 1. Using LengthSquared() is a small performance optimization; computing the square of the length is a bit faster than computing the length itself because it avoids the relatively slow square root operation. You'll see code using the squares of lengths or distances throughout the program. In this particular case, the performance difference is negligible, but this optimization can make a difference when used in tight loops.


We are now ready to make the ship move. Add this code to the PlayerShip.Update() method:

This will make the ship move at a speed up to eight pixels per frame, clamp its position so it can't go off-screen, and rotate the ship to face the direction it's moving.

ToAngle() is a simple extension method defined in our Extensions class like so:


If you run the game now, you should be able to fly the ship around. Now let's make it shoot.

First, we need a class for bullets.

We want a brief cooldown period between bullets, so add the following fields to the PlayerShip class.

Also, add the following code to PlayerShip.Update().

This code creates two bullets that travel parallel to each other. It adds a small amount of randomness to the direction. This makes the shots spread out a little bit like a machine gun. We add two random numbers together because this makes their sum more likely to be centered (around zero) and less likely to send bullets far off. We use a quaternion to rotate the initial position of the bullets in the direction they're travelling.

We also used two new helper methods:

  • Random.NextFloat() returns a float between a minimum and maximum value.
  • MathUtil.FromPolar() creates a Vector2 from an angle and magnitude.

Custom Cursor

There's one more thing we should do now that we have the Input class. Let's draw a custom mouse cursor to make it easier to see where the ship is aiming. In GameRoot.Draw, simply draw Art.Pointer at the mouse's position.


If you test the game now, you'll be able to move the ship around with the WASD keys or or left thumbstick, and aim the continuous stream of bullets with the arrow keys, mouse, or right thumbstick.

In the next part, we will complete the gameplay by adding enemies and a score.

Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.