Monday, March 5, 2012

World 2 mechanics

Hey folks, Cody here. Sorry I haven't been posting a whole lot, but I'll be spending the next 4 days in San Francisco for Game Developers Conference! This of course means things may not progress too much this week, but I figured I'd drop in and talk about a few of the mechanics I'm working on for world 2.

The first, and most complex thing being added is the new power! As you may have seen in the previous post, world 2 will feature a robot power that allows the player to fire bullets. However, Robot Shadow will be unable to jump! This allows us to focus more on puzzles going into world 2. The robot power is actually being drawn with two separate bitmaps: one for the body and one for the arm. This lets me move shadow around on screen while independently rotating his arm to face whichever direction he's aiming. I'll be adding controls to let the player touch a position on screen to aim shadows arm, then press the fire button (which replaces Shadow's jump button) to shoot! Bullets will both kill certain enemies and hit buttons, which leads into the next mechanic I'm working on.

Buttons! World 2 will introduce buttons and shutters which are closed until the buttons are hit with a bullet. We will be using this to design puzzles in which the player needs to find a robot power and reach the button with it's limited mobility to proceed. The tricky aspect here is that in the past, all collidable objects have been a part of the level. The introduction of shutters means editing the tile map itself, which should be much more efficient than things like the light gates which utilize an independent object which must be updated. My current plan is to iterate through the tile map matrix when the button is pushed, looking for shutter tiles and replacing them with open tiles.

Finally, if all goes well, world 2 will have moving platforms. These are a must for moving robot shadow across gaps, and Marty has been pushing for them since world 1. Since these platforms will need to be animated, it's not really practical to make them a part of the tile map. That means they will be the first collidable object, which means checking their position when they are present. I'll also need to add some code to be sure the player moves with the platform if they are standing on it, so that should be fun!

That's all for now, look forward to all these fun things as soon as world 2 is finished!

Thursday, March 1, 2012

New Sprites

So, here are some of the sprites I've been working on for world 2.
Photobucket
New Transformation! New power!

These were a lot of fun to do. Trying to really push the cartooniness to make transforming feel really cool in game. I'll talk more about the robot power and its features in a later post.

New Enemy!

Here's the Roboshoot 5000. He shoots at you. He doesn't die like the stingers in the first world, he just shuts down so you can always go back for the power. 

Photobucket
New checkpoints!

In the past we used the light gates as vague checkpoints. That wasn't their original function, and the checkpoint spots were kinda thrown in as an afterthought. We've now made for real checkpoints and are placing them more thoughtfully, which is important because the levels in world 2 are a lot longer. In the future we're also going to revamp world 1, placing them less haphazardly, and reworking enemy positions to ease the learning curve. 


Photobucket
Turrets! They shoot at you!

Oh no!

That's it.

Sunday, February 19, 2012

Beginning World 2

The blog's been a little dead lately. For a while we were focused on just getting world 1 ready for its release onto the Android Market last week. 

That's done now, and we're on to World 2!

Production begins this week, and we have big things planned for the next world. Expect more frequent updates as we get the ball rolling.

One of the biggest complaints I've gotten on the visual side is the blandness of the environments. We remedied that a little bit in more recent builds, but they're still a little lacking. From now on I'm going to try to step it up and put as much care into the environments as I do the animation. Having a fresh start with World 2 will help a lot.

Here's what I have so far for the platform design:

World 2's platforms follow a simple mechanical motif. Lots of beveled edges, gears, etc. I'm not quite sure what I'm going to do for the actual backgrounds yet. 

Any suggestions?

Sunday, February 12, 2012

Wednesday, February 8, 2012

Boss Fights

Hey everybody! Cody here, sorry for the lack of updates. Trying to balance a game, work, and a full engineering course load is difficult at best. But worth it!

I wanted to talk about the boss fight. The first world's boss is done, and it took a lot of thinking to figure out exactly how I wanted to do it. I think I found a decent solution though, and Ill explain why it was so much harder than an enemy or something.

Good programming is all about modularity. You find ways to represent general cases, arbitrary values, etc. Why make a screwdriver when you can make a Swiss army knife? For example, the enemy class is a class that can represent any enemy we have created and (in theory) any enemy we will create. I do this by assuming very little about the enemy being created and letting many aspects such as size, behavior, and sprite sheet be defined when I create the enemy.


public Enemy(Assets assets, int type, int height, int width, int cols, int numFrames, int xPos, int yPos, int xSpeed, int ySpeed) { 
//values initialized here
}

So why couldn't I take this approach with bosses and make a general Boss class? Well, I definitely juggled with the idea, but the one boss that has been designed is much more complex than an enemy. Combine that with the fact that we don't even know what the other bosses will do yet and it just wasn't going to work out. However, I still need to classify all of my bosses under some distinct label that I can pass into my level. Things get really messy if I can't file all these bosses under some category. And that, my friends, is what Interfaces are for!


//Boss interface gives me a standard format for creating and storing a variety of 
//bosses for the different levels. In retrospect, I should have implemented the 
//player as an interface.
public interface Boss {
 
 public void draw(Canvas c);
 
 public void updatePhysics(double elapsed);
 
 public void update();
 
 public void killBoss();

}


There's an Interface, short and simple. And yes, I left the comment in which I lament over past mistakes. Hindsight is 20/20.. Anyways, think of this as a skeleton for a class. I can now create separate classes for every boss I ever want to create that implement this interface. That means they are required to define the 4 methods seen above, and I can call those methods without necessarily knowing what sort of boss I'm dealing with, but I can also write completely separate code for each boss. Cool, huh?

So since the boss is only being used once in one level under one circumstance, I more or less wrapped every detail concerning it into it's class. Most enemies are given a position as you saw above, the boss actually has his position defined inside of his own code. He goes there, everyone else deals with it. Then I just had to whip up some code drawing a huge static body, two animated arms, and animated eyelids. The arms switch animation when he charges up, and then bullets fly in every direction! Whenever we start making a new boss, we aren't bound to any of the limitations on how I developed this first guy; I can essentially rewrite everything and pass it to anything looking for a Boss object. So without further ado, here he is!

As a neat side note, absolutely no collision is defined for this dude. We instead created 2 new tiles, both transparent. One acted like a wall, other like a spike. I then pasted the entire boss onto the map, traced over him with the tiles (wall tiles for the black region, spike tiles for the white), and then deleted him off of it. Worked like a charm!

Hopefully we'll have the public build updated soon with the boss fight and the nifty screen shake and fade to black preceding it. And a new cutscene for good measure. Also, I'm working on rooting my phone so I can record some gameplay for those without Androids who want to see what the game actually looks like. Hang tight!

Monday, February 6, 2012

Winding Down on World 1

We're THIS close to finishing up world 1. Here's the pre-boss scene to tide you guys over









Commence boss fight!

Tuesday, January 31, 2012

New Backgrounds

Hey!

It's been a while since my last update, but rest assured we're working hard on getting this game out.

Here are the new backgrounds for World 1
The basic idea is that he's running towards the city

So, with each level it gets a little closer

Almost there!

Be sure to check them out in-game in the latest version.

Sunday, January 29, 2012

Enemies

I haven't posted about game mechanics in a bit, so I guess I'll talk about how I implemented enemies! This will also contain a modification I made to my asset system, as well as another one that I would like to make in the future. So here we go!

An instance of the Enemy class is created for almost everything in the game that has the potential to kill the player. The exceptions to this are doors and light gates (implemented with another class called Static) and the spikes that line the edges of some levels.

Now in order to create a single Enemy class that can represent any type of enemy, I had to use a lot of switch statements. For the non programmers out there, a switch statement lets you define several different cases and execute a different block of code depending on which case fits. For my purposes, I could check which type of enemy a particular instance of the Enemy class is and make sure it behaves correctly.


//Conditional x collision depending on enemy type
    if(type==SLIME){
     if(assets.getBg().checkCollisionX(collision, yPos) || assets.getBg().checkGap(collision, yPos+spriteHeight)){
      collided=true;
     }
    }else if(type==STINGER){
     if(assets.getBg().checkCollisionX(collision, yPos) || assets.getBg().checkCollisionX(collision, yPos+spriteHeight-assets.getBg().tileSize) || (xPos<=xBoundL && xSpeed<0) || (xPos>=xBoundR&&xSpeed>0)){
      collided=true;
     }
I again use a switch statement to define different hitboxes depending on the type of enemy
public Rect getLoc(){
  if(type==STINGER){
   return new Rect(xPos+40,yPos+40,xPos+spriteWidth-20,yPos+spriteHeight-25);
  }else if(type==LIGHT_TRAP){
   return new Rect(xPos,yPos+15,xPos+spriteWidth,yPos+spriteHeight);
  }else{
   return new Rect(xPos,yPos,xPos+spriteWidth,yPos+spriteHeight);
  }
 }


This setup makes it very simple for me to add new enemies in. I simply need to add cases defining it's hitbox and movement pattern and I'm set!

Another consideration I  needed to make was how I manage the bitmaps containing spritesheets for these enemies. My original implementation had all of the enemy sprite sheets aliased correctly such that each sheet was loaded once per type of enemy. However, whenever an enemy switched directions or was flipped from on to off, the change was handled within the enemy class. This meant that eventually, every enemy instance would have it's own sprite sheet. Terribly inefficient, and unavoidable as long as sprite sheet changes are handled by the enemy itself.

To fix this, I modified my Assets structure (yet again) to contain a bitmap manager for the Enemy class. A data structure was built that stores two sprite sheets per enemy type, labeled by the enemy's type name. The reason I stored two per enemy is that if we have some slimes facing left and some facing right, they can't be read off of the same sheet! Whenever an Enemy is created, it checks the data structure to see if it's bitmaps are loaded in and loads them if needed. When a switch is flipped, the two bitmaps for that enemy are overwritten with the new versions. This way, I can have 2 slimes or 200 slimes in a level with virtually the same memory footprint!

In the future, I'd like to move ALL bitmap allocations into the Assets class. Right now the Player sets up its own bitmaps, the Background sets up a bitmap, etc. A much more elegant and less bug-prone setup would be for the Assets instance created for a level to have a single data structure with all of the bitmaps used for the level. It can then pass every single asset a reference to it's bitmaps, and requires much less work when I want to clean out all of the bitmaps before loading a new level.

Saturday, January 28, 2012

VERSION 0.1 UPDATE

Hey!

So, apparently the game didn't work on phones with different screen sizes...

We fixed that!

It also works on Tablets now!

Download Off-Switch V0.1

Instructions:
  1. Download Offswitch.apk
  2. Email the file to whichever email you have linked to your phone
  3. Open the email on your phone, click install (May have to confirm that you want to allow untrusted apps)
  4. Enjoy!

Feel free to post any suggestions/critiques/bug reports either as comments on this post or emailed to martywalkeranimation@gmail.com (Art/level design) or cjalbert@umd.edu (programming/bugs).

Known Issues

  • Standing inside/slightly under the thin platforms
  • Light gates misbehave a bit when turned off and back on
  • Shadow's head may pass through blocks when hit from the side
FAQ

1. Q: Why won't this run on my device? 
    A: If it doesn't install at all, it's possible that your phone is running on an older version of Android. To make multitouch work correctly, the app supports Android 2.2 and later. 

2. Q: Why can't I save my game?
    A: Saved games aren't in yet.. However, if you hit your phones menu button, there's a skip level button to help you get back to where you left off. No cheating!

3. Q: Can I play on my PC?
    A: Unfortunately, no. The only way to run android apps on a PC is with the AVD Emulator, which is build into the SDK and more for debugging than anything. It lags TERRIBLY.

4. Q: Are you going to make an iPhone version?
    A: Short answer: No. Long answer.. The Android API is built on java, and the iOS API uses Objective C. This means essentially rewriting all of my code. On top of that, my understanding is that Apple charges a 100 dollar developer license fee to write apps, along with requiring the programmer to have an iMac and an iOS device for testing. Finally, apps can't be installed on phones unless approved by Apple, so I wouldn't be able to send you a development version anyways!

Friday, January 27, 2012

Alpha demo now available!

With great excitement and mild exhaustion, I'm happy to announce that we now have an alpha version of Off-Switch available to play! This demo contains all of world one except for the boss fight. So download it, find bugs, show it off to your friends, and have a merry time!

Download Off-Switch V0.1

Instructions:
  1. Download Offswitch.apk
  2. Email the file to whichever email you have linked to your phone
  3. Open the email on your phone, click install (May have to confirm that you want to allow untrusted apps)
  4. Enjoy!

Feel free to post any suggestions/critiques/bug reports either as comments on this post or emailed to martywalkeranimation@gmail.com (Art/level design) or cjalbert@umd.edu (programming/bugs).

Known Issues

  • Standing inside/slightly under the thin platforms
  • Light gates misbehave a bit when turned off and back on
  • Shadow's head may pass through blocks when hit from the side
FAQ

1. Q: Why won't this run on my device?
    A: If it doesn't install at all, it's possible that your phone is running on an older version of Android. To make multitouch work correctly, the app supports Android 2.2 and later. On the other hand, if you play on a tablet or phone with a screen larger than 480x800, there's a scaling issue that I'm working on fixing. Hold tight!

2. Q: Why can't I save my game?
    A: Saved games aren't in yet.. However, if you hit your phones menu button, there's a skip level button to help you get back to where you left off. No cheating!

3. Q: Can I play on my PC?
    A: Unfortunately, no. The only way to run android apps on a PC is with the AVD Emulator, which is build into the SDK and more for debugging than anything. It lags TERRIBLY.

4. Q: Are you going to make an iPhone version?
    A: Short answer: No. Long answer.. The Android API is built on java, and the iOS API uses Objective C. This means essentially rewriting all of my code. On top of that, my understanding is that Apple charges a 100 dollar developer license fee to write apps, along with requiring the programmer to have an iMac and an iOS device for testing. Finally, apps can't be installed on phones unless approved by Apple, so I wouldn't be able to send you a development version anyways!


Wednesday, January 25, 2012

Act 1, Scene 1

We'll be releasing a demo of world 1 in by the end of the week, so I wanted to do at least the intro cut-scene done first.

I've changed the story a bit from what I had originally envisioned. Originally it was going to be this big story where Silhouette (Shadow Jones' girlfriend for those new to the blog) gets possessed along with all of the other creatures, so Jones chases after her and spends the whole game trying to snap her out of it - fighting the bosses whenever they got in his way.

 I made this cut-scene as a stand-in for the first demo, but I think I'm going to go with it. The first story is big and kinda cool, but at the end of the day it's a generic "save the princess" story.

Plus this one's funnier


...and people don't have to tap through 20 panels of story to get to the game.

We'll see where we end up.

Sunday, January 22, 2012

Progress 1/23/2012

So I noticed that while we have many informative posts describing different elements of the game, there's really no indication of how far along things currently are. So I figured I'd give a quick update on the current state of Offswitch, along with some stats.

As of now, all of the framework is in place for a simple platformer. The tiling system is in place, so levels of any size can be quickly created and loaded into the game. There are currently 3 enemies (light traps, slimes, and stingers), one player type (default), and 2 statics (doors and levers). Levers are functional, flipping enemies from their light state to their shadow state. Enemies are also killable, though no transformations exist in game yet.

The things I'm working on now (in order of priority):
  • Stinger transformation (allows player to fly, but removes ability to flip levers)
  • Parallax gradients (Gradient in background moves with player, but at a different speed relative to the level)
  • Pause/resume states (Currently, player will restart at beginning of level if app loses focus)
  • Slight bug fixes
Also, we will soon be talking about how to implement boss fights. We are hoping to have a demo available once world one (levels 1-1 to 1-3 and boss fight) is completed. The demo should feature the flying transformation and near-final versions of all world 1 levels.

Now for some fun stats!
  • Assets: 83 (levels, sprite sheets, etc.)
  • Assets in game: 34 images, 3 level files
  • Classes: 12
  • Lines of code: 3,272
  • Project size:  4.25 MB
  • Application size: 1.05 MB
  • Revisions: ~350
  • Number of times the word "Offswitch" appears in source code: 85
  • Start date: Dec 23, 2011 (1 month old today!)
  • Most revised class: Player.java (Collision is hard!)

Levels

This is kind of a fun one to talk about. The level system is the subject of the single largest and most complicated overhaul I had to make in the course of this project! It was a tedious and terrifying process, but the results are awesome. I'll start with the old system.

In our original level system, the Background object mentioned in a previous post held a Bitmap. This Bitmap was essentially the entire level. Here's what one looks like
As a fun aside, here's the image Marty would give me to place the enemies and such.

The player and enemies would actually refer to this bitmap in memory, looking up pixel positions to see if they were black. This is how collision was managed, and it wasn't a very good way for a few reasons. First off, we were limited to black platforms/walls/etc and nothing else that was a part of the background layer could be black. However, it lead to a MUCH more significant issue. Memory management.

Alright, this is going to require a hardcore digression so skip this paragraph if you aren't interested in how memory is managed. Image files on a computer can be saved in several formats: GIF, JPEG, BMP, etc. However, this file extension only refers to how the image is compressed to store on a hard drive. While actually working with the picture (viewing it or manipulating it, for example), it is expanded and stored in RAM, which I'll refer to as memory here. The images size in memory has nothing to do with what format it's saved as; in fact, it's pretty simple to figure out it's size. Multiply the number of pixels by the bit depth (typically 32) and divide it by 8 bits in a byte to get the number of bytes. One megabyte is a million bytes (sort of), so the rather small level depicted above is 1600*1966 pixels, or about 12.5 MB. On Android, these images are stored in an area of memory called the native heap which is as small as 24MB on some devices and has no problem crashing your app if you try to go past that. Since I'm also loading player sprites, enemies, and all sorts of other fun images, this level crashed phones.

So I made a new system, that didn't suck. In the new system, I used tiles. Each tile is loaded only once, and a level file is loaded in that is used to create a massive data structure describing what kind of tile goes where. We only needed to load around 20 or 30 different 32x32 pixel tiles into memory, and we could create massive levels! This was stress tested with a 200x200 tile level, which ran perfectly but was absolutely miserable to navigate (thanks Alex Mateik..) In this fancy new system, levels are made like this.


Marty loads in a tile set, creates a level, and sends me the tile set and .tmx file produced. The level is parsed out using a nice little chunk of code called TMXLoader (Thanks David Iserovich) and I create a bitmap of what the player can currently see. The bitmap is constantly recreated, and all of our memory issues are solved!

Collision is also a bit easier in this system. Rather than checking pixels, I can look up what tile the player is entering and decide if it is a collision tile or not. To determine what tile number each type of tile is, I open up the .tmx file in a text editor and I am greeted by something like this.
Slightly eye-melting, I admit. However, squint your eyes and you should see a level amidst these numbers! 0 is a transparent tile (or lack of tile), 1 is a solid block, 2 is a platform, and all of the other numbers are pieces of the curved cliff edges. With this, I can decide what tiles should cause the player to react in what ways, and keep the player from randomly falling through floors! Well..sometimes.

Saturday, January 21, 2012

Polishing the Transform Animation

I spent a lot of today finishing up that transform animation. It gave me more trouble than a lot of the others because I had started the first pass straight ahead on 1's, 2's and 4's without much of a plan. The result I got was basically good, but needed a lot of polish

Here's what I had started with:
It's not the worst thing in the world, but there are parts that could be clarified. The idea of the transform was that his arms would pop into wings and pull him up. As a friend pointed out to me, it really isn't clear that his arms are what's changing. It almost just looks like wings are popping out of his back.

The reason is that the initial antic pose for his arm was all scrunched up like so:
Which I think could have been kind of fun....if anyone could see it...

The fact that I followed that with a vague smear didn't help much.

Fixing it was a simple matter of making a bigger deal out of his arm before it changed
I made the arm pose a little cleaner and had it slow in to the anticipation so that it stays around that pose for an extra frame before popping off. I also replaced the vague smear with a clearer morphing pose.

Here it is animated:
The next real issue is that the spacing's a bit of a mess. Since I did a lot of it straight ahead I hadn't planned for proper slow ins and outs, so his bounce is a little mushy. I went over the whole thing and pushed his up and down extremes a little further, while cleaning up the overall arc a bit. 
The differences are subtle, but there. From there it was mostly clean-up.
I cleaned up the body and arms first as they're the main action. The legs are all follow through, and the face is largely secondary, so I threw them inside of symbols to be dealt with later.
Then I dealt with them.

...guess that's it...

'Till next time.

Friday, January 20, 2012

Transformations

One of the hardest things we've had to come up with from the design side is how the transformations are going to look. We've had a lot of cool ideas, but they had to be scrapped simply because there are too many variables to account for. We needed an animation that would work no matter what state the player/enemy sprites are in and no matter which direction they were facing.

 Here's the idea I think we'll end up going with:
When the player kills the enemy it'll swoop down and compress into a little ball that hovers over to the player.
Once it hits the player he transforms into his new state with his new abilities (unless it's a slime...those don't give him powers. It just hits him and disappears).

Here's the first pass at the roughs for his transformation. I'll fix a few things then clean it up tomorrow:
It's a nice, simple solution that separates both animations, and should help them transition smoothly from any state.

Thursday, January 19, 2012

Asset Management

In today's episode of offswitch development nonsense, I'm going to talk about the asset management system I made! Rather, I'm going to talk about the old system and how terrible it was before describing the new system and how much better it is! This post will have pictures instead of code, so that's exciting.

When I say asset, I'm referring to elements of the game: backgrounds/gradients, buttons, enemies, statics (doors, levers, etc), and the player. Just to clarify, background and gradient are kind of misleading names.. the gradient object I refer to is the scene painted behind the level, and the background object is the platforms and walls of the actual level. I should REALLY get around to renaming those things before I get called out on it.

So I'll explain the old system. For fellow java programmers out there, I created an Asset object with some generic methods/variables, then made all six of the game objects I listed extend Asset. My "Asset Management System" was just an Asset array. Since all of the different things extended Asset, I could throw them all into the array. In English, this is the equivalent to dumping everything into a large box. Whenever I needed to access an objects, I had to go digging through the box and check what each thing was. And just about everything in the box needed to access just about everything else in the box. If the player needed to access the background to check for collision, It had to search through the box to find the background and then check the pixel needed. This led to a lot of weird dependencies and channels of communication between all of the different objects. I drew a picture, both to illustrate the unnecessary complexity of this system and to demonstrate why Marty is doing ALL of the drawings.


It doesn't take a programmer to tell that this system redefines terrible. So I decided to rip it all out and redesign it!

The new system creates an Asset object, which is a custom data structure containing all of the individual objects and a few methods for them to interact. Each object is given a handle to the Asset object, so if they need to talk to each other they can trace up to the Asset and access the object they need. This is both entirely more efficient and WAY easier to understand, as the following picture demonstrates.


Way better, right?

Silhouette

Here are some concepts for Shadow Jones' girlfriend Silhouette. She gets possessed along with the other creatures when the light demons attack, which is what drives Jones to take action in the first place. He spends the whole game chasing after her and trying to snap her out of it.


She's been the easiest of any character to design so far. I figured out the look I wanted pretty quick, I just need to lock down the a bit before doing any in-game drawings.

That's it for now. I'm off to work some more.

Wednesday, January 18, 2012

So, How's the Game Work?

Ah, day 3 of the production blog. I suppose it's time to explain how the game actually works.

The basic premise is "Light Demons have invaded Shadowland and possessed all of the creatures. It's up to you to stop them!" (I'll go more into the story once I get the cut-scenes drawn out for you.)

It's sort of your basic platformer. All the enemies are these glowing light creatures:

(Well, in game they glow...the glow doesn't export well into an animated gif)

Somewhere in the level each enemy has a lightswitch. When you turn it off they become shadow versions of themselves
At which point they're harmless and you can merge with them to use their abilities to solve puzzles and get around obstacles. (You can only flip one switch at a time, though. Once you deactivate one, it reactivates all the others.)


For instance if you wanted to get to the ledge in the upper left:

You'd kill the little flying dude, and fly up there.

That's an easy example...

Eventually it'd get a bit harder...you'd have to dodge spikes and stuff...

Should be fun...

Here's hoping

Tuesday, January 17, 2012

Controls

To start things off from the programming side, I'm going to post some of my favorite code: the controls! Implementing good, functional multi-touch controls was harder than I had anticipated, as there are a lot of things we take for granted when playing video games. For example, what happens if I slide my finger off of the button before lifting it from the screen? How about if I slide my finger from the right button to the left? I'll talk about how I dealt with some of these cases, but first let me show you the code!
 @SuppressWarnings("unchecked")
 public boolean onTouchEvent(MotionEvent event){
  //Binds the key to a hashmap so we can watch for it to lift, then proceed to call doKeyUp/Down

  int actionCode = event.getActionMasked();
  switch (actionCode){
  case(MotionEvent.ACTION_DOWN):
  case(MotionEvent.ACTION_POINTER_DOWN):
   if(event.getPointerCount()==4){
    mAssets.getPlayer().invincible=!mAssets.getPlayer().invincible;
   }
  if(thread.getCurrentState()==STATE_PAUSE){
   thread.unpause();
   return true;
  }else if(thread.getCurrentState()==STATE_WIN){
   level=0;
   thread.doStart();
  }else if(thread.getCurrentState()!=STATE_RUNNING && level==0){
   level=1;
   thread.doStart();
  }


  for(int i = 0; i < event.getPointerCount(); i++){
   if( event.getActionIndex()!=i){
    //This pointer has not gone down, or the button is already bound to something
   }else if (event.getX(i)>10 && event.getX(i)<100 && event.getY(i)>380 && event.getY(i)<470 && mPointers.containsValue(Button.BUTTON_LEFT)==false) {
    //Left button
    mPointers.put(event.getPointerId(i),Button.BUTTON_LEFT);
    onKeyDown(Button.BUTTON_LEFT);

    //Right button
   } else if (event.getX(i)>110 && event.getX(i)<200 && event.getY(i)>380 && event.getY(i)<470&& mPointers.containsValue(Button.BUTTON_RIGHT)==false) {
    mPointers.put(event.getPointerId(i),Button.BUTTON_RIGHT);
    onKeyDown(Button.BUTTON_RIGHT);

    //A button
   } else if (event.getX(i)>600 && event.getX(i)<690 && event.getY(i)>380 && event.getY(i)<470&& mPointers.containsValue(Button.BUTTON_A)==false) {
    mPointers.put(event.getPointerId(i),Button.BUTTON_A);
    onKeyDown(Button.BUTTON_A);

    //B button
   } else if (event.getX(i)>700 && event.getX(i)<790 && event.getY(i)>380 && event.getY(i)<470&& mPointers.containsValue(Button.BUTTON_B)==false) {
    mPointers.put(event.getPointerId(i),Button.BUTTON_B);
    onKeyDown(Button.BUTTON_B);
   }
  }

  break;
  case (MotionEvent.ACTION_UP):
  case (MotionEvent.ACTION_POINTER_UP):

   for(int i = 0; i < event.getPointerCount(); i++){
    if(event.getActionIndex()==i && mPointers.containsKey(event.getPointerId(i))){
     onKeyUp((Integer)mPointers.get(event.getPointerId(i)));
     mPointers.remove(event.getPointerId(i));
    }
   }
  break;
  
  case (MotionEvent.ACTION_MOVE):
   for(int i=0;i110 && event.getX(i)<200 && event.getY(i)>380 && event.getY(i)<470 && mPointers.containsValue(Button.BUTTON_RIGHT)==false){
      onKeyUp(Button.BUTTON_LEFT);
      mPointers.remove(event.getPointerId(i));
      mPointers.put(event.getPointerId(i),Button.BUTTON_RIGHT);
      onKeyDown(Button.BUTTON_RIGHT);
     }else if((Integer)mPointers.get(event.getPointerId(i))==Button.BUTTON_RIGHT && event.getX(i)>10 && event.getX(i)<100 && event.getY(i)>380 && event.getY(i)<470 && mPointers.containsValue(Button.BUTTON_LEFT)==false){
      onKeyUp(Button.BUTTON_RIGHT);
      mPointers.remove(event.getPointerId(i));
      mPointers.put(event.getPointerId(i),Button.BUTTON_LEFT);
      onKeyDown(Button.BUTTON_LEFT);
     }
    }
   }
  break;

  }

  return true;
 }
A lot to process, I know. I'll explain some of the more interesting parts for you. First off, button binding!

When implementing game controls, the natural first thought is to set a button to "pressed" when you put your finger on it and "unpressed" when you lift your finger. However, this leaves one major problem. If your finger is not on the button still when you lift it, it won't be lifted! An additional problem I ran into was that it's easy to get your fingers mixed up when programming multi-touch. If you aren't careful, lifting your left thumb may cause the button under your right thumb to lift.. which I claimed made the game more interesting, but was shot down in the end.

I fixed both of these problems with one Hashmap, a fairly basic java structure that stores data using a key in the same way the post office uses your address to determine which house to bring your mail to. So after the first bit of code with all the STATE garbage (all that does is start the game if it isn't started when I touch anywhere on screen), I have a nicely labeled block of code for every button that checks to see if the finger went down on top of one of the buttons. If so, it binds the pointer ID of that finger (guaranteed not to change, where the pointer INDEX can change whenever it feels like it) to the button it is pressing. This way, when the finger is lifted I don't even have to care where it is at the time. I just look up what button it was bound to, lift the button, and unbind it. Fun, right?

The next bit of code worth talking about is the block under ACTION_MOVE, which is what I call the d-pad sliding code. You may not think about it, but gamers typically slide their thumb between the left and right buttons of the d-pad on a controller to quickly switch directions. Initially my code required the player to lift their thumb from the left button before pressing right and vice-versa, which felt a bit clunky. To fix that, I check if a finger that is bound to the left button hovers over the right button or if a finger bound to right hovers over left, and unbind/rebind the finger appropriately. This small addition makes a HUGE difference to gameplay.

Finally, you might be wondering what happens when I call that doKeyDown thing. What I'm doing there is sending a signal to the actual game thread, which then does two things. The first thing it does is talk to the Button class, telling it to redraw the button as a depressed button (slightly greyed out version) to give the player some feedback that their button press was received. The second thing it does is update a variable in the Player class telling the player that the button is pressed. I've considered moving this variable outside of the Player, but it seems to be fine there for now since the player is the only thing that has to read in a button press and respond to it.

Anyways, this was a bit lengthy but I hope it offers some insight into what it takes to develop controls for a touch screen game. Next time I'll talk about something more headache inducing, like collision!

Designing Shadow Jones

So, I guess I'll start off with the development of the main character, Shadow Jones, the Shadow from Shadowland.

Funny enough, he started out as a magician:
It was an idea for a short film I had a couple years ago about a sort of magic duel between a magician and a sorcerer. Not the greatest idea in the world, but I wanted it to be in a cool, silhouettey style.

Anyway, eventually I canned it in favor of what became The Mighty Hunter

After TMH I was back to trying to find an idea for my next short and started doodling that magician again.

If you look across those pages from right to left you can almost see him change from the magician to the shadow. I eventually simplified his slicked back hair into just that little swoosh in the back, and dropped the sleeves and pants in favor of simple arms and legs.


Eventually it became a story about a little shadow who's wandering around one day when he finds a little glowing light bulb. He reaches out to touch it and the light burns his hand off. Once the light bulb has a taste for shadow flesh it starts chasing him around and stuff. Then the shadow...

dies...

or something...

I never really worked out the story 100%...



It was becoming little more than an extended chase scene, so I was about to scrap it. Then I figured it'd make a cool game, so I suggested it to Cody.

Now that's what it is...

Here are some sprites of him in a couple of the forms he takes in the game:


PhotobucketPhotobucketPhotobucket