I know, this is quite long for a "short" summary, but I wanted to expose my project as clearly as possible. I'm really curious to know if there are people here who would think this is an interesting idea.
Introduction
AGE is a DLL library entirely written in C# whose purpose is to allow the user to create any kind of games or multimedia applications. It uses IrrlichtNETCP for video, Bass.NET (not IrrKlang, which is too limited in its current version) for audio and ODE.NET for physics.
Using the engine is easy : just create an instance of the AGEEngine class (consider it like some kind of IrrlichtDevice, the mother of all other things). Then, this class' main purpose is to create entities through the various AddEntity() methods.
1- The concept of entity
(Does that sounds philosophical enough for you?)
So what is an entity, exactly? In fact, every element of the AGE world is a child of the abstract class AGEEntity. The idea is to make this class the ONE AND ONLY thing you'll ever need to add a new object to your game's world. Do you want your entity to emit a sound? Alright, the AGE engine will handle stereo and volume according to the entity's relative distance and position to the camera. Maybe you'd like this entity to emit a continuous looping engine sound? No problem, AGE can handle it: when the entity will move towards you, volume and stereo will be dynamically adjusted. And yes, the Doppler effect is handled automatically. According to the same principle, you won't have to bother to "link" the object used by the physics engine (ODE) and the the object used by the graphics engine (Irrlicht). Of course, an entity has a 3D model (or anything else, for that matters: it can be a skydome, a particle fountain, a billboard, etc...), but it also has a mass, a speed, etc.. In fact, it is a complete "object", like in the real world. When I fall from my chair, there's no godly programmer in heaven bothering to link my 3D model to my physical entity affected by gravity. Why should it be otherwise in a game engine ?
But the concept of entity goes further: not only a part of the game engine, the entity is to be an object in the game world. So why would you have to store informations used by the "hard" game engine (video, sound, physics) and informations used by the gameplay in two different places? That's why the AGEEntity class contains some kind of hashtable (if you don't know what it is, consider it like a single-dimensional array, except each element is linked to a key -in this case, a string- instead of an index number) named Properties. If you want your entity to have hit points, just add a value named health, of type integer to its properties. To access it, you'll just have to type something like MyAGEEntity.Property[health]. A property can be of any type (even another entity or another table of properties, although this might give you serious headaches), and can also be an array of values.
Now, if you want your entity to just sit back and watch the beautiful skydome above its head, you can. But if you want it to do something a little more interesting, you can too, and very easily. Everything is handled through events and delegates. For instance, the event OnEachFrame happens 10 times every second. Just code a little method to handle artificial intelligence and with a single line of code (MyAGEEntity.OnEachFrame += MyAIRoutine()), you can assign it to all entities who are to use it. Other events will be included for everything that can possibly happen in a game world (the entity is clicked, collides with another entity, comes near another one, etc...)
To sum up: before, a character was an Irrlicht node + an ODE Geom + a lot of stuff to handle the sounds it emits + another class to handle its behavior. Now it's just an AGE entity.
2- Other features
In addition to this, AGE contains (among others):
- The AGEInputHandler class which allows you to handle (through events/delegates) all kind of input you can imagine, from the usual OnMouseMove(), OnMouseWheel() and OnKeyUp() to more advanced ones like OnJoystickMove().
- The AGEAudioPlayer class which can play sounds/music (wav, ogg, mp3 or midi) and allows you to change volume and pan, as well as frequency (to simulate the sound of a car's engine when it accelerates, for instance). You can also specify a random variation in frequency, so each gunshot will sound different from the last one.
- A new type of camera in addition to the FPS camera and the "targeted" camera" : the "rotating" camera. Its rotation is set using its Rotation Vector3D like a "normal" node. It can also be rotated along the Z-axis ("roll" axis). All the poor fellows who spent hours trying to simulate a plane's cockpit in Irrlicht (I was one of them) know what I'm talking about.
- AGE also extends Irrlicht capabilities regarding 2D games. Okay, Irrlicht can create 2D games, but it was quite a mess, to be honest. In every "BeginScene() - EndScene()" loop, you had to redraw everything and to manually recompute the screen positions of objects if they (or the "camera") have moved. Now there are 2D entities who have a position and a size independant from their screen coordinates. There is a also a "2D camera" with its own position and field of view. Basically, it's a SceneManager for 2D!
3- The AGE.Library namespace
AGE also features, inside the AGE.Library namespace, a whole set of "toolbox" classes which can be used for different types of games. Some of them are :
- The AGERandom class, with a constructor which accepts a single string parameter. This string can contains various "definitions" of random numbers. "1-8", for instance, will generate a number between 1 and 8 (obviously). But now, if you use "3d6+4", the AGERandom class will simulate the roll of three 6-faced dice and add 4 to the rolled value. Very useful for role playing games, this can also be used to apply normal distribution to any randomly generated value. You can also specify "floor" and "ceiling" values so that your "2d8-4" roll will never return anything below 1, for instance.
- The NameGenerator class can generates names by combining random syllabes and "pre-defined" parts. For instance, the class can randomly select a first name from a list (from a string array you provide), add a space and then generate a fully-random last name. You can also choose to randomize only the last part of the last name for a scotsman whose last name will always start with "Mac". Hey, that's just an example! Here's an on-line program which does roughly the same thing, so you can get the idea.
- The LevelGenerator class creates a level of "dungeon" from a few parameters. This useful for role-playing games or a "skirmish" mode in an FPS. It can also create an "outside" map (randomly dispatching various tiles: water, moutains, rocks, snow... Useful for a wargame, or the outside parts in your role playing game). Here's an on-line program which does roughly the same thing, so you can get the idea.
- The AGEXMLFile class is used to easily handle XML files to read/save game settings, or to allow the creation of "moddable" games. Trust me, if every unit of a wargame is an XML file in the "UNITS" directory, the game is gonna stay MUCH longer on my hard drive than if the list of units is hardcodded in the source code.
- The AGEEncryptedXMLFile class does the same thing, except the XML file is encrypted using a RC2 algorithm. Useful for savegames.
4- What now?
Well, here we are... I'm eagerly waiting for your suggestions, advice... Do you thing this project is a good idea? Not? Any other ideas?
I'll post a message in the Irrlicht forums when the library is complete, something which should happen in less than a month now.
Thank you again for reading so far!
