2010-05-02

Design decisions

I said I'd talk about why I'd decided to use C# and OpenTK, so I'll do that here. Along with why I'm developing reusable code, which is something of a two-edged sword if you're not careful.

Why C#?
To be blunt, because I can get from clicking "start project" to a working OpenGL window in under 2 minutes. With OpenTK installed on the system there's minimal messing around with dependencies etc, etc.
On top of that, .NET has a very, very rich network of libraries. VB also has access, but it's not as flexible a language. There are other options for adding useful libraries to C/C++ but you have to take time to set things up, which can take a long time and there's also issues with linking things so they'll "just work" on other people's machines. C# with always "just work" on a Windows box and with mono installed will most likely "just work" on both Linux and OS X as well without requiring me to release 3 copies of the game.

Why OpenTK?
Once C# was decided on, there were several things I could use for games programming. The most obvious is XNA, which is Microsoft's release and is easily portable to the X-Box 360. However, it's Windows only and is based on DirectX, which I've never particularly liked.
SDL.NET was another possiblity, but this works in 2D and seems to be abandoned in recent years. It was more active around .NET 1.1 than any other time and much of the coding harks back to that era, C# and .NET have moved on since then.
Tao is another possibility and would be a solid choice, but again it looks abandoned.
So that brings me to OpenTK, which has almost direct calls to OpenGL, contains a very quick and easy class called "GameWindow" (which allows that 2 minute setup I spoke about), contains maths classes that are almost (but not quite) directly portable with XNA, has support for sound playback and has extensive input support for keyboards, mice and joysticks. It also supports these features across both Windows and Linux, with most supported on OS X (I think sound playback and joysticks are a bit iffy, but I have no Mac to test them on).

Also note, I'm discounting anything that isn't free here.

Reusable code
Working out how much of a game to make reusable is more complex than it first appears.
For example: You could build an entire game engine that could be used for multiple games, but it should be pointed out that this is a large project in and of itself and if you just want to write a game then it's advisable to write a game-specific engine which will be much less flexible, but you're more likely to complete.
For my Game-A-Month project I've hit somewhere in the middle ground. Certain parts of my games will be reusable, but the game itself will be built largely from scratch each time.
The main part that is reusable is are the user interface components. Specifically this is a lump of code that contains the decision making for what is happening in the game at the moment, making sure things that are supposed to be rendered are so and those that aren't, aren't, making sure when a key is pushed the game takes the right action, etc, etc.
In Whirligig it deals with where and what the mouse has clicked on, who's turn it is and what to display on the screen at any moment. It will also deal with the main menu and shop when those are implemented.
In Hoshi it just deals with the basic rendering right now and not a lot else, although it also knows when the player dies and deals with ending the game; this bit of user interface is particularly clever as internally user interfaces lie on a stack, the first on the stack is the 'main menu' then you stack whatever else the user visits as you need it. When the user finishes with the user interface it just pops the stack and the user is automatically returned to the previous interface. If the stack is empty the game ends.
This allows me to very quickly knock together a group of components I want rendering into a user interface, chuck it on the stack and have a game prototype. This is the stage both Hoshi and Whirligig are currently at. When I want to add a main menu, I just create the menu as a separate interface and when the user selects "play game" just push my 'prototype' interface onto the stack. When the game ends, the stack is popped and control drops back through to the main menu.

Other components are designed to work with this interface and mostly consist of fairly mundane things like windows, labels, buttons and progress bars (all showcased in Whirligig) which inherit an interface called IUIElement. This interface allows me to create and add a new element to a user interface very quickly. For example, the radars took ~30 minutes to knock up in the end and the energy bar not a lot longer, then I just use an AddControl() call on the interface and they're rendered the same as anything else.

This is all very useful, but I take some performance hits for it. Interfaces suffer some nasty performance problems and once I start developing more complex objects I will certainly start using less of them (right now every render object uses one for it's main render cycle, this is VERY BAD as it generates unnecessary allocation and therefore garbage collection calls for every object in every render cycle -- 60+ times a second -- which severely impacts performance and may be the reason I'm having issues recording a video). Hopefully project #3 (which I'm looking at a plaformer idea I have for) will have less of these.

There are other small elements that I'm making reusable, small things like the OpenGL texture upload code, which I'm just doing quick'n'dirty right now, text drawing is done through the .NET image subsystem to a texture then uploaded with a transparent mask, this isn't perfect (rapidly changing text would be bad for this method) but works for what I have right now.
When I write a simple audio subsystem (which I'll be doing in the next couple of weeks for Hoshi), that will be reusable as well.

No comments:

Post a Comment