Wednesday, October 30, 2013

Bouncing a Ball with Canvas Arc (Game Programming)

Recently I created a simple programming showing how to bounce a ball around a Firefox OS phone screen using nothing but HTML5, JavaScript, and CSS (check it out).

CSS is very cool, but Canvas has its place also. There are a few different ways to work with Canvas, and I'll show you one here. The game looks the same, so I grabbed a graphic from Wikipedia when they weren't looking.



I'll be covering bouncing balls in Canvas (with a few variations) as well as SVG (with greater variations).

So basically instead of pushing around a bitmap, we'll create a canvas in HTML5 and then draw on it using the Canvas Arc method. This is only a few more lines than the CSS version, and runs just as fast. And, again, this runs in all browsers.

Here is the code, in glorious HTML5:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      Canvas Bounce Draw Circle
    </title>

    <script>
   
    // Global variables
    var canvas;
    var ctx;

    var boardWidth = 320;
    var boardHeight = 460;

    var ballHor = boardWidth / 2;
    var ballVer = boardHeight /2;

    var changeHor = 10;
    var changeVer = 10;

    // Listen to that page load!
    window.addEventListener("load", getLoaded, false);

    // Run this when the page loads.
    function getLoaded(){

      // Make sure we are loaded.
      console.log("Page loaded!");
 
      // Load the image and the canvas.
      loadMyImage();

      // Start the game loop.     
      gameLoop = setInterval(doMainLoop,16);
    }

    // This will run every 16 milliseconds.
    function doMainLoop(){
 
      // Clear the canvas.
      ctx.clearRect(0,0,boardWidth,boardHeight);
 
      ballMove(); 
    }

    function ballMove() {
     
      // Changes are calculated but do not
      // take effect until next time through loop.
         
      // Calculate new vertical component.
      ballVer = ballVer + changeVer;

      // If top is hit, change direction.
      if (ballVer + changeVer < -10)
        changeVer = -changeVer;
       
      // If bottom is hit, reverse direction.
      if (ballVer + changeVer > boardHeight - 10)
        changeVer = -changeVer;

      // Calculate new horizontal component.
      ballHor = ballHor + changeHor;

      // If left edge hit, reverse direction.
      if (ballHor + changeHor < -10)
        changeHor = -changeHor;
       
      // If right edge is hit, do something.
      if (ballHor + changeHor > boardWidth - 10)
        changeHor = -changeHor;
       
      // Draw a ball using canvas arc function.
      ctx.beginPath();
      ctx.arc(ballHor, ballVer, 10, 0, Math.PI * 2, true);
      ctx.closePath();
      ctx.fillStyle = "Fuchsia";
      ctx.fill();             
    }

    // Load the image and the canvas.
    function loadMyImage() {

      // Get the canvas element.
      canvas = document.getElementById("myCanvas");

      // Make sure you got it.
      if (canvas.getContext) {

        // Specify 2d canvas type.
        ctx = canvas.getContext("2d");
      }
    }

</script>

</head>
<body>

  <canvas id="myCanvas" width="320" height="460">
  </canvas>

</body>
</html>


There are lots of books written about Canvas and you can always get started at the W3 Schools: http://www.w3schools.com/html/html5_canvas.asp

Essentially, this code can be divided into  parts:

  1. HTML5 shell - standard, except Firefox OS likes to know about UTF-8.
  2. JavaScript that defines some global variables and defines a page load event.
  3. An initial function that loads the canvas and starts the game loop.
  4. A game loop function that erases the screen and draws the ball.
  5. A function that calculates what's next and moves the ball.
  6. A function that loads the canvas.
  7. A canvas element in the body that defines the canvas size.
This has been tested with my trusty ZTE Open Firefox OS phone. I like the phone for all its quirks, and it is a good environment to test on because it represents the minimum that a Firefox OS phone offers. I haven't even tried to upgrade the OS, but everything I'm doing is very standard and shouldn't cause any problems. After all, it's only game programming!

Here's how it works:

Shell and Globals and Page Load

The shell is just your standard HTML5 shell. Nothing special to see here, but be sure to give it a title and specify UTF-8 (unless you are working with other kinds of UTF).

The canvas and its context (ctx) are defined as global so they can be accessed anywhere. Sometimes globals are good. The size of the screen (board), position of the ball, and the amount of change are defined.

An event handler is created that will detect when the page is loaded. I always do this because I want to make sure everything is loaded before I start calling JavaScript. In the CSS ball bounce, I used the onload function in the body but event listeners are cooler.

Initial Function

You call two functions here (and I added a console output in case you want to make doubly sure the page loaded).

First the function is called that defines the canvas. You do this once.

Next you call the game loop, which will run every 16 milliseconds. You can mess with this number, but it seems to work with the way that browsers are programmed. Or maybe it's just a memory of that time when you were sweet 16?

Game Loop

This just does two things:
  1. Clear the screen.
  2. Call a function to draw the ball.
Canvas needs to have the screen cleared. Once you draw on the canvas, it stays that way. Think of it as fire and forget. Except that with games, you can't forget, so you need to keep track of what you're doing, but the canvas won't help you. The canvas forgets! There are some other techniques you can use to take care of this, but we'll talk about that later.

Anyway, the loop just goes around and around, each time clearing the screen and drawing the ball in a new place. For fun, don't clear the screen and watch it fill up with ball images.
 
Drawing the Ball

This is the good part. Canvas has some drawing commands, like line, square, and arc. They don't have a circle command, but you can draw a circle with the arc method (arcs are just parts of a circle, so make it go around all wthe way). You can find out more about arc here. Of course, there's a W3C canvas specification, but it's written for browser manufacturers, not web monkeys like you and me.

So drawing the ball has some similarities to the CSS bouncing ball. Calculate the move, and draw the circle. The difference here is that instead of blasting with a bitmap, you draw a circle.

      ctx.beginPath();
      ctx.arc(ballHor, ballVer, 10, 0, Math.PI * 2, true);
      ctx.closePath();
      ctx.fillStyle = "Fuchsia";
      ctx.fill();    


This is a pretty standard canvas procedure. All your methods are attached to the canvas context (ctx, defined in the function below). Follow this for painting with a method:
  1. Arc is really a way to define a path. So you need to begin the path first.
  2. The arc method needs the ball x and y position, radius, and three other standard variables.
  3. Then you close the path. Otherwise the horse will get out of the barn!
  4. Then define your color with the fillStyle method (isn't Fuschia fun to spell?).
  5. Finally, use the fill method to make it happen.
Canvas likes fiddly procedures, but once you learn them, you can just fill in the blanks.

Loading the Canvas

Getting a canvas to work is not that hard, it just takes a few steps:
  1. Define the canvas in the body.
  2. Load the canvas into the web page.
  3. Get the context of the canvas.
  4. Make sure you get the context!
In this function, you first find the canvas element that was created in the body with the canvas tags. The canvas tag needed to have a height, width, and an id (so it can be found).

Next, do an if statement to make sure you get the canvas. In that statement, use the canvas.getContext method and assign it a name (ctx is popular). Specify that you want a "2d" canvas. 3D is coming but I'm not sure how well it is supported and I'm only looking at 2D games right now.

You want to make sure you got the context. It's like page load. You'll appreciate it the first time you make a typo or forget to define the canvas tag in the body.

Canvas Element in the Body

Just put the canvas element in the body. Give it a size and id. The position of the canvas is determined by the flow of the page, but wherever it is, once you have its context, you can blast away on it. Think of canvas as its own little world. You can draw on it and every HTML5 browser supports it.

That's it for now. This seems to run as fast as the CSS ball bouncing, but I haven't done any precise tests yet. It runs fast enough to convince me I can do an action game with Canvas or CSS.

So far, the advantage goes to CSS, because I don't care about what's on the screen and I don't erase anything. In CSS I just move the ball, but in Canvas I have to clean up after the ball moves. Well, maybe that's like taking care of a cute little puppy.

Next time: what if you have other stuff on the Canvas screen and don't want to erase everything?

No comments:

Post a Comment