How to Create Video Games in VB.Net (Windows Forms)
I realize that this is a very popular subject, especially amongst budding developers. The drive to create games may be the reason you started working with Visual Basic in the first place. After stepping through a few samples and getting the hang of working
with user controls on a form, it may be very tempting to start to throw some PictureBoxes and a Timer on a Form and start to implement some game logic. Seems easy enough, right?
To some extent, this is a true statement. You could start to do this and it would be easy enough… at first. But when you begin to try to calculate collision and animate or rotate your “sprites”, you may start to run into some difficulty. And attempts to
circumvent the problems often lead to even worse issues. This can cause an endless spiral of misery which could leave you thinking VB just isn’t meant to make games! ;)
The initial problem that most people face is the desire to use a PictureBox (or any other control) as the logical “Sprite” container for the elements in the game. It makes sense since the control appears to provide a lot of the required functionality already
and it’s easy to extend it with more properties as needed.
The issue though is that Windows Forms Controls are designed to be drawn statically – that is, they aren’t meant to move around in real-time. You can of course move them at run-time, but this is normally an on-demand operation (something which occurs because
the user just took an action like clicking a button or menu item). Attempting to move controls in real-time puts a heavy strain on your application and can cause poor performance quickly.
There’s also the issue that a control is painted according to its own logic, so you can’t just take any old control and “rotate” it without modifying the logic which draws the control (at some level).
The other thing that Windows Forms leads you right into is using Events. So it’s natural to think to implement user input by handling key and mouse events on the PictureBox or the containing Form. But even though Windows Forms are designed to rely heavily
on the Event chain, they are expecting the application to be idle most of the time, doing its work in fits and bursts. This kind of application works well even with many events and handlers.
But a game is a single long-running loop. Your Windows Forms application is technically a pre-specified Form instance started in a long-running message loop, but then you interact with the loop through the Event chain.
For the best performance, a .Net GameEngine should actually do away with the main Form and use the program’s main loop to execute the game loop functionality. But it can be acceptable to maintain the Form and a Control or Component or two and implement a
GameEngine in componentized form.
However, this is where the use of controls stops. While there may be a component to house the “GameEngine” related functionality, and a “RenderCanvas” CustomControl to render the game engine display, all of the actual game elements would be class instances
handled by the GameEngine component which are not controls of any kind.
Your “Sprite” class (we can debate terminology as technically a sprite is just an image resource, but for this discussion “sprite” is a game object of some sort with image and movement and collision and all) is its own custom “game object” class that you
define to hold values such as location, speed, bounds, image and/or animation. The GameEngine is responsible for updating and drawing each game object once each game-loop-iteration and the RenderCanvas is responsible for rendering the last drawn frame.
Here is an example from a thread on the MSDN forums. This very simple example uses a Timer component as the “game engine” and the Form serves as the “render canvas”.
'One timer controls the entire game loop
'A list of the game tile objects used by the game
'An instance of GameTime to track running game time
'Two bitmaps and a boolean used to buffer drawing and rendering
'setup the form
.FormBorderStyle = Windows.Forms.FormBorderStyle.Fixed3D
'load some image assets to use for frames of animation
'create a grid of tiles
Point(12 + (x * tile.Bounds.Width), 12 + (y * tile.Bounds.Height))
'set the game time to 30 fps (1000ms / 30frames)
Timer1.Interval = 33
'start the game loop
'Use a stopwatch to track the execution time
'Record they time since the last loop iteration
'Reset the stopwatch to 0 and start tracking again
'Run a loop to check input for each item.
MouseButtons = Windows.Forms.MouseButtons.Left
'Run a loop to draw each item after determining which
'buffer to draw on this frame
gfx = Graphics.FromImage(_Buffer1)
gfx = Graphics.FromImage(_Buffer2)
'Cleanup and swap buffers
'Show the drawn scene
'Draw the approprite render buffer
'this is the images per second of the animation
'this is the total time to animate after recieving a click
'set the remaining animation time to 3 seconds when clicked
_AnimationTime = 3.0
'draw the current frame at its current location
'if there is remaining animation time, then animate
_AnimationTime > 0
_FrameIndex += gameTime.LastFrame * FrameRate
CurrentFrameIndex = FrameImages.Count
_FrameIndex = 0.0
_AnimationTime -= gameTime.LastFrame
'GameTime can be a simple structure or class which just tracks executed
'game time based on what the game loop tells it
ElapsedTime += TimeSpan.FromMilliseconds(milliseconds)
LastFrame = milliseconds / 1000
The GameTile has very simple logic which just executes a 3 second “animation” (sequence of images) played at the frames-per-second specified by FrameRate whenever the tile is clicked.
The game engine loop itself is implemented in the Timer1_Tick event handler. As previously noted, this is not ideal as the event chain is less efficient for our purposes than running a background thread would be, but the timer keeps the example simple. Regardless
of where it is run, the logic executed by this Timer1_Tick event handler lays out the general structure of the logic which needs to occur once each game loop iteration.
First, we update the time based on how long the last frame took to execute. You might do this at the end of each iteration, rather than at the beginning, but this implementation does it first because it makes the code simple to follow.
Next we update input for each game object (GameTile). Since the example is running directly off of the Form’s thread we can just cheat on input and read it in real time from the Form. A more robust game loop would maintain an Input object which was updated
once per frame before beginning on game objects. So the code checks each object to see if the mouse is being held down on it, and calls the OnInput method for that object if so.
Game objects should have their input updated first, then their logic processed, and finally their positions drawn. It is important to perform separate loops for each operation so that all game objects work together in a predictable manner. This example does
not use an OnUpdate method, but typically, OnInput, OnUpdate, and OnDraw are the minimum logic processing methods for a game object.
Now that all of the GameTile objects are updated, they can have their current state drawn. The example does implement buffered drawing even though this simple implementation doesn’t really require it. But it is not very complex and it makes it much more
clear how to transition drawing into multiple threads.
By implementing a buffered drawing (do not confuse with DoubleBuffered property of Form – that just makes GDI behave for real-time drawing) we ensure that the image being processing by the Form thread is never the same as the image being processed by the
background game engine loop. The Form renders one buffer image and the game loop draws to the other, and then flips buffers as the last operation on each frame. After the buffer has been flipped, a call can be sent off to invalidate the Form (or render control)
and the game loop can continue processing and drawing the next frame (on the alternate buffer).
Once the code has selected the correct buffer for drawing this frame, it proceeds to create the graphics object which will be passed to every game object allowing it to draw itself to the buffer. When this process is complete, the graphics can be freed,
the buffer can be flipped, and the render control can be informed that it needs to update.
Again, and I can’t stress enough, this is only a most basic implementation – a robust game engine has a lot more work to do. But this example should provide a simple overview of the primary concepts involved with creating a game engine.
The next most important thing to be aware of when it comes to creating games in VB.Net is that Microsoft has an official platform just for Games and Interactive Software, called
XNA Framework. As of the latest refresh you can now use VB with XNA Game Studio. Although XNA can seem quite daunting at first, if you understand the basic concepts lain out above, then
you are already well on your way to using it. XNA follows a similar pattern to what I’ve described here, and there are lots of examples and tutorials to get you started. There is just a lot more to it since XNA supports everything - all 2D, 3D, audio, game-pad
input, multiplayer networking, Xbox Live access, etc.
Games created in XNA can also easily be written to port from Windows to Xbox to WindowsPhone7. And you can easily become a publisher and actually put your game on Xbox Live or Windows Marketplace and collect royalties for its purchases.
Now, for a fairly simple, very “classic” style 2D video game, XNA could be considered overkill. And what you can accomplish with GDI+ and some creative sound and input hooks might provide everything that your game design requires. But just keep in mind that
broad support for game development is available under the XNA platform and it is incredibly powerful once you get the hang of using it (which really isn’t as bad as it first may seem if you just stick with it!).
I always feel obligated to mention this non-Microsoft-based solution because it is just so dang powerful and cool and wonderful and free (to play with anyway!).
Unity3D is a complete 3D development environment; like Visual Studio only the “form designer” is a 3D world space and the toolbox is full of game objects! The AI can be developed through script plugins in multiple
languages including C# and Java. So while it’s not exactly a VB solution, I still bring it up because the C# you would need to know is pretty easy to convert from VB and the Unity engine itself is truly remarkable.
In many ways what Unity does is very much like what XNA does. The main difference is that Unity goes so far as to define what a game engine is and then allows you to easily extend it, whereas XNA only provides all of the interfaces necessary for you to create
your own game engine of some kind. This is what allows Unity to provide a rich editor full of drag-and-drop and property-grid-setting features.
Finally, if you still have your heart set on making a quick little game directly in VB.Net (and why shouldn’t you?! They do make such fun projects!), then you may wish to check out the
GdiGaming API over on CodePlex.
This is a project I’m working on as I have time, which is meant to give a robust example of creating game engine in VB.Net using GDI as well as provide a compiled runtime which can be used as-is to quickly make little games based around the engine.
While there may still be a few bugs to work out, the API works generally as intended and is quite powerful for what it does and how it is designed. The project is a pretty good start on a full-scale game engine based around the kind of example shown above.
It is open-source (as CodePlex implies) and I’ve tried to provide fairly rich documentation and sample code. There’s still plenty to do (always a work in progress I guess!) but I believe there is enough there already for it to be of additional help if you
are interested in reading more.
I hope that somewhere in all of this there is some useful information for those of you starting out to write games in .Net. The horizons are currently broad, and the roads become more and more well-traveled every day. The amount of information available
is tremendous and I would encourage you to play with all of the technologies mentioned in this article and read all of their help files. Even if you don’t download anything yet, just go to the XNA and Untiy websites, navigate to their intro tutorials and read
them. Take note of the terminology and get a general feel for what the code appears to do, even if you can’t read all of it.
The next great game is just waiting to be written, and with effort and determination in no short supply you could be the one to write it! =)