TurboSprite is a set of components that provide a complete 2D animation sprite engine to your .NET applications. A "sprite" is a movable object in a game or other application that supports animation. In TurboSprite, you can use several different types of sprites, and create your own derived types to exhibit exactly the appearance and behavior you need. TurboSprite is written completely in C# managed code. The primary components are:
SpriteSurface - The visual canvas that the sprite animation takes place on.
Sprite - An abstract base class that encapsulates a sprite. TurboSprite contains several concrete descendant sprite classes, like
SpriteEngine - Sprites the are added to a
SpriteEngine will appear on the
SpriteEngine notifies you of collisions between sprites. Descendant classes of
SpriteEngine allow you to define different movement capabilities of the sprites that they contain. The
DestinationSpriteMover descendant that is included in TurboSprite allows you to move sprites to a destination point at varying speeds.
TurboSprite began back in the mid 1990s as a Windows sprite engine written in Borland Delphi. At the time, generating responsive animation in Windows was very difficult, and TurboSprite relied an special assembly language coded functions to draw directly into the image buffer memory. Now that computers are much faster, the newest incarnation of TurboSprite leverages the drawing capability of GDI+ to perform its rendering. This enabled me to develop the package completely in C# managed code. The performance is very acceptable for simple 2D games and other applications! TurboSprite for .NET has kept the simple, object-oriented design pattern of the original library.
SpriteSurface is the visible animation surface where sprites move and other animated effects occur. After placing a
SpriteSurface on a form, set the
DesiredFPS property to establish the number of frames per second of animation that you wish to achieve. In your code, set the
Active property to
true to begin animation. At any time, you can examine the actual animation rate of the
SpriteSurface by examining the
You can produce animation through a number of different avenues, using
SpriteSurface. One way is to use
Sprites (see below). When you connect
SpriteEngines to a
SpriteSurface, the sprites contained in the
SpriteEngines will be rendered and processed on the
SpriteSurface also provides events and properties you can handle to tap into the animation cycle at various points. Some of the events use
PaintEventArgs, so you can use the
Graphics object that is contained in the event to draw on the surface. Keep in mind that the sequence of events below occurs during each animation cycle. You are basically drawing your complete frame during every cycle. It is the slight alteration of what you draw in each frame that can produce animation effects.
BeforeAnimationCycle event occurs before each frame of animation.
- If you set the
AutoBlank property to
true, the first thing that happens during each animation cycle is for the surface to be cleared using the
BeforeSpriteRender event occurs before any sprites are rendered to the surface, but after the AutoBlank processing. Use the
Graphics object to perform any custom rendering to the surface during each animation frame.
AfterSpriteRender event occurs after the sprites have been rendered, and allows you to draw to the surface using the
Graphics object passed.
SpriteSurface has a
Width and a
Height property like any other Windows Forms control, but it also has the concept of a "virtual" size, where the visible portion of the control is a viewport into the full virtual area. To enable this feature, set the
UseVirtualSize property to
true, and set the virtual size using the
VirtualSize property. When the virtual size mode is in effect, you use the
OffsetY properties to read and set the offsets of the upper left hand corner into the virtual space. When using virtual size, remember that a sprite's X and Y coordinates are expressed in the full virtual space, not the visible portion of the
There are a number of properties that expose a selection cursor in
true, the cursor will appear as a rectangle wherever you click on the surface. The cursor's appearance is controlled by the
CursorWidth properties, and its location by the
Additionally, a selection band will appear when you drag the mouse on the
true. The color of the selection band is controlled by the
SelectionBandColor property. When the user does draw a selection band, the
SpriteSurface triggers the
Wraparound property determines what happens if sprite objects move outside the virtual size of the
false, sprites are allowed to move outside of the actual dimensions, they are just not rendered. If
true, then a sprite moving beyond one edge of the surface will appear at the other edge, effectively wrapping around the surface.
Sprite class defines an object that can be moved around and rendered onto a
Sprite is an abstract class that defines a
Position property, a
Height, and some other properties that are common to all sprites. TurboSprite contains a number of concrete derived sprite classes:
BitmapSprite uses a
Bitmap to render itself.
AnimatedBitmapSprite descends from
BitmapSprite, and allows you to specify a set of
Bitmaps that define the frames of animation that are used to render the sprite.
PolygonSprite renders itself based on a set of points that you define, and supports rotation around its axis.
ParticleExplosionSprite generates a particle based explosion, allowing you to control the size, speed, and color range.
ShockwaveSprite generates an explosive effect composed of outwardly radiating circles.
StarFieldSprite reproduces the classic arcade game star-field hyperspace effect.
You are encouraged to use these as examples and create your own
Sprite class contains two important methods that warrant further discussion here:
Process method is virtual, and you can choose to override it if you wish in a concrete descendant class. TurboSprite calls a sprite's
Process method prior to each frame of animation, whether the sprite is within the visible portion of the virtual area or not. Here, you can perform any processing that you wish to apply to the sprite during each frame of animation. This can include things like particle dispersal, decrementing a life counter, etc.
Render method is abstract, so it must be implemented in derived classes. It contains the code that actually draws the sprite onto the
Render provides a
Graphics object that you should use to render the sprite.
When rendering a sprite, use the sprite's
Location, minus the current
OffsetY of the
SpriteSurface to determine where to draw it on the
Graphics object. The example below is the
Render method of
BitmapSprite, which uses a
Bitmap to render itself. Note that the code also subtracts half the size of the
Bitmap when rendering, ensuring that the
Bitmap is centered on the sprite's actual position.
protected internal override void Render(Graphics g)
g.DrawImage(Bitmap, X - WidthHalf - Surface.OffsetX,
Y - HeightHalf - Surface.OffsetY);
Y are properties of the
Sprite class, giving you access to its location. As you can see above, the
Sprite class provides access to its
SpriteSurface via the
Sprite-derived classes, it is important to tell TurboSprite how large the sprite is. TurboSprite uses this information, in combination with the sprite's
Position, to determine if it needs to be rendered during each animation frame. The sprite's
Shape property (a
RectangleF) should be assigned in a
Sprite-derived class to define its size. The
Shape property should be set irrespective of the sprite's location. For example, if a sprite is 20x20 pixels in size, its
Shape property should be set to a new
RectangleF (-10, -10, 10, 10); this centers the sprite's shape around its location. You should set the
Shape property so that it roughly corresponds to the image that you draw during the
Below, we see that the
BitmapSprite sets the
Shape property when the
Bitmap is assigned:
public Bitmap Bitmap
_bitmap = value;
if (_bitmap != null)
Shape = new RectangleF(-_bitmap.Width / 2, -_bitmap.Height / 2,
TurboSprite supports the clicking of sprites and notifying the client through a
SpriteClicked event. You don't always want a sprite's visible drawn region to determine the area of the sprite that defines when it is clicked. Because of this, the
Sprite class also has a
ClickShape property that you can set if you wish to make the clickable region different than the
Shape. By default,
ClickShape assumes the value of whatever the
Shape property was set to.
Sprite class also defines some properties that describe rotation, including
Spin is set to
SpinType.CounterClockwise, then TurboSprite will automatically adjust the sprite's
FacingAngle during each animation cycle. It is up to the derived
Sprite classes to utilize the
FacingAngle when they render the sprite. To see an example of one that does, examine the code for the
PolygonSprite maintains an internal list of points that define the polygon shape of the sprite. During the
Process method, the points are rotated based on the sprite's
protected internal override void Process()
if (FacingAngle != _lastAngle)
float sin = Sprite.Sin(FacingAngle);
float cos = Sprite.Cos(FacingAngle);
_lastAngle = FacingAngle;
for (int p = 0; p < _points.Length; p++)
_points[p].X = _unrotated[p].X * cos - _unrotated[p].Y * sin;
_points[p].Y = _unrotated[p].Y * cos + _unrotated[p].X * sin;
Points = _points;
As a side note, the
Sprite class creates static lookup tables of sin and cos values that reduce calculation overhead during the animation cycle, and
PolygonSprite makes use of these lookup tables in the code above.
To have your sprites appear on the
SpriteSurface, they must be added to a
SpriteEngine is a non-visual component that manages sprite movement and collision detection.
SpriteEngine has a
Surface property which should be set to the
SpriteSurface that its sprites will be drawn on. You can use several
SpriteEngines connected to the same
SpriteSurface to provide different behaviors to different groups of sprites on the same surface.
Priority property determines the order in which sprites are rendered when multiple
SpriteEngines are connected to a
Collision detection among sprites is handled by setting the
DetectCollisionFlag properties. If
true, the sprites within the
SpriteEngine will detect collisions among themselves. When multiple
SpriteEngines are used, the ones that have the same values for
DetectCollisionFlag will detect collisions amongst themselves. When a sprite collision is detected, the
SpriteSurface triggers a
SpriteCollision event, passing you the two
Sprite objects that collided.
Sprites are hardly worth anything unless there is some way of putting them into motion! In TurboSprite, this is handled by components that descend from
SpriteEngine provides a design pattern for defining a sprite's movement. Derived components can utilize this pattern to create different ways to move sprites. TurboSprite contains one such descendant, the
SpriteEngineDestination component, which moves sprites at a specific speed towards a specific destination.
The design here utilizes a special tag property in the
Sprite class called
SpriteEngine-derived component can assign whatever object it needs to this property to track and/or control the movement of the sprite, as it sees fit. The place to set this value is in the
InitializeSprite method of
SpriteEngine, which should be overridden in derived classes. The
SpriteEngineDestination overrides this method to create an instance of a
DestinationMover object, and assigns it to the
protected override void InitializeSprite(SCG.TurboSprite.Sprite sprite)
sprite.MovementData = new DestinationMover(sprite);
SpriteEngineDestination provides a public method called
GetMover which returns the instance of the
DestinationMover to the client for a particular
Sprite object. The
DestinationMover class itself contains properties that describe a sprite's speed and destination and whether or not the sprite should stop moving once it reaches its destination. The client code can thus cause a sprite to move by setting the
TurboSprite executes the movement logic when it calls the
MoveSprite method. This happens during each animation cycle.
SpriteEngineDestination overrides the
MoveSprite method and employs its custom movement logic. See the code for the
SpriteEngineDestination and the comments contained, for a more thorough understanding of the sprite movement design pattern. Although it may seem cumbersome, it provides a level of flexibility for different movement behaviors that can be added in the future.
The TurboSprite Demo App
Included in the source code is a full demo application that illustrates creating sprites, adding them to
SpriteEngines, and moving them. It also touches on some of the other goodies that come with TurboSprite, like the
GamePieceBitmapFactory component that lets you easily access individual sprite graphics that can be contained in a single larger
Bitmap, and even colorize them to any specific color.
Here is the code that executes when the "Bitmap Sprite" button is clicked. This creates a
BitmapSprite instance, and puts it into action on the
private void btnAddSprite_Click(object sender, EventArgs e)
BitmapSprite s = new BitmapSprite((Bitmap)picGlyph.Image);
s.Position = new Point(surface.Width / 2, surface.Height / 2);
DestinationMover dm = engineDest.GetMover(s);
dm.Speed = rnd.Next(10) + 1;
dm.Destination = new Point(rnd.Next(surface.Width), rnd.Next(surface.Height));
dm.StopAtDestination = false;
TurboSprite in Action
TurboSprite is the animation engine used in my freeware real-time strategy game, Solar Vengeance. Solar Vengeance uses many of the TurboSprite features described here, and some that are included in the package but not touched on in this article:
- Uses a number of custom
Sprite-derived classes to render StarShips and StarSystems.
- Uses the
AnimatedBitmapSprite class to render Wormholes.
- Uses the
ShockwaveSprites to render explosions.
- Uses the
SquareGridSpriteSurface as the main surface. This is a component that derives from the basic
SpriteSurface, but provides additional functionality that allows you to work with square grids.
- Uses the
SpriteEngineDestination to move sprites on the playing field.
Visit the Silicon Commander Games website to learn more about TurboSprite, Solar Vengeance, and our open-source .NET multiplayer gaming and chat component package, PrismServer.