Pondering Pause

So, it's been a few months since I posted here.  But, it's not like I've been slacking.  I've even fleshed out some of the start-up sequence code for Nimble (I ended up changing one of my dev machines, and that caused me to need to do some extra caps checks and respond properly to what was found).  And then there is work and a half-dozen other "free time" projects (won't go into a list here).

 But, now we've come to a point where I need to stop and ponder a few things.  First, SlimDX has their June 2008 release out, which changes a few things ... and I think it would be best to bring Nimble up to the latest-and-greatest.  Second, I've been thinking through the games I'd like to get to making.  The responses I've gotten from the ARA Tech Demo (plus some of my own re-tinkering) have made that fade from my mind as my "next big project".  I find myself sliding back to my strategy/board gaming roots.  And those sorts of games wouldn't really require a full Nimble2D-type engine to get to coding them ... in fact, they could probably be done using straight Graphics.Drawing calls.  Finally, I've found myself paying some attention to some wise advice I received from one of the folks hanging out at the Indiegamers Forums -- find/build an engine to use quickly, so that games can get made.

And now I'm off on a week's vacation ... and I plan to do some pondering.  Advice and comments are always welcome! :-)

Posted by MattWorden | with no comments

My "QuickTrig" Helper Class

I've uploaded a ZIP file that contains the source code for the "QuickTrig" helper class that I've mentioned a couple of times now.  You can get it by clicking this link.

For those curious, looking through that should help explain how I can handle my angles primarily in degrees (as mentioned in my previous post).

Feel free to give it a look ... and use it if it helps you out.  Performance-wise, I've found the COS and SIN look-up functions to take half the time of the comparable Math.Cos and Math.Sin traditional functions.  While the speed increase is nice, being able to just work in degrees with the rest of my code is the biggest help given by this class.

-Matt

Posted by MattWorden | with no comments
Filed under:

Units of Measure

I've been working through some auto-moving sprite functionality, and have wandered a bit further down that road than I originally expected to at this point ... so now I need to back up a bit to get back on the main route of progress.  Here is my list of current things to do:

  • Finish fleshing-out my auto-move sprite class (going to set it up to work like a cross between a simple-but-somewhat-intelligent game object and a particle)
  • Crop things down into a "base" sprite class ... and change the auto-move sprite to inherit from the base
  • Build the primative (circle, rectangle, triangle, line) sprites from the base sprite
  • Finish the initial camera functionality (sprite-following, defined bounds, and defined viewports -- leading to multiple cameras in a GameSpace and "split screens" ... btw: thanks once again to the XNA Machine Blog who is taking a slightly different approach to similar terrain -- and that's helping me see things in new ways as well)

Once I get that far, I should be ready to compile a quick demo on how the camera and sprite basics work.

But I wanted to be sure to touch upon a couple units-of-measure that I will be using throughout the library ... and since I don't have something productive to show from my code at this point, I figured now might be as good a point as any. ;-)

Angles In Degrees -- I prefer my angles to be measured in degrees.  Something about my old-fashioned American math training just won't let go of me ... so, I like my circles to start at 0 degrees at top, increase in a clockwise fashion -- 90 degrees is to the right, 180 degrees is down -- until you end up at the top again at 360 degrees.  So, if you see a property or function that is returning an angle (names like "Heading", "Facing", "Aiming", "GetAngle", etc.), it will be in degrees.  However, for properties, I will likely have an equivalently named property with a "_InRadians" suffix (such as "Heading_InRadians") to give something to work with if someone wants to use Windows functions that prefer radians.  The "QuickTrig" helper functions in Nimble2D operate in degrees -- so, making use of those is very easy with this degrees-friendly approach.

Time in Seconds -- I've found it traditional for game programmers to deal with time in milliseconds, for a number of different reasons.  However, I've found over time that I always need to convert those into true seconds to do things related to time-based programming (X = X + VX * (DeltaMS / 1000), etc.).  So, with this library, I've decided to always deal in actual seconds ... usually of type Double.

Space Measurements in "GameSpace Pixels" -- Position and spacial measurements will essentially still be in pixels, with the normal caviats thrown in when dealing with current 3D programming: It's a pixel if everything is at a 1.0 scale.  And everything will be relative to each other within the GameSpace ... so, basically, the camera's position will determine what will be showing up on screen.  Having a position of (800, -16372) may be in the middle of the screen, if the camera is moved into the right place ... and something at (805, -16372) will be 5 pixels to the right of the first object, assuming a scale of 1.0.  When I combine these two things, I like to think of these units as "GameSpace Pixels", as it reminds me of the relativity between all things within the GameSpace.

Rates are "per Second" -- Any rate-style measurement -- "Linear Speed", "Acceleration", "Rotational Speed", "Alpha Fade Rate", etc. -- will be in a "per second" format.  Linear Speed, for example, is in "GameSpace Pixels per Second" ... Acceleration is "GameSpace Pixels per Second per Second" ... Rotational Speed is "Degrees per Second" ... Alpha Fade Rate is in "Values per Second" (where a "value" is each integer in the 0-to-255 range).

"ColorOnly" versus "Color" -- There are times when I like to separate the Alpha channel out by itself from the rest of what would normally be an ARGB-style System.Drawing.Color.  Also, there are cases (such as background color) where the Alpha channel just doesn't matter.  As an example of the former, sprites will have a "SpriteAlpha" property that can hold a value of 0 (completely transparent) to 255 (completely opaque) and a separate "SpriteColorOnly" that, while still being of type System.Drawing.Color, will only make use of the Red, Green, and Blue channels to color-shade the sprite.  If something contains just the word "Color" (and not the "Only"), then all 4 channels will be used for whatever purpose that property or function is up to.

Those are the main ones that I've run into so far ... I'm sure there will be more, so I reserve the right to re-visit this topic (and maybe even change what's been stated here). ;-)

-Matt

Doing 2D in SlimDX

Now that I've had a couple of weeks to play around with 2D programming in Direct3D9 via SlimDX, here are a few things that I've found.

After creating the Direct3D Device (as explained in the "Graphics Enumeration and Launching the Game Form" post), I create a Direct3D Sprite object (which I will be calling a "Sprite Batch" object):

varSB = New Direct3D9.Sprite(varD3D_Device)

This will be passed through the main Nimble2D object to each of the 2D objects that will be drawing themselves to the screen.

The magical math-thingy that makes the whole thing work is how Matrices and Matrix Transformations are used to determine where and how 2D sprites are drawn.  As mentioned earlier, all objects within a gamespace (including cameras) will have a location (simply a "Current X" and "Current Y") within "game space", which essentially is a way to measure their positions relative to each other.  They will also have a "Facing" angle and a "Scale".  These are the main pieces used within SlimDX's nifty Transformation2D function to get the matrix needed to draw things how they should appear on screen.

First, the camera:

varActualMatrix = SlimDX.Matrix.Transformation2D(New SlimDX.Vector2(varWidth / 2, varHeight / 2), 0, New SlimDX.Vector2(varScale), New SlimDX.Vector2(varWidth / 2, varHeight / 2), varN2D.QuickTrig.DegreesToWinRadians(varFacing), New SlimDX.Vector2(varCurX, varCurY))

varInverseMatrix = SlimDX.Matrix.Invert(varActualMatrix)

The parameters of that function are as follows:

  • scalingCenter - A Vector2 around which to scale things (set to the middle of the screen)
  • scalingRotation - A Single that indicates rotating the X/Y scaling away from the identity angle
  • scaling - A Vector2 that gives the actual X/Y scaling (1.0 = original size)
  • rotationCenter - A Vector2 around which to rotate things
  • rotation - The angle to rotate (I like to work with angles in degrees ... DirectX and Windows trig functions prefer radians ... so I have a translator function)
  • translation - A Vector2 to relocate everything in X/Y space

The first line sets the camera's actual matrix ... the second line uses that to create the inverse of it, which will be passed to the sprites within the gamespace to relocate them in relation to the camera.

 So, the sprites go like so:

Me.varMyTransform = SlimDX.Matrix.Transformation2D(New SlimDX.Vector2(varCurX, varCurY), 0, New SlimDX.Vector2(varSourceScale.X * varScale, varSourceScale.Y * varScale), New SlimDX.Vector2(varCurX, varCurY), varN2D.QuickTrig.DegreesToWinRadians(varFacing), New SlimDX.Vector2(0))

(For my sprites, I have a "SourceScale" that indicates if the initial source image is always to be stretched.)

To draw things, the following steps are taken:

  1. Begin Scene & Clear to Background color (Direct3D Device)
  2. Cycle through all layers ...
    1. Begin Drawing Sprites (Sprite Batch)
    2. Cycle through all sprites ...
      1. Transform the Sprite Batch Matrix
      2. Draw the sprite
    3. End Drawing Sprites
  3. End Scene
  4. Present to Screen

In this system, these steps are scattered through several objects, but put together, they look something like this:

     varD3D_Device.BeginScene()

     varD3D_Device.Clear(ClearFlags.Target, varCurGameSpace.BackgroundColorOnly, 1, 0)

     varN2D.SpriteBatch.Begin(SpriteFlags.AlphaBlend Or SpriteFlags.DoNotSaveState)

     varN2D.SpriteBatch.Transform = SlimDX.Matrix.Multiply(varMyTransform, LayerTransform)

     varN2D.SpriteBatch.Draw(varSourceTexture, varSourceRect, New SlimDX.Vector3(varOrigin.X, varOrigin.Y, 0), New SlimDX.Vector3(varCurX, varCurY, 0), Color.FromArgb(varAlpha, varColorOnly))

     varN2D.SpriteBatch.End()

     varD3D_Device.EndScene()

     varD3D_Device.Present()

I have other code bits in between things here and there to handle stuff like allowing for additive blending effects, full-screen fade in/out, writing "screen info" (screen size, camera position, FPS) to the screen, etc.

What I'm working through now is the sprite-based primary shapes (filled rectangles, circles, and triangles, lines, empty rectangles, filled rectangles with borders, and empty polygons using lines).  I hope to give some details about the lookup-table trig system being used at some point as well.

-Matt

Posted by MattWorden | 2 comment(s)
Filed under: , , ,

A GDI-based Screenshot Method

I was struggling with trying to make an easy screenshot method using SlimDX.  Looking at MDX samples, the standard method was to grab the Backbuffer into a surface (Device.GetBackbuffer), then use the SurfaceLoader.Save helper method to save that surface to a file.  I have not been able to find that SurfaceLoader.Save method anywhere within SlimDX.  (I have added it to the SlimDX "issues" list as an enhancement request.)

In the meantime, I was looking for a way to make it work.  An internet acquaintence of mine (and a hyper-good coder also working on a SlimDX-based project), CodeImp, suggested that I lock the surface and transfer the data to a GDI bitmap and use the Bitmap's ability to save-to-file.  I also wondered about using the SlimDX's Texture.FromStream method to create a texture from the surface, then do a Texture.SaveToFile ... but none of these worked.  For some reason, once I locked the rectangle on the surface, that LockedRect's Stream wasn't able to get its own length -- so it kept throwing errors.

 So, my next attempt was to use the surface's GetDC to see if I could create a GDI Graphics device from that DC and do something with it that way.  That's where the "looky what I found" happened ... GDI Graphics devices have a method called "CopyFromScreen", which does exactly what it says.  This made me drop any SlimDX-related code and go pure GDI, with great results.

Here are the steps:

  1. Determine your Top, Left, Width, and Height to capture ... if in full screen, these are 0,0,ScreenWidth,ScreenHeight ... if in windowed, these are the Top, Left, Width, Height of your Game Form
  2. Create a new Bitmap using Width and Height
  3. Create a Graphics Device from the new Bitmap
  4. Do Graphics.CopyFromScreen
  5. Do Bitmap.Save
  6. Dispose the Graphics Device and Bitmap

So, it's not quite the 3-step process available with MDX, but this pure-GDI process should work no matter what your drawing system is.  Here's the actual VB.Net code:

        tempBMP = New Bitmap(tempWidth, tempHeight)
        G = System.Drawing.Graphics.FromImage(tempBMP)

        G.CopyFromScreen(tempLeft, tempTop, 0, 0, New Size(tempWidth, tempHeight))

        tempFileName = "Screenshot_" & Date.Now.ToString("yyyyMMdd_hhmmss") & ".png"

        tempBMP.Save(tempFileName, System.Drawing.Imaging.ImageFormat.Png)

        G.Dispose()
        tempBMP.Dispose()

This routine names the file using the current date and time (down to the second) and saves it as a PNG.  It seems to work fine in both windowed and fullscreen mode.

-Matt

Posted by MattWorden | with no comments
Filed under: ,

Laying Out the Graphics Approach

I won't be able to do much more coding until the weekend.  So, I figured I should give a quick overview of how I'm going to approach the main graphics drawing routine.  I'll start high-level and work downward, then spiral back upward, and then back down a little bit before popping up into the atmosphere to wrap everything together.

It would be interesting to me to be able to approach displaying a game as if it were a live-action TV show.  You would have different sets (I'm going to call them "Game Spaces") for different sort of things.  Think about a normal local newscast -- you have the "main anchor desk" set, the "weather map" set, the "sports report" set, the "investigative reporter" set, etc.  For a game, this might translate into things like a main menu, a configuration menu, a high scores list, the pre-level briefing, the main gameplay space, the post-level results, and a game over screen.  Each set would have 1 or more cameras trained on it, and you would play the director ... "switch to set 1, camera 1" ... "zoom camera 2" ... "switch to camera 2" ... "prepare camera 1 on set 2" ... "move things around on set 2" ... "switch to set 2, camera 1" ... etc.

Now, when programming 2D games, I've always logically grouped my graphics into layers.  There's usually some sort of background layer which consists of your ground-level surface or a starfield or something else that is simply going to be behind everything else.  It may scroll around, but it will otherwise not really interact with anything else in the game and it's just there for your eyes and brain to have a backdrop on which to make sense of the rest of the game.  Then there is usually one or more layers of game objects (these are usually called "Sprites", and I don't plan to stray from that norm).  These layers might consist of a map layer and a layer for ships and weapons, etc.  Basically, I try to group the sprites that may interact with each other (and probably won't overlap in 2D space) into the same layer.

Let's use Gem Raider as a quick example.  Look at this screenshot (click it for a big version):

Example Screenshot of Gem Raider

In this game, I had 6 layers (starting back to front) ...

  1. The grid-like backdrop surface
  2. The "under the walls" explosion layer
  3. The "walls" layer for the main static map structures
  4. The "moving objects" layer for the player ship, the gems, and all of the weapons
  5. The "above everything" explosions layer
  6. The UI layer to show the score and the quick key listing

Each layer becomes, essentially, a collection of sprites.  Especially if you treat your primatives (drawn circles, rectangles, lines) and text as sprites, which I plan to do.  Sprites move around freely in game space.  Layers are drawn from back to front, and the current camera determines what part of that game space actually makes it to be displayed on the player's screen.

So, why put things in layers?  Why not just assign each sprite a "z" (or depth) value and allow DirectX to sort the order to draw things in?  Because I would like the programmer to easily be able to apply logic to all sprites in a layer at the same time.  Also, it will make for a logical grouping within which to breakup update and draw processes, if the game programmer wishes.  While Nimble2D will be designed to very easily draw everything on screen, it will still allow the programmer some capability to mix in some of their own drawing code if they wish (perhaps to render a true 3D object in amongst the layers somewhere).

Just as sprites will be able to move around, rotate and scale, cameras will be able to move around, rotate and scale/zoom ... and this will be reflected in how the sprites are drawn to the screen.  However, there will also be some "over layers" available within a game space that will not be impacted by the camera.  These over layers will be used to render UI components and messages onto the screen (after the camera shot is drawn) and always have them show up in the same screen location, no matter what is going on with the camera.

For most of what I'll be doing with Nimble2D to start, I'm just going to work with a single camera per game space, which will be drawing directly to the backbuffer.  However, I will also be keeping in mind that this system will eventually allow for multiple cameras in a game space, which will draw to their own render targets and those resulting graphics will be assembled onto the screen by the game space ... this will make it easy to do split screens for player-versus-player type games or games which might need to track multiple locations in the game space at the same time.

At the highest level -- the Nimble2D class itself -- each game space that is created will be tracked by the system.  A call to Nimble2D.UpdateAll will push update calls down through the camera, layers and sprites of the current game space (and every game space that is setup to do "background updates", which I will get into at a different time).  Drawing everything in the current game space to the screen will be done with Nimble2D.DrawAll, and switching between screens will be as easy as setting a different game space as Nimble2D.CurrentGameSpace.  As mentioned, there will also be finer-grain controls available to allow the programmer to update and draw just the pieces as is needed.  This also sets a nice framework for easily allowing full-screen fade-in and fade-out and other fun stuff.

For now, let's put it all together with this graphic of a single game space:

Nimble2D Game Space Visualization

It shows multiple layers resulting in a collection of sprites within the game space.  A camera presents a portion of the game space to the screen.  And over layers are added to give the player a single frame of the game.

2D game programmers will need to shift their thinking a bit from managing things within the scope of "screen space" to managing things within "game space" and grouping those things into layers ... and to how they wish to position the camera to show the game to the player.  (This also presents a programming challenge for the NimbleInput class -- giving mouse coordinates in both screen and game space ... but that's exactly where a library like this is supposed to make things easy on the game programmer, right?)

There is a lot of class skeletons and methods to get into place just to draw some simple sprites on the screen.  But once those are in place, the actual game code writing should become much easier, and we can then start fleshing things out to add value quickly.

-Matt

Posted by MattWorden | with no comments

Graphics Enumeration and Launching the Game Form

When it comes time to write a new game, I'd like to be able to tell my graphics library the various screen styles that the game wants to make available to the player and then have the library figure out which ones are supported by the player's computer.  This will be how Nimble2D does things ... receive a list of requested screen styles, look at each available adapter for support for the requested style, and provide back a list of available screen styles.

 Here's how the graphics enumeration testing app starts things off:

        Nimble2D = New clsNimble2D()

        'At least 1 video adapter is needed to continue ...
        If Nimble2D.Adapters_Count < 1 Then
            Application.Exit()
            Exit Sub
        End If


        '--- Change this list to reflect requested screen styles ---
        Nimble2D.AddRequestedScreenStyle(800, 600, False)
        Nimble2D.AddRequestedScreenStyle(800, 600, True, clsNimble2D.enumColorDepth.CD_32bit)
        Nimble2D.AddRequestedScreenStyle(800, 600, True, clsNimble2D.enumColorDepth.CD_16bit)
        Nimble2D.AddRequestedScreenStyle(900, 400, False)
        Nimble2D.AddRequestedScreenStyle(1024, 768, True, clsNimble2D.enumColorDepth.CD_32bit)
        Nimble2D.AddRequestedScreenStyle(1024, 768, True, clsNimble2D.enumColorDepth.CD_16bit)
        '---

Then the start-up form cycles through the available styles for the selected adapter:

        'Load Screen Styles List Box
        If modGame.Nimble2D.AvailableScreenStyles_Count(Me.cboAdapters.SelectedIndex) > 0 Then

            For j As Integer = 0 To modGame.Nimble2D.AvailableScreenStyles_Count(Me.cboAdapters.SelectedIndex) - 1
                Me.lstScreenStyle.Items.Add(modGame.Nimble2D.AvailableScreenStyleName(Me.cboAdapters.SelectedIndex, j))

            Next

            Me.lstScreenStyle.SelectedIndex = 0

        End If

That gets us this far:  Nimble2D Graphic Enumeration Startup Form

Once the player selects the adapter and screen style and clicks "Launch", the game's code creates an instance of a game form and asks Nimble2D to launch it on the requested adapter in the requested screen style:

        GameForm = New frmGame()

        Nimble2D.LaunchGameScreen(GameForm, AdapterIndex, ScreenStyleIndex)

Which results in this:   Nimble2D Graphics Enumeration Launched Game Form

 So ... how's it done?  Well, SlimDX (which is what Nimble2D uses to access DirectX) makes a number of enumeration functions and properties available.  The available adapters are grabbed when Nimble2D is first constructed, using this code:

        Direct3D.Initialize()

        Me.varAdapters_Count = Direct3D.AdapterCount()

        For j As Integer = 0 To Me.varAdapters_Count - 1
            Me.varAdapter(j) = Direct3D.GetAdapterIdentifier(j).Description
        Next

The handling of requested screen styles is a bit more complicated.  So, instead of giving code here, I'll walk through the steps.

  1. The supplied parameters for screen style are:  Width, Height, FullScreen, and ColorDepth
  2. If FullScreen = False, then the ColorDepth is assumed to be whatever the primary adapter is currently set to, and the screen style will be considered available as long as the Width and Height are smaller than the current screen size
  3. If FullScreen = True, then each adapter is run through the various formats for the given ColorDepth in preference order.  As soon as a supported format in the given Width and Height is found, then it is marked as available for that adapter.  The first-found supported format is noted to be used later if that screen style is selected for the launch.

When the game requests for the game form to be launched, Nimble2D resizes the supplied game form to the width and height of the selected screen style, shows the form, and creates the Direct3D Device:

        GameForm.Size = New Size(varSelectedScreenStyle.Width, varSelectedScreenStyle.Height)
        GameForm.Show()

        Dim presentparams As New PresentParameters

        presentparams.BackBufferWidth = varSelectedScreenStyle.Width
        presentparams.BackBufferHeight = varSelectedScreenStyle.Height

        If varSelectedScreenStyle.FullScreen Then
            presentparams.BackBufferFormat = varSelectedScreenStyle.BackBufferFormat
            presentparams.Windowed = False
        Else
            presentparams.Windowed = True
        End If

        presentparams.DeviceWindowHandle = GameForm.Handle

        varD3D_Device = New Device(AdapterIndex, DeviceType.Hardware, GameForm.Handle, CreateFlags.HardwareVertexProcessing, presentparams)

The next thing to tackle is the main skeleton structure that will be used to get graphics on the screen ... Game Spaces (and their cameras), Layers, and Sprites.

-Matt

p.s. When requesting a screen style that is full screen, only 16- and 32-bit color depths are allowed.  The various formats (5 to 6 in each color depth) are checked in order of "preference".  If someone reading this has strong knowledge about graphics formats and in what order preference should be given, please post a comment or send me an e-mail ... I have some questions for you. ;-)

Posted by MattWorden | 1 comment(s)
Filed under:

Breaking Up the Solution, and How I Program

I expect, in the end, Nimble2D will be a rather full-featured library for making games -- graphics, particles, collisions, input, sound effects, music, etc.  But to get there, I will need to break things up into manageable chunks, building higher priority things first, then fleshing-in the more detailed things.  I expect there to be a core set of projects to handle graphics, input, and sound, with a few add-on projects to handle more specialized things such as asset handling, multi-language, tile maps, etc.

The expected core projects:

  • Nimble2D -- The Graphics System -- handling graphics capabilities enumeration & screen launching, game spaces, layers, cameras, sprites, trig, primatives, text, particles, and anything else that has to do with graphics.
  • NimbleLog -- Easy Log File Writing -- a lowly project, but quite useful ... I like to write log files -- not sure I have more to say on that topic. ;-p
  • NimbleInput -- The Input System -- handling keyboard, mouse, and game controller input, mouse-to-game-object relations, key-to-action mapping, and other things having to do with the player interacting with the game.
  • NimbleSound -- The SFX & Music System -- for SFX:  volume/pan control, sprite-position-based volume/pan, delayed/repeated firing; for music: music file categorizing, queueing & shuffling, fade-in/fade-out ... and other things sound-related.

Some probable add-on projects:

  • NimbleMap -- Tile Map handling -- what's a good 2D graphics library without a nice-and-easy way to work with tile maps?
  • NimbleAssets -- Asset Data handling (aka "Pack File handling") -- a library-style approach to getting game assets and data out of packed and encrypted data files.
  • NimbleLang -- Multi-Language handling -- a library-style approach to getting language-specific text phrases and making multi-language support easier.

I expect to work on them essentially in the order I listed them.  But, as I said, I will probably build working frames around the main features, move on to the next one, then come back to flesh something out in an earlier project as I find it needed.

This leads into how I work as a programmer.  I am quite new to .Net, although I'm not new to VB.  I broke my teeth on Commodore BASIC, Quick BASIC, and Pascal while I was in high school and early college.  Then, I wandered in the wilderness for a while after changing my major in middle and later college.  Once I was out in the working world, I became aware of VB3 and the VBA tucked inside MS Access 2.0.  I quickly progressed to VB6 (which I've done both business and game programming in) and I'm still working with Access/VBA.  So, it's only been a few months that I've seriously tried to work on VB.Net and C# projects, which means that I'm rather new to strong object-oriented approaches -- especially with games ... and I will likely be doing things "wrong" and in "non-traditional" ways.  If you see something completely out of the norm, or something that can be done much more effeciently in another way, please be sure to make a comment or send me a message about it.

I'm a very practical worker, and while I can discuss and design just on theory, I usually need a practical example to develop for.  In this case, the practical purpose for Nimble2D is to help me build my current game, "Air Ralley Ace" (ARA), which is an arcade airplane racing game involving scrolling landscapes, layered clouds, and lots of colored smoke.  As I make progress, I will very likely be using ARA examples to show off capabilities.

So ... first-things-first ... I need Nimble2D to be able to let the game know a bit about the player's graphics card -- texture size/shape support, supported full screen sizes and color depths -- and be able to launch the selected screen style.

-Matt

Posted by MattWorden | with no comments
Filed under: ,

A Nimble Launch

Nimble2D LogoOn this first post of the new blogspace for Nimble2D, I'd like to do two things:  (1) Give credit where it is due, and (2) give a brief overview of how I see this project at the start.

So, credit ... First, a big thank you to Chris Williams for setting up ilovevb.net (a perfectly logical place for a project like this to land), and for providing the space and resources for me to blog about the project.  Second, I have to give a lot of credit to Dave Munsie of JGOware for his now-extinct DXGame engine, which really opened my eyes to how powerful doing 2D-via-3D could be.  (Now go to his site and play Retroblast ... then read the rest of this.)  Third, my recent epiphany on how to approach things with this project came about by reading the xna machine blog, where the concepts of matrix math and how game objects relate to one another (and to the camera) really became clear.  If you want to see some very neat VB.Net + XNA work taking place, be sure to check out that blog.

And finally, my traditional shout-out to the crew at the Game Programming Wiki (gpwiki.org), who provide a nice combination of friendly interaction and good brains to be picked.

Now, the project ... as given in the brief description: Nimble2D is a 2D game development library for .Net, based on SlimDX and DirectX9. It will use Direct3D9's Sprite functionality to create a fast 2D environment (with real-time rotation, scaling and blending), mobile cameras, sprite-based text and primatives, and real-time sound effect panning and volume based on sprite locations.  But first, I'll explain how I got here ... and where I think I'll be going.

I came to the point of writing my own 2D library due to a number of reasons.  First, my trusty tools that I've been using (VB6 + DXGame) are a bit long in the tooth ... although I'm happy with what they allowed me to do with Gem Raider.  Still, there were things that I wanted to do differently and I wanted to have a reason to get to use the .Net programming languages.  I was about half-way done with my new game project when it struck me that I should probably find a new set of tools to make the game with ... it would give me a very practical example of a game that I'd want to make, and a reason to learn how to use those new tools.  So, I looked around a bit and didn't quite find what I was looking for.  XNA was a bit requirements-heavy for my taste (I don't actually have a computer in my house that can install Game Studio Express due to OS or graphics card requirements) ... SDLdotNet didn't have real-time rotation nor additive blending (DXGame had spoiled me) ... Torque Game Builder didn't seem to fit my personal style ... and BlitzMax would require learning a BASIC-like language that wouldn't be very useful in a work setting.  So, I settled on VB.Net as my language (although I'll probably play around with C# as well) and looked for a way to tap into DirectX.  That's when I found SlimDX ... and suddenly everything came together.  Now all I need is to put together a fast, flexible 2D system ...

And that leads to Nimble2D.  Why "nimble"?  Well, frankly, all of the other names that I came up with first were taken or were hard to pronounce.  It was while I was describing to my wife (bless her for standing there and listening) how I wanted the cameras to work that I first used the word "nimble" as a descriptive ... and then I paused and ran over to Google for "nimble" combined with "game engine" and for "Nimble2D" ... and then I had the name.

So, here are some of the main concepts ... Imagine having a "game space" that is a flat surface, like a table top, to work on.  All of your in-game objects (sprites) are put down onto the game space in layers.  A camera is then hovered above the layered game space and snaps a picture of the current frame.  That camera should be able to move to frame the game space in whatever way the programmer would like, including rotation and zooming.  Now imagine having multiple game spaces to organize different aspects of a game -- a "main menu" game space, a "high score" game space, a "world map" game space, etc. -- and being able to switch between these spaces the same way a TV show director switches between his various sets.  This is the approach being taken with Nimble2D.  It will be a sprite-based, camera-based, matrix-based, real-time 2D-via-3D system ... and the library should allow the game programmer to just work with the traditional 2D settings (X, Y, Facing Angle, etc.).

Along the way, I hope to pack in some tricks I've learned as standard goodies within the libraries.  So now all I need to is write some code ... ;-)

-Matt