DeathRun Part 2: Deciding on control schemes and layout options

So now that I've got an idea and a basic plan I need to start making some decisions.  I've already decided to use HaxeFlixel as my game engine, but I'm going to start with targetting only the Flash platform.  Once I get it working on Flash, Haxe will let me easily port it over to other platforms like HTML5 or desktop targets.  While I could port it over to mobile I've never enjoyed playing a platformer on a touch screen so I might just pass on that for now.

I also want to decide what the game is going to play when I'm finished because that will influence design decisions.  Decisions like target resolution, sprite size, and level size don't seem to be connected to gameplay but they can have a large affect on how the game is played.  

How resolution decisions affect gameplay

If you compare Super Mario World on the SNES to Sonic the Hedgehog on the Sega Genesis you get a picture of how these decisions affect gameplay.  In Super Mario World, Mario takes up one space on a grid that is 16 x 14.  If he is running to the right, Mario's sprite sits slightly to the left of center screen so the player can see ahead 8 tiles.  If Mario's speed is 8 tiles/second (it is actually much higher) I know that a player has one second to react to an obstacle or enemy that appears off to the right.  On the other hand, Sonic is much larger on the screen.  A Sonic player can only see about 5 tiles ahead.  If Mario and Sonic run at the same 8 tiles/second the Sonic player will have a little over half a second to react to the same obstacle.  Sonic is going to seem to be running much faster and is going to play very differently than Mario, even if both are moving at the same speed.

So how do I want DeathRun to play?  I want a viewing area closer to Mario rather than Sonic.  Avoiding Death and planning out how to hit the enemies is going to play a large part of the game, so being able to view a larger area will be helpful for the palyers.  In an avoidance and planning type game, having a 20x20 tile view is going to make the game easier than if I only gave players a 10x10 tile view.

So I think my target resolution is going to be 800x800.  If my tiles are 40x40 that will give me a total viewing area of 20x20 tiles.  That should give players enough space to see what is going on around them and plan accordingly.

DeathRun Part 1 : Project planning and setup

I've decided to start a new game project and figured this would be a good time to document my entire process from planning to asset creation to (hopefully) completion.  I've been lurking a long time on One Game a Month and figured now that October is half way over this would be a good time to start this month's project.  My timing could be better, but I've come up with a pretty simple concept that should be possible to complete in a couple weeks.

There is always an optional theme for the #1GAM games and with Halloween almost upon us it makes sense that this month's theme would be DEATH.  I've been kicking ideas around in my head for a couple days now and have finally landed on an idea that I think will be:

  1. Interesting to program
  2. Fun to play
  3. Possible to complete in a couple weeks

I also wanted to document the programming and creation process to keep myself motivated and maybe create a useful guide for anyone getting started with HaxeFlixel in the future.  So without further ado I give you...

Death Run

The basic premise is that you will play as a guy (named Guy, for now)  who is being chased by Death.  Death starts out slow and not very maneuverable, but the longer the game goes the faster he becomes.  The game will take place in a tower that Guy is trying to climb and each level is filled with monsters that need to be defeated before continuing.  The tricky part is that Guy has no way to kill the monsters.  Instead, he has to have Death do his dirty work.  Death will be following Guy constantly, so the player has to maneuver Death into killing the enemies instead of Guy.  Whenever Death claims a soul of a monster he slows down, his hunger briefly sated.  

The game will be a standard action platformer.   Each level will be a single screen with monsters scattered randomly about.  Death enters from a random screen edge and begins to chase the player.  After defeating all the monsters a door or something opens which leads to the next level.  Repeat forever.

I think this game is going to be endless with the tower levels getting harder and harder while Death speeds up more quickly.  I don't want to ever get to the point where it is physically impossible to dodge Death, but I do want the game to end with the death of the player.  That way, the game becomes a metaphor for life.  The sad truth is that you can never actually escape Death.  See how deep that is? 

HaxeFlixel FlxTilemap

Every time I go without using a FlxTilemap objects in HaxeFlixel I always have trouble using them.  They are a powerful tool but some of the features aren't obvious and the documentation isn't great.  I also have trouble finding examples online anywhere that are what I'm looking for.  There are lots of examples and each one works on its own, but they don't have a good overall picture of how it works.  So here I am brushing up on the tool (again) and figured I should record what I've learned so at the very least the next time I'm looking for this information I'll know where to find it.  Note that is is all true in HaxeFlixel 3.3.5.

For this example I'm using two images.  The first is just a black and white .png file that I will use to build my map.

The second are my test tiles.  They are just two 16x16 tiles end to end that I will use to draw test maps.

The HaxeFlixel FlxTilemap constructor:

More research on code reflection in Haxe

So I think I've found the cause of the problem I'm facing with code reflection in Haxe.  It has to do with the nullability of the type the variable is being declared as.  In explicitly typed languages, certain variables cannot be assigned the null value which forces the Haxe compiler to do something with them while compiling them down to C++, Java, C#, ActionScript, or whatever.  When I declare a variable without initializing it to a value the compiler looks at my output target language and sees if null is valid.  If it isn't it substitites a default value and (I'm guessing at this part) makes the variable a monomorph.  Until I use the variable in the program and it is set to it's explicit type any reflection call on it is going to return a type of whatever the compiler happened to assign to it, or maybe the type of a monomorph in each additional language.  This means that reflection will probably work well in untyped languages which allow a null value for basic types, but will cause some problems when trying to hit the explicitly typed languages.

 

Simple rules and complicated behavior

Sometimes simple rules can be used to generate complicated behavior.  I recently read a paper by Chris Melhuish, Matt Wilson, and Ana Sendova-Franks (available here) about how they solved the problem of grouping multiple colored discs scattered randomly around an area using robots.  To solve the problem they used a collection of simple robots each using simple rules.  The robots had a gripper that had the ability to pick up a frisbee and a sensor that could see in front of the robot if it was holding a disc.  The basic rules were:

Rule 1: If (gripper pressed & Object ahead) then 
Make a random turn away from the object. 
Rule 2: If (gripper is pressed & no Object ahead & colour in front different from colour carried) then
 Reverse for pull-back distance 
 Make a random turn left or right 
Rule 3: If (gripper is pressed & no Object ahead & colour in front same as colour carried) then
 Drop object and reverse small distance 
 Make a random turn left or right. 
Rule 4: Go forward 
 
The robots would just drive around randomly until they crashed into a disc.  Then they would pick it up and drive ahead.  If they ran into a different colored disc or a wall they would back up, turn in a random direction, and go again.  If they hit a same colored disc they would drop it.  Using these simple rules they were able to make simple robots perform the complicated process of sorting discs into groups by color.  
 
This is very cool stuff.  First, and most importantly, they are sorting things with robots!!  Secondly, the intelligence to solve the problem isn't built into the robots themselves.  The ability to solve the problem comes when you apply the simple rules over a period of time, or rather, the interaction of the rules with one another.  
 
There are other good examples of this same principle.  One is the Game of Life invented by John Horton Conway in 1970 (Wikipedia link).  The game allows for cells to be placed on a grid and then allowed to evolve naturally.  Each cell is either alive or dead.  Every step of the game each cell is checked against its adjacent neighbors.  Using four simple rules, the game produces potentially complicated patterns over time.  These four rules are:
  1. A living cell that has fewer than two adjacent living cells dies.
  2. A living cell that has more than 3 adjacent living cells dies.
  3. A living cell with 2 or 3 neighbors lives to the next generation.
  4. An empty space that has exactly three live neighbors is filled with a living cell.

Haxe Code Reflection strangeness

I am running into problems with the Haxe method of code reflection.  It could be that I'm just more familiar with Java and the ability of Java code to examine itself and learn what parameters different methods require.  The explicit typing of Java also makes things a little easier.  Haxe is statically typed, but the fact that the varaibles can be monomorphs without a type until they are initialized is throwing code reflection off.  It is strange that when I explicitly declare something a Bool code reflection sees it as an Int until it is initialized.  I'm not sure what this means for LearnBot and how I can work around it.