Friday, September 18, 2015

Safe Places to Respawn

Though Eruptoid is MonkeyBall-Like, it isn't a full clone.  My game design is being informed by a number of other games such as the NES classic Marble Madness.  What I liked about Marble Madness is how it handled death.

  • In Super Monkey Ball 1, you had a number of lives and every time you fell off the level, you'd lose one.  When you ran out, it was game over.
  • In Super Monkey Ball 2, you had unlimited lives, but every time you fell off the level, you'd start the level over completely.  Timer reset and you would spawn at the start place.
  • In Marble Madness, there were no lives.  The only opponent was the stage and the clock.  So when you fell off the level, you would respawn at the most recent safe place and the clock kept running.  These places were hard coded per level, and you'd spawn at the nearest one.
I'm going the Marble Madness route with a difference.  I'm not hard coding in my respawn locations.  Every certain number of seconds, I check the balls velocity in the Y direction (that's up and down) to determine if the ball is falling or not.  If the ball is not falling, then I set the respawn point to that location.  Under the level is an invisible plane that, when hit by the player, will trigger the game to pick the ball up and drop it back at the respawn point.  Simple yet effective.

Except it doesn't work if you have moving platforms, like my most recent level does.  While the ball is on the moving platform, its Y velocity is zero, so respawn points get saved.  That's fine until the player falls off, the game picks them up and drops them back at the respawn point, only to find that the platform has moved on and the player falls again into the respawn plane, infinitely respawing to a place with no ground below it until the platform comes back.  For this particular level, the platform reciprocates slowly, so this isn't the end of the world, but it severely limits my level design opportunities, so I decided to fix it.

My first thought was to check for ground under the last respawn point, and if there was no ground, then we'd respawn at the level start location.  This solved the problem, but still severely limited my level design.  Its fine for short levels, but if I have a long level where the player falls off a moving platform near the end of the level, they'd go all the way back to the beginning, with not nearly enough time to complete the level again.  This would effectively give the player a game over, and would be frustrating if it happened repeatedly.

So instead, I created a list of respawn points.  As above, every few seconds I check for falling, but instead of replacing a variable with safe locations, I add the safe locations to the end of a C# list.  Then, when the player hits the respawn plane after falling off the level, I iterate through that list backwards until I get to a spawn point that is over ground, and then respawn the player there.

And it only really took adding about 5 lines of code to make it happen.

Other things I did today was set a speed limit for the player.  I'm not sure how well that's going to work out, but I feel like it's necessary.  Of course I gave myself the option of whether to enforce the speed limit or not under certain conditions.

I also fixed another issue with the above moving platform.  As far as I can tell, there's no "friction" in Unity.  Friction is simulated with the drag parameter on a rigidbody.  What this means is that when my ball was on my moving platform, the platform wasn't moving the ball with the platform.  The platform would move right out from under the ball, and the player would fall into the afore mentioned respawn plane, and respawn in the same place they were before, sans platform.  Since my platform moves using an animation, instead of the physics system, I had to calculate its velocity myself.  Once I had the platforms velocity in world space, I could apply that velocity as an added force on the ball when the ball contacted the platform.

Best part is, the way I wrote the script means I can put it on ANY moving object and they will effect not just the player, but any other physics body that I want it to effect.

Overall, it was a good weekend for development.