The currently released version of BASeBlock is 2.3.0. I have made a lot of changes to the game, added a few blocks, abilities, and other fun stuff, and refactored various parts of the code to make things work better since then. One of the biggest new features is “framerate independence”. 2.3.0 and earlier versions basically did velocity like this for every game tick:
Location = new PointF(Location.X+Velocity.X,Location.Y+Velocity.Y)
However, the faster the game loop ran, the more times this would run, and typically the higher the fps the more the game loop would run too. This meant that the speed of objects could be the same internally but visibly the objects seemed to move at wildly different speeds. The “fix” to this is relatively simple- instead of simply adding the velocity to the location, we need to take into account some other factors. First, we analyze the problem. What do we want to achieve? The quick answer is “we want the movement of objects to remain equal regardless of how fast the game ticks go”. The best way I’ve found is to choose a given framerate as the “ideal” framerate; if the game runs at this fps, than the result would be that the velocity is added verbatim; If the framerate is less, than we add “more” to compensate; for example, a framerate of 30 in this case would double all speed additions that are performed; and a framerate of 120 would half them.
BASeBlock already tracks the FPS, so the solution was three-fold; first, create a routine that would retrieve the appropriate multiplier based on the framerate and the desired framerate, next, create a routine to simplify the incrementing of a location with a velocity that would take into account the current multiplier that was derived from the framerate, and also to change all the code that simply adds them to use the new routine.
Implementing this in BASeBlock was something I was wont to do for quite some time; it seemed a lot more involved than it really was. Eventually I just decided to try; if things went sour I could always roll back to a previous SVN commit anyway.is has
First, I added the routine for getting the game Multiplier. This required the current FPS of the game. Since that seems like something best dealt with in the presentation layer (and also since the main game form was already tracking FPS for the FPS counter) I simply added a property to the IClientObject interface, which is designed to allow for a way for the form and the game logic to communicate without explicitly requiring knowledge on what it is communicating with. With that property in place, I simply implemented the multiplier routine as a basic division- the DesiredFPS divided by the current FPS. (There is an exception for the case where the retrieved FPS is 0 where it will return 1 for the multiplier). One very interesting side effect of this is that I could, if I wanted, “fake” slow motion by munging around with the CurrentFPS as returned by the clientObject, though that is probably not a good use of this design.
I then implemented a simple routine for incrementing the location, not surprisingly I called this “IncrementLocation”. It adds the velocity, but multiplies it by the multiplier as derived from the currentFPS and desired FPS.
This worked rather well, once I found and replaced all the old direct-addition code with a call to this routine. However there were still some odd behaviours; mostly related to velocity decay. Some objects- particles, the gamecharacter’s jumping, some items falling, and whatnot would reduce or increase their speed by multiplying components of that speed by a set factor. For example, a particle might “slow down” after it spawned by multiplying it’s X and Y speed by 0.98 each frame. I needed to make similar adjustments to the multiplications factors there in much the same manner as for the additions.
I still encounter minor issues that are a direct result of the changes to a “managed” framerate concept; a nice benefit compared to 2.3.0 is that I was able to remove the silly Thread.Sleep() call that slept for 5 or 50 milliseconds (I forget specifically) so the framerate is typically higher; on the “Spartan” Level set builder, the framerate is usually close to 200, which is pretty good for GDI+, and that’s the debug build, too, which is slower than release.
After this, I tried to improve the platforming elements of the game a bit more. I added some new powers, fixed a few minor issues with some of the powerup management code, and added a new interface for the editor to allow blocks to draw something “special” when being shown in the editor; this is used by the powerup block to show the contents of itself as well as modify the tooltip shown. Another change was “block tracking” at the level of the PlatformObject. This also sounded a lot more complex than it was. The idea was simple- when the character, or anything, is on a block, we want them to move with it. This was done by having the platform object track any block it is on, then, each frame, adding the distance the block moved, if any, to it’s own location as well.This has worked spectacularly. I also added an interface for blocks so they can receive notifications from a platformobject when they are stood on.
There is a bit of a downside to this idea, though, based on how I implemented some other “moving” block features for performance reasons. I have a few blocks that give the illusion of moving when hit, but in fact destroy themselves and spawn another object in their place that looks the same. These blocks include BlockShotBlock, BallDirectShotBlock, and the “magnetAttractor” block; the first one gives the appearance of shooting upwards when hit, breaking all blocks in it’s path; the second goes in the direction the ball that hit it was going, and the third works in tandem with another instance of a magnetAttractor block to create the illusion of the two blocks flying towards each other and exploding, or flying apart. These rely on GameObjects to control their behaviours after they are hit, allowing themselves to be destroyed and allowing the rest of their “action” to be governed by those objects. Most specifically, the “BoxDestructor” which is used to create a block-shaped projectile that can destroy other blocks. The magnetAttractor creates two such blocks when necessary, and controls them with yet another gameobject that handles their velocity change, and detects when they meet, creating the requisite explosion. I did it this way because my animatedBlock “architecture” is terrible and annoying to work with, or, at least it was at the time. This means that a gamecharacter cannot stand on such a block and be “fired” along with it, which would have been an awesome gameplay principle for level design. I did create a movingplatform block that opens up some neat possibilities too, though. And causes some really goofy gameplay when I replace all the blocks in a level with them.
My next endeavour was related to the editor; With the new platforming component, I had made it possible to create a Platform-oriented level, with or without a paddle, by adding the appropriate triggers and components to a level. I forgot to add some of these more than once; in fact the second level of the “testplatforming5.blf” levelset included with 2.6 forgot to set the autorespawn field of one of the spawner blocks, meaning that once you die, you cannot beat the level, since only the paddle respawns, not the character. To help alleviate this, I decided to create “templates”. This means that when adding a new level, as well as being able to just add a blank level, one can create a new level copied from a template. This really added a richness to the editor. Templates are loaded from the templates directory, and can be shown either in a categorized drop-down or in a categorized dialog; the “category” design derives from the template concept used with tools such as Visual Studio itself or VB6, which separates the templates into separate categories. This should make the creation of custom levels, particularly platforming levels, far easier. Templates can also add sounds or images to the loaded Set. (possible revisions might be to warn when a template object conflicts with an existing resource, rather than replacing it).
I also fixed a myriad of other bugs and UI issues that I encountered while working on other features. The newer version is really shaping up to be a great update.