Its been a while since any of us updated the blog; all the teams suddenly realised that their projects were a heck of a lot bigger than they thought they were. Features and documentation are being dropped left, right and centre to help bring the projects back on track. Frequent blogging was the first thing to go!
My project, Escape From Swinburne (EFS), has shed some features including multiple AIs and more complex animations such as skidding-to-a-halt. However, all is not lost. In fact, over the last three weeks great progress was made (remembering that a "week" is three days plus some voluntary time at home, for this Scholarship).
EFS has evolved into a side-scrolling 2D game that lets the player use a jetpack to jump over gaps in the floor and (hopefully soon) avoid enemies.
EFS now features:
- Animated graphics
- Collision system
- World-scrolling
- Sound and music
- Dynamic frames-per-second (FPS) load-balancing
- Loading from a file (dynamic map creation)
- Jetpacking
Animated Graphics
EFS has implemented an animation system that allows any world object (an object in the game world such as the player or a floor piece) to have animations for certain actions. A world object, when loaded, can load as many image frames as it likes, then can specify what ranges of frames make a certain animation (eg. frames 10-19 are the left walk animation).
EFS provides the following animation hooks for world objects:
- Walk left
- Walk right
- Stand still left
- Stand still right
- Jetpack left (no horizontal movement)
- Jetpack right (no horizontal movement)
- Jetpack left (horizontal movement)
- Jetpack right (horizontal movement)
A small "fudge" has to be made with the current animation system because of a limitation in the collision system. The collision system can't deal with world objects that change width as they animate (since they might change width into a wall and get stuck). Hence, when animating, the player's (or any other world object's) width can never change and transparency must be used as padding. However, this means that players can seem to be able to step off an edge without falling (they are being caught on their transparent part). This is gotten around by putting a "shield" around the player at the edges of his bitmaps. It looks poor at the moment, but I hope to improve it.
Collision System
I wrote a complicated collision and movement system that uses vectors to control movement and some basic vector math (unit vectors etc) to detect collisions. Thank god I kept my Specialist Maths notes from school!
A main problem was that world objects could collide with something, but never butt right up to it (since their movement was cancelled because a collision would occur if it continued); there was always a gap. I resolved this by "growing" a movement vector pixel by pixel (using unit vectors) until the object either collided with something, or it was able to move by its whole vector. This meant that objects could "move as close as possible" to other objects, removing that gap.
World Scrolling
EFS lets you load a large wide image as a background to a level and will size the level to that image. It then lets the player move left and right around the level, scrolling the view as necessary.
A problem with this method is that every frame that is rendered has had the entire large background image painted. This is a very inefficient method, since only a fraction of the background is visible at a time, yet all of it is being painted. I have calculated that the painting of the whole background takes around 40-50% of the entire frame's rendering time: a massive inefficiency.
However, I lack the time to rewrite that system, what with the deadline fast approaching. Lucky today's modern computers can handle it.
Sound and Music
This part of EFS was cut back considerably. Originally I wanted each game object to be able to have their own individual sounds, but now there can be only three sounds: the background music, the player's walking sound, and the player's jetpack sound.
I grabbed some free sounds off the Internet and bashed them with a wave editor to make them sound slightly reasonable. However, they aren't the best; if you listen carefully you can hear artefacts and the sound repeating harshly. But they are quite okay.
However, as heavily cut back as this feature is, it still sounds great and does not detract from the experience.
Dynamic Frames-Per-Second Load Balancing
This part of EFS took me a long time (relatively) to do. The game speed in games should be constant and shouldn't be faster on faster computers. Old DOS games often have this problem. EFS has a dynamic load balancer that calculates data updates such as movement and collision every 16 milliseconds (62.5 fps) and the rest of the CPU's time is spent on rendering graphics frames as fast as possible (with a hard-coded max of 125fps to stop flickering). However, when the rendering framerate drops beneath 30fps, EFS will start sacrificing game data fps to speed up the rendering. The result: the game plays slower, but with a higher (but not that high) framerate. Modern computers almost never experience this.
This was achieved by using a "performance counter" from the Win32 API that counts time in microseconds (as opposed to a normal time getting function which get time accurate to around 10ms: not good enough). The game goes into a tight loop (maxing out your CPU) and only runs the data update once 16ms has passed. It will then only run a frame render when:
- There enough time until the next data update is due taking into account how long it takes to render a frame (the renderer times itself so it knows how long it takes to render a frame) OR
- The framerate has dropped below 31.25fps (a render hasn't run for 32ms)
However, it will skip renders if the framerate is over 125fps (a render was last run in the last 8ms).
My laptop manages around 80fps on one of my testing levels, and my main computer (much more powerful) managed 180fps until I put a cap on that to 125fps to prevent the flickering that occurs at very high framerates.
I created fps meters in the top-left corner of EFS, to show the player their current, highest, and lowest fps for the game data and the graphics rendering.
Loading from a File
EFS will load its levels from map files. This means you can create levels on the fly without changing the source code of EFS just by editing a few text files.
Unfortunately, EFS has become so complicated that creating these text files is time-consuming and difficult. I had to create a template in Excel to help myself since the files get very complicated. A visual level editor is needed, but I don't have time to create one. :(
Jetpacking
The earlier revisions of EFS did jumping by adding an upwards movement vector against the downward vector of gravity. By holding down spacebar, you were able to continue adding that upwards vector against gravity and accelerate upwards at a great rate. I liked the "feature" so much, I decided to dump "jumping" and keep this "jetpacking" functionality instead. However, to limit their usefulness (otherwise the game would be ridiculously easy as you would be able to just fly across the top of the level), I implemented "jetpack fuel" which uses up as you fly and recharges when you don't. An onscreen progress bar is painted to show the jetpack fuel status.
TODO: Real Map(s)
At moment, I've created a simple dodgy testing map with my stellar (read: awful) drawing skills in MS Paint. It looks like a drawing out of a kindergartener's book. Even my dear old mother thinks its poor. Take a look at the screenshots to see what I mean.
The plan is, for the real maps, to take a picture of outside in Swinburne somewhere with a panoramic camera (for the wide angle) and then gaussian blur it in Photoshop to create a nice background for the levels. I have tried this before with Eyal's camera phone and it came up nicely. It is a technique I am pinching for some webcomics that use it for the backgrounds on the panels.
Then I will have to create the levels, which will be a pain because of the file format. Hopefully I can make something good in the time I have left. :|
TODO: AI
The very last feature of EFS I aim to get in before the deadline is a really stupid AI enemy. This AI will move left and right (changing direction when it hits something) and when the player touches it, the player will die.
This will require not only new code for AIs, but also changes in the collision system that will allow something to happen when the player collides with an AI, and allow the AI to detect when it hits a wall so it can move the other way.
I'll probably hack these changes into the code nastily just to get the feature done in time. I have a feeling that to get it done "properly" (ie not completely crap and limited) I will need a serious revamp of a lot of EFS (collisions, the game loop, etc). So we will see whether this feature makes the final version or not.
Wish me luck.