Tuesday, December 31, 2013

My GitHub Game-off 2013 Entry

This past November I participated in the GitHub Game-off 2013. Basically it was a month-long game jam where you created a game that could be played in a web browser on the theme of "change." When I first read about it, it was already November 6th so I was a little behind. But since I had some experience with creating HTML5 games using JavaScript and Canvas I thought I'd give it a try.

The theme was "change" which made me immediately think of frogs. In fact, almost everything makes me immediately think of frogs. I decided to make a game about the life-cycle of frogs. Starting as a tadpole, you have to grab food and avoid being eaten by fish. Other tadpoles are also out to get you. It's a hard life for tadpoles. So in my game, you move your tadpole around in a pond trying to catch falling food and grow into a tadpole with legs, a froglet, and finally a full-grown frog. Once you are a frog you leave the pond, but you have to return to complete the cycle. The game completely changes (see, the "change" thing again) when you are a frog and now it's about jumping back in the water and catching bugs.

I drew some tadpoles and fish and plants and stuff, and found some great music from Incompetech and sound effects on Freesound.org. I can't say enough good things about Kevin MacLeod of Incompetech. The library of extremely high-quality music that he offers royalty-free is just awesome. And his graph paper is pretty cool too.


But what about the code? What did I do? How did I throw something together so fast?

For starters, I didn't use any game development systems. I know some that are very popular and allow you to publish your game as HTML5 and for iOS and Android and a whole bunch of other stuff, but I don't know how to use them. I admit it. I'm not a professional game developer. It's more of a hobby. I am a professional software engineer, and I do know how to write decent JavaScript so I just went with what I knew. I also kept it simple. When the game is simple, the code is simple, and doesn't require a lot of overhead from tools. Here's a quick overview of the basics. You can probably use the outline to make some simple HTML5 games yourself.

There are two absolutely essential packages for making HTML5 games: jQuery and SoundManager2. Well, jQuery might be essential for any type of web development these days. But games aren't much fun without sound and SoundManager2 is the library when you want to do sound from JavaScript. Stop what you're doing, download it, learn it, and love it. Right now.

That being said, making a simple game on an HTML5 canvas element is probably easier than you thought. To begin, create a web page with a canvas element.

<!DOCTYPE html>
<html>
  <head>
    <title>Game</title>
    <style>
     canvas { border: 1px solid #000000; } 
    </style>
  </head>
  <body>

    <div>
      <canvas id="game" width="800" height="450"></canvas>
    </div>
    
  </body>
</html>

You're halfway there! Okay, maybe not halfway. The next thing to do is set up some JavaScript to start working with the canvas. The basic outline of any game is to make a loop that updates the objects on the screen and draws them. In modern browsers, we have a nice utility for that - the window.requestAnimationFrame() function. This method has been added specifically for the purposes of doing animations on web pages, and it is the most efficient way of doing so. The following is a bare-bones version of a game. Note that you have to explicitly call requestAnimationFrame again after each call to your run function (or it will only run once!).

(function(window) {
 
 function Game() {
  
  this.lastTime = null;
  this.paused = false;

  this.canvas = null;
  this.ctx = null;
  
  this.setup = function(options) {
   
   this.canvas = options.canvas;
   this.ctx = this.canvas.getContext("2d");

   var me = this;
   window.requestAnimationFrame(function(e) { me.run(e); });

  };
  
  this.run = function(timestamp) {

   var elapsed;
   if (this.lastTime === null) this.lastTime = timestamp;
   elapsed = timestamp - this.lastTime;
   this.lastTime = timestamp;

   this.gameLoop(elapsed)
   
   var me = this;
   window.requestAnimationFrame(function(e) { me.run(e); });
   
  };
  
  this.gameLoop = function(elapsed) {
   
   // update all your objects here
   
   this.gameDraw();

  };
  
  this.gameDraw = function() {

   // clear your canvas   
   this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
   
   this.ctx.save();

   // draw all your objects here   
   
   this.ctx.restore();
   
  };

  
 } // Game()
 
 game = new Game();
 
 window.game = game;
 
}(window));

After saving this code (I saved it as "main.js") you can fire it up by adding the following scripts into your HTML file with the canvas element:

<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript">

    $(function() {

        game.setup({
         canvas: document.getElementById("game")
        });
        
    });
      
</script>

Now as soon as your page is loaded, your setup function is called. It is passed the canvas element and starts looping and drawing. To complete your game, just add some objects to be moved around and drawn!

If you'd like to see my completed code, it's here on GitHub: cwleonard / game-off-2013.

If you'd like to play the completed game, you can find it here: The Frog Lifecycle Game.

Leave a comment below with your scores! A really good time for becoming a frog is about 135 seconds.

Friday, August 23, 2013

We're Kickstartering

Great news! My wife's company, Syslark, Inc., has decided to use Kickstarter to raise the funds to take my FFZ game from amusing prototype to finished game on the OUYA!

She's participating in OUYA's Free the Games Fund, which provides matching funds for games that will be OUYA exclusives for 6 months after launch.



So everyone please have a look and back her if you like what you see.


Monday, August 5, 2013

The Science of Fun

Let's Do Science!

Well, let's at least consider why some games are fun and you want to play them more and more...while other games don't hold your attention for 3 minutes.

Two games that I really think get it right are Minecraft and The Amazing Frog. On the surface, these games have absolutely nothing in common. Punching trees to collect wood in one and throwing a rag-doll frog off the top of a parking garage in the other. So what makes them fun?

First, both are immediately playable. There's no complex story you have to sit through. In fact, I don't know that there's a story at all. There doesn't need to be. And there's no tutorial. You just start doing stuff. You pick it up as you go. You have nothing to lose, except your currently mundane existence in which you are not playing these games.

Second, both create environments of open-ended creativity. Obviously in Minecraft you can build yourself houses or roller-coasters or chicken farms or whatever you want. You can play with friends - one of you digging in holes while the other rigs traps for zombies. Or not. You can really do whatever you want. There are no rules. But The Amazing Frog is not all that different. Okay, so it's more about blowing up cars in Swindon than it is about building things, but there aren't really a lot of rules. You get points for falling, but you don't have to care about that. My kids have also turned the game into hide-and-seek, soccer (well maybe football since it's British), and capture the flag (or crown in this case). Sometimes they just bounce in the bounce house. For like 37 minutes! And there's always something unknown on the horizon. None of us have been able to get in that cargo container hanging from the blimp yet, but it fills our imaginations with ways to maybe get there - all of which end with us blowing something up instead. What's up with that crown anyway?

Third, and this one is maybe odd, but neither game is finished. Huh? Really. Minecraft updates all the time. Do you remember how exciting it was to get carrots on fishing poles so you could finally steer pigs? You'd had pigs to ride for months, and that was fun, but now you can steer them! It's like you just got a whole new game! My daughter gets really excited when Minecraft PE updates on her iPod. New stuff! Even if she's already had that stuff in the PC version, it's still exciting. It's like when you were a kid and you loved checking the mailbox every day...some days you would get something and it would be great! Other days you would get nothing but it just made you more excited about the possibility of getting something tomorrow. These "unfinished" games give you the same feelings. Maybe "unfinished" isn't the right word. Maybe the games are complete in their state of constant change. I can't wait to see the next iteration of Amazing Frog...and if you follow Fayju on Twitter you get to see little hints of things to come that make you even more anxious. Will we get a few more stages? New outfits for the frogs? New things to grab and throw? Or whole new game mechanics? No matter what, I'm sure it will be great - and it keeps players coming back for more.

So now I will summarize.

  1. Stories. Keep them short.
  2. Rules. Keep them few.
  3. Updates. Keep them coming.
And that is how you make a great game. In theory, anyway. If we're going to be scientific about it we have to test this theory by making games according to these rules and see if they become awesome.



Thursday, July 4, 2013

Facebookified and Zyngaficated

I've decided that to truly succeed as a game developer I have to change the way I design things. I have to design for revenue. I have to put revenue before gameplay. Here's my plan...

  1. Limit how long people can play. I know this sound crazy, but just wait. I'll limit my players to 20 minutes of play and then make them wait an hour to play for another 20 minutes - UNLESS they give me another dollar. Then I'll let them play as much as they want, but only for 24 hours. Tomorrow they'll have to give me another dollar.
  2. Start out easy, then make it impossible. Will people quit playing when it gets too difficult? No, they'll already have too much of an emotional investment in the game to walk away. They'll just have to buy a power-up that will enable them to continue. It will cost another $1. Then after that really hard level it will get easier for a little while, you know, to get them back into it before I throw in another impossible level and charge another dollar.
  3. Make you bring friends if you want to keep playing. At first you can play by yourself and multiplayer will be optional. But after a certain point, you have to play with other people if you want to continue. Something in the level won't be possible without a second player. And that second player has to buy the game too! She might not want to at first, but you'll keep twisting her arm until she does. And she will because you're friends. Then BAM! I start getting dollars here and there from her too. Brilliant!
Oh, wait. I forgot. I just want to make things that are fun. But this plan sounds strangely familiar. It sounds like the outline of every Zynga and/or Facebook game ever made.

Is this all the world has to offer? I get to choose between another pointless first-person shooter that costs me $70 up front, or an addictive puzzler that is designed to take my money one dollar at a time?

This is why I'm developing for OUYA.

Saturday, June 15, 2013

Hack It, then Refactor It

I've spent the last several days refactoring my OUYA game. It seems strange to spend so many hours working on the code and the great accomplishment is that it still works. I just felt the need to explain why I do this and how it works for me.

I believe that I am a very results-oriented person. Not to say that the ends always justify the means, but I recognized many years ago that getting a product working is much more important that making sure that all the T's are dotted and the I's are crossed. I've also been known to get forgiveness instead of permission on many occasions.

You can be writing the most elegant, perfect, optimized code in all the world but if no one ever sees or uses the product then what have you really accomplished? This is true for everything, not just software products. Once (1998) I decided to replace the stock 3.8L V6 engine in my 1989 Mercury Cougar with a 5.8L small-block V8. I had 3 months until I needed the car to run again so I could go back to college. As far as we could tell, this feat of automotive engineering had never before been accomplished. The engine did not physically fit in the car. But I wasn't building it to put on display, so we hacked and bent and cut and torched and pounded with a hammer. It wasn't pretty, but it ran. I drove it back to college and almost every day while I was there. I also spent the next 3 years fine-tuning it. Parts were replaced with new ones as they were fabricated. The more powerful engine totally blew out the rest of the drive-train in time, but that got fixed as well. I could have spent those 3 years making it perfect before it ever left the garage, but it was much better to be driving it all that time.

Basically, I learned that success means shipping a product. So how does this relate to hacking and refactoring software? It's pretty much the same thing.

I wanted to get stuff on the screen of the OUYA and get things moving around with the controller as quickly as I could. I needed to see it working, even if the code was less than perfect. I needed to see those results so that I could continue. Letting it "sit in the garage" for too long would just discourage me and I would lose interest.

However, I know better than to leave the code that way for too long. If I am going to build a complete game, my code has to be structured such that it can be built on. It can't be brittle. It has to use the proper design patterns. So every few weeks, I stop adding new features and refactor. I clean up the ugly code and make sure I have a solid foundation before building more. But in the mean time I also have something that my kids and I can play (You don't have to release your product to everyone to count it as a release. My Cougar only had one user, after all).

It's just what works for me. And it works for other people as well. Check out the works of Kent Beck and Martin Fowler. They've written lots of stuff on design patterns and refactoring code.

Also, read this paper.

And as for my Cougar, I no longer drive it but it taught me a lot about successful engineering projects.

Friday, March 22, 2013

Virtual D-Pad Killed by Geometry

I hate virtual D-pads in mobile games. The D-pad was great on my Nintendo Entertainment System, but trying to play Mega Man II on my iPhone with the standard touch-screen replacement for tactile control made me regret spending $2.99 on the game. With nothing to stop my thumb from sliding right off the control zone, Mega Man plunged needlessly to his death so many times. So many times. Oh, the humanity! Well, in this case, the android...ity? Androidity? Is that a word? Feel free to substitute another word in your head when you read this. A word that you would use to express anguish over the massacre of heroic humanoid robots.

So let's just say I hate virtual D-pads. In the Android version of my FFZ game, I was not about to use one. There are a few alternatives that people have come up with, but here I'm going to talk about my current favorite and how I implemented it. It just took a little geometry.

What I wanted was a system where I could swipe my finger anywhere on the screen, and then my frog would move in a similar way. I swipe down and to the right, the frog moves down and to the right by the same distance. I don't have to start my swipe on the frog, so I don't have to block anything on the screen that I don't want to. I basically just want to create a vector with my finger that is then applied to the frog.

Doing this seemed fairly simple. I would just need a class that could represent the line segment created by the finger swipe, and then create a parallel line segment for the frog to move along.

Formula for a Line


Remember back to high school geometry class. The standard equation for a line is
y = mx + b
where m is the slope and b is the y-intercept (where the line will cross the y-axis). Slope is really important in this case, since that's basically what I want to duplicate in a second line for the frog's movement. Remember, lines with the same slope are parallel.

How, then, does one calculate slope? If you have a line, take any two points on it. Let's represent these two points as (x1, y1) and (x2, y2). Subtract y2 from y1 and divide that by the value of x1 minus x2.
m = (y1 - y2) / (x1 - x2)
The two points I'll use are the positions of the start of the touch event and the end of the touch event. So here's what my FrogPath class looks like so far.

public class FrogPath {

  private float x1;
 private float x2;
 private float y1;
 private float y2;
 private float slope;
        private boolean vertical;
 
 public void setStart(float x, float y) {
  this.x1 = x;
  this.y1 = y;
 }
 
 public void setEnd(float x, float y) {
  
  this.x2 = x;
  this.y2 = y;
  this.calculateSlope();
  
 }
 
 private void calculateSlope() {
  if (x1 - x2 == 0) { // don't divide by 0! no!
   slope = 0;
                        vertical = true;
  } else {
   slope = (y1 - y2) / (x1 - x2);
                        vertical = false;
  }
 }

}

Note the special handling for lines that go straight up and down. If there was no change in the x values for the two points, you'll divide by zero if you're not careful to check for that. Instead, a vertical line is said to have no slope. The formula for a line with no slope looks a little different, it's just x = n. The y value can be anything, but x will always be the same and there's no y-intercept. It's a little different than a horizontal line, which has a slope of 0. You can use the standard formula for those types of lines, but the value for m is 0 which essentially eliminates x from the equation. You're left with just y = n where n is always equal to b, because the line will cross the y-axis at the same value as every other point on the line! Consider the horizontal line y = 2, for example. Anyway, the point is that we have to perform special handling for vertical lines but not horizontal ones.

Thanks to Garrett Bartley for the Virtual Graph Paper I used here! 

So in my Android app, when I get an ACTION_DOWN MotionEvent I create a new FrogPath object and set the start coordinates. I hold on to that object until I get an ACTION_UP event, at which time I set the end coordinates. The FrogPath object calculates the slope of the line. That was the easy part!

Can We Get There from Here?


Now I have a slope and I have the current coordinates of my frog. I calculate the distance I want the frog to move, based on his speed and how much time passes between animation frames. What now? To calculate his new position, I have to figure out new coordinates that are on a line with the calculated slope that passes through the current coordinates. These new coordinates have to be the calculated distance from the current coordinates. Sound easy? Let's look at the picture...


Here we can say that c represents the distance we want to move the frog along the line. We know where the frog is now. Your first thought might be to call on your old friend Pythagoras and do that whole a2 + b2 thing. Sorry, but Pythagoras can't help you here. There's just not enough information. We need to find both a and b, and we can't do that with just c. This is where it get's tricky. You need to look at the problem in a different way. What if instead of seeing a triangle, you see a circle?

We can figure out the next position of the frog using the formula for a circle and determining where a circle centered at the frog's current coordinates and with radius r will intersect with the line. You may not be as familiar with the formula for a circle as you were with the formula for a line, but here it is. If the coordinates for the center of the circle are represented as (c, d) and a point on the circle is represented as (x, y) and r is the radius, the standard form circle equation is
(x - c)2 + (y - d)2 = r2
It might look crazy, but if you think about it, we have enough information to solve the problem if we combine the equation of our line with the equation of our circle. We know c and d, because those are the current coordinates of the frog. We know r because that is the distance we want the frog to move. And we know y (in terms of x anyway) because the line formula is y = mx + b. We know m because that is the slope. We can find b because we have a point on the line (the frog's current coordinates) and the slope. That's everything. Just plug it all in and solve for x! If you factored it all out, you'd come up with an equation like this for x:
x = c ± r / √(1 + m2)
Now you might notice that plus/minus thing in there, and rightly so - if you look at the picture above it clearly shows that the circle intersects the line in two places. How do you know which x value you want? Simple. You go back to your original two points that you used to calculate the slope in the first place. If the x value for the end point is greater than the x value for the start point, do a plus in the equation above. If not, do a minus. This basically means that if the user moved their finger from left to right you want to pick the intersection point on the right to keep the frog moving in the right direction. Pun intended.

We're almost done now. We can solve for x. But we still need a y value for the frog's new coordinates. Back to the line formula! Take our newly acquired value for x and plug it into our line equation y = mx + b along with the known values for m and b. You'll easily get y and now you've got a coordinate pair!

Just one more minor note before we get to the code. Remember that whole vertical line thing? Yeah, we need to handle that. But, good news! If we have a vertical line we don't need to mess with any circles or triangles or dodecahedrons or anything. Just add or subtract the distance moved from the current y coordinate (again, depending on if the original swipe was up or down) and return that paired with the current x coordinate.

Here's the two new methods that should be added to the FrogPath class shown above:


private float yIntercept(float x, float y, float m) {
return (y - (m * x));
}

public float[] getNextPoint(float c, float d, float dist) {

if (vertical) {

float yp = d;
if (this.y2 < this.y1) {
yp -= dist;
} else {
yp += dist;
}
return new float[] {c, yp};

} else {

float b = yIntercept(c, d, this.slope);

float xp = 0f;
if (this.x2 < this.x1) {
xp = (float) (c - (dist /
                          (Math.sqrt(1+Math.pow(this.slope, 2)))));
} else {
xp = (float) (c + (dist /
                          (Math.sqrt(1+Math.pow(this.slope, 2)))));
}
float yp = (this.slope * xp) + b;
return new float[] {xp, yp};

}

}


Just note that I return the new coordinates as an array of floats where the x coordinate is at position 0 and the y coordinate is at position 1. You could easily substitute some kind of object that represents a point if you prefer.

The only thing left to do is to figure out when to stop moving. That task is relatively simple, you just have to keep track of the total distance moved and stop when it equals the distance moved in the original screen swipe.

So that's it. That's how I used geometry that I probably should have learned in high school to defeat the dreaded virtual D-pad in a mobile game. And speaking of defeating something, who do you think would win in a fight between Pythagoras and Archimedes? Leave your comments below. My money's on Archy. Yeah, that's right. I called him Archy. Archimedes had a nickname. That's what his friends called him.

Sunday, March 17, 2013

It would appear that I've made an error

Back in 2011 I implemented the Separating Axis Theorem in JavaScript to help detect polygon collisions in HTML5 games. Now that I've started implementing similar games in Java to play on my OUYA, it has come to my attention that my algorithm had a slight mistake in it.

The problem had to do with calculating the Minimum Translation Vector, which tells you how to move one of the polygons to get them out of collision. If you were just using the algorithm to detect collision with a true/false you wouldn't notice any problem.

Here's what I did wrong...

After projecting both shapes' vertices onto the normal axis, you will have two line segments and you are supposed to determine how big the overlap (if any) is between the them. You can read a great explanation of the whole algorithm on the Code Zealot blog.

So let's say you end up with two line segments, A and B. Both sit on the X axis, so you can ignore any Y value. A runs from 1.5 to 4.4 while B runs from -2.8 to 2. What would you say the overlap is? The correct answer would be 0.5, but my implementation of the algorithm was coming up with 7.2.

Here was my calculation of the overlap:
o = (maxA > minB ? maxA - minB : maxB - minA);
See anything wrong there? In the case I outlined above, maxA was 4.4, obviously greater than minB which was -2.8. So I calculated the overlap as 4.4 + 2.8. Wrong! What was I thinking? Try it yourself with other line segments...you'll see that it sometimes gives you a correct value but often does not. If only I had created a good unit test for this code years ago. Fortunately, I did create such a test for my Java version using JUnit, and found my mistake. Here is the correct calculation of overlap:
o = (maxA > maxB ? maxB - minA : maxA - minB);
I've updated my JavaScript version, so people who find it on my previous blog entry won't be led astray. Sorry about that. I'll post my Java version soon, along with what is (hopefully) a good explanation of how it works.