When I sit down to write some new code, I am always trying to break the problem down into some manageable chunks. I try to divide them into a couple of categories:
- How will I store my data
- How will I get input from the user
- How will I show output to the user
Once I have some ideas about these, I put them into two big buckets:
- Stuff I know (or think I know) how to do
- Stuff I don’t know how to do yet
Since this blog is aimed at making you a better coder, an example of how this was applied recently is in order.
There’s a game I’ve been wanting to write ever since I played a Flash version of it many years ago. The original was called Spaced Penguin, and had a related game called Doom Funnel Chasers. Played in space, you had to get Kevin (the spaced penguin) from one side of the game board to hit a target on the other side. The complication was that the game board had a number of planets in the way, which exerted gravity on Kevin. You had to pick the right trajectory and speed to loop Kevin around them and hit the target. Crash into a planet, and Kevin had to start the level over.
I knew could represent Kevin’s speed and direction using vectors. These are are nothing more complicated than two numbers, like coordinates on a graph. Kevin’s current position is one vector, and it’s speed and direction of travel are a second. If I add them together, I get a new position. Change the speed and direction vector, and the position will change as well.
Which led me to my first big unknown: how do I change Kevin’s speed and direction based on the gravity of the planets on the screen? Off to the library I went, and after over-complicating things hopelessly, I finally figured out that simply applying Newton’s equations for gravity would work just fine. Every frame of the game, I figure out the change to Kevin’s acceleration from all the planets on the screen, then calculate the new position.
But where does that initial speed and direction vector come from? That one took me too much time, considering what the solution really is. In the game, Kevin starts in a slingshot. Pull back on the player, and they stretch a rubber band which, when you let go, propels them forward. The amount you pull back and the direction Kevin is pointing determines it’s speed and direction. Knowing the point where Kevin started and the point at which the player let go, I subtract the two to get a speed and direction vector.
Of course, there’s always the chance that Kevin achieves escape velocity for the system, and will never return. How do I detect that? The easiest way is to set a boundary beyond which we assume Kevin is lost. It should be bigger than the screen size, so Kevin can loop around planets near the edges of the screen, but not too big. I could also calculate his distance from the nearest on-screen object, and when it gets too large, declare him lost. The first way is quicker, but the second allows the player a bit more flexibility.
Now, how do you keep score? In the original game, Kevin got points for the distance he traveled, divided by the number of attempts it took. The longer the trip, the better, but if you crashed or restarted, the score would go down. Calculating the distance can be done every frame, by simply calculating the distance between the last position and the next one and adding it to the score. Vectors FTW!
Of course, this all leads to the last problem, on which I am still working: level design. How do I know Kevin can actually reach the target, given the planet setup for each level? How do I ensure each level is solvable? I haven’t figured that one out yet, but I think I’ve got a way to verify that a level is solvable, and if so calculate the max score. I can write code which will set Kevin on every possible trajectory through the system, and calculate whether he hits a planet, gets ejected, or finds the target on that trajectory. If Kevin can’t be pulled more than 100 pixels away from his starting point, I’ll have 4000 possible vectors to try for each level (100 pixels to each side of Kevin’s starting position defines a 200×200 pixel box, which gives me 4000 possible starting combinations). If I increase that to 15- pixels, then I’ll have 9000 vectors. Sure it’s a little brute force, but it only needs to be done when the level is ready.
I’ll have more on this as the blog continues, and I’ll have an update on the game once it gets closer to finished.