Showing posts with label SVG DOM. Show all posts
Showing posts with label SVG DOM. Show all posts

Monday, December 2, 2013

SVG Collision Detection (Game Programming)

In the last two Firefox OS game programming posts covering collision detection, I wrote about simple collision detection using calculation (CSS Collisions) and using color to detect a collision (Canvas Collisions). The first is the most common, and the second takes advantage of a feature of Canvas I've only seen used a few times.

Unlike CSS, which has nothing built-in for collisions, and Canvas, which has something you can use (reading a color pixel on the canvas) but was probably not intended for collisions, the third technique uses a feature of SVG that seems to a perfect candidate for collision detection. The secret of this technique is to use the getBBox.method.


As I wrote about in the topic on Touch and SVG Spirals, SVG is made up of lines and shapes, and the shapes can be irregular. In that topic I created a spiral and used it to move to the touch of your finger. Because SVG shapes don't need to be regular, you might think it would be hard to know whether you are colliding with them or not. But by using getBBox, you can determine the size of the box that will exactly enclose that shape, no matter how goofy. If you'd like to see lots of unusual SVG shapes, I recommend you check out the Open Clipart site, which not only offers free clipart (like the box above), but all of their art is stored as SVG files.

So what about getBBox? First of all, as you might guess, it stands for "get bounding box" and that's all it does. But that's a lot. You can get bounding boxes of enemies so you can shoot them, and they can get your bounding box and shoot back. Whatever the shape, it has a bounding box. So what? Well, once you have the bounding box (which is a rectangle), you can determine the x and y coordinates of the top left corner, and the width and height of the box. From there you can decide if your bounding box overlaps the enemy bounding box. What is particularly cool about this for SVG is that one of the coolest game aspects of SVG is that your shapes can change size, and then they do, the bounding box changes also.

Where can you learn about bounding boxes for SVG. Well, unfortunately not a lot of places. For once, Mozilla is silent on the subject of getBBox. It doesn't even have links to SVGLocatable, which is where getBBox lives in the W3C specification for SVG (http://www.w3.org/TR/SVG/types.html#__svg__SVGLocatable__getBBox). I learned about it in a cool blog post from Erik Dahlstrom called How to get the boundingbox of an svg element.

Why isn't this more well known? Probably the easiest answer is that SVG wasn't designed for JavaScript; but because it has an object model you can get at with JavaScript, you can do cool stuff. You don't need to understand anything about SVGLocatable, it's just the object that getBBox method hangs off of. SVG has methods, but they can only be used in JavaScript. So use 'em! Make that SVG move!

And by the way, getBBox works in Firefox, Chrome, Opera (which is where Erik Dahlstrom hangs out), and even IE (starting with version 9). Why does all this scripting stuff work with SVG even though it isn't very well documented anywhere? The answer is that most of it is needed to make SVG work behind the scenes. Sometimes it is complicated, but once you know the basic tricks and can work your way through the SVG specification (can you say huge?), things work, and they work fast.

So the topic for today is using getBBox to detect collisions. A lot of the code will be similar in structure to the two previous collision detection posts, with only the drawing parts changed to SVG. I use an angry blue square trying to get an innocent red ball. The red ball can jump out of the way and avoid the blue box. And all this takes place on a chocolate square (a box of chocolate?).

The code runs fast on my ZTE Open with Firefox OS and it looks like this:

<!DOCTYPE HTML>
<html>  
  <head>
      <meta charset="utf-8"> 
    <title>
    SVG Collision
    </title>

    <script>
       
          // Global variables
      var boardWidth = 320;
      var boardHeight = 460;
      var bwPixels = boardWidth + "px";
      var bhPixels = boardHeight + "px";
        var redBallHor = 60;
      var redBallVer = 160;
      var redBallRad = 10;
      var howFast = 3;
        var blueBoxHor = 270;
      var blueBoxVer = 150;
   
          // Namespace for SVG.
          svgNS = "http://www.w3.org/2000/svg";
     
      // Covers all bases for various browser support.
        var requestAnimationFrame =
          window.requestAnimationFrame ||
          window.mozRequestAnimationFrame ||
          window.webkitRequestAnimationFrame ||
          window.msRequestAnimationFrame; 

      // Event listeners
      // Page load event listener
      window.addEventListener("load", getLoaded, false);
      // Mouse down event listener
      window.addEventListener(
          "mousedown", redBallJump, false);
         
      // Run this when the page loads.
      function getLoaded(){

        // Make sure we are loaded.
        console.log("Page loaded!");    
    
        // Create SVG parent element.
        myBoard = document.createElementNS(svgNS, "svg");
        myBoard.style.setProperty("width",bwPixels);
        myBoard.style.setProperty("height",bhPixels);
        myBoard.style.setProperty("top","0px");
        myBoard.style.setProperty("left","0px");
        myBoard.style.setProperty("position","absolute");
        
        // You must append the board to the body.
        document.getElementById("pageBody").
             appendChild(myBoard);
            
        // Create blue box.
        blueBox =
          document.createElementNS(svgNS, "rect");
         
        // Width,  height, radius, and color of box.
        blueBox.x.baseVal.valueAsString =
          blueBoxHor + "px";
        blueBox.y.baseVal.valueAsString =
          blueBoxVer + "px";
        blueBox.width.baseVal.valueAsString =
          "20px";
        blueBox.height.baseVal.valueAsString =
          "20px";       
        blueBox.style.
          setProperty("fill","blue","");
         
        // Attach the box to the game board.
        myBoard.appendChild(blueBox);

        // Create red ball.
        redBall =
          document.createElementNS(svgNS, "circle");
         
        // Width,  height, radius, and color of ball.
        redBall.cx.baseVal.valueAsString =
          redBallHor + "px";
        redBall.cy.baseVal.valueAsString =
          redBallVer + "px";
        redBall.r.baseVal.valueAsString =
          redBallRad + "px";
        redBall.style.
          setProperty("fill","red","");
         
        // Attach the ball to the game board.
        myBoard.appendChild(redBall);
       
        // Create ground.
        myGround =
          document.createElementNS(svgNS, "rect");
         
        // Width,  height, radius, and color of box.
        myGround.x.baseVal.valueAsString =
          "0px";
        myGround.y.baseVal.valueAsString =
          "170px";
        myGround.width.baseVal.valueAsString =
          "320px";
        myGround.height.baseVal.valueAsString =
          "230px";       
        myGround.style.
          setProperty("fill","chocolate","");
         
        // Attach the box to the game board.
        myBoard.appendChild(myGround);

        // Start the main loop.
        doMainLoop();
      }

      // Game loop
      function doMainLoop() {
     
        // Loop within the loop.
        // Outer loop
        // Runs every 1/3 second.
            loopTimer = setTimeout(function() {
       
          // Inner loop
          // Runs as fast as it can.
          animTimer = requestAnimationFrame(doMainLoop);         
      
          // Drawing code goes here
              console.log("Moving the box.");
         
              // Move the box
              moveBlueBox();
         
        }, 1000 / howFast); // Delay / how fast     
      }
           
      // Move the blue box here.
      function moveBlueBox() {
     
          // Subtract 10 from box horizontal value.
          blueBoxHor = blueBoxHor - 10;
     
      // Draw the new blue box.
      blueBox.x.baseVal.valueAsString =
          blueBoxHor + "px";
   
          // If the blue box hits the left edge, restart.
          if (blueBoxHor < 10) blueBoxHor = 270;   

          // Get bounding box of box.
      bbBox = blueBox.getBBox();
      console.log(bbBox.x);

      // Get bounding box of ball.
      bbBall = redBall.getBBox();
      console.log(bbBall.x);

      // Is there an x collision?
      if (bbBall.x + 20 == bbBox.x) {
     
        // Is there a y collision?
        if (bbBall.y == bbBox.y) {
       
          // Collision!
          blueBoxHor = 270;
          alert("Bang");
        }
      }  
    }

    // Make the red ball jump up.
    function redBallJump() {

      // Calculate red ball jump and move it.
      redBallVer = redBallVer - 50;  

      // Draw the new red ball.
      redBall.cy.baseVal.valueAsString =
          redBallVer + "px";      
   
      console.log("Ball up.");
   
      // Make the red ball fall after one second.
      redBallTimer = setTimeout(redBallFall, 1000);     
    } 

    // Make the red ball fall down.
    function redBallFall() {
   
      // Calculate the redBox fall and move it.
      redBallVer = redBallVer + 50; 
     
      // Draw the new red box.
      redBall.cy.baseVal.valueAsString =
          redBallVer + "px";    
      console.log("Ball down.");  
    }

    </script>
  </head>
   
  <body id="pageBody">
  </body>

</html>


Here is what it looks like. You have a blue box marching across the screen from right to left. There is a red ball just sitting there on the left.


You can make the red ball jump out of the way by touching the screen.


Whee!

If the ball doesn't jump out of the way fast enough, the box catches the ball and an alert is displayed.



Maybe not very exciting, but my philosophy is to show the least amount of code to illustrate a concept. Here the concept is to have three different drawing techniques (CSS, Canvas, SVG) doing the same thing. In this case, detecting a collision between two objects.

Most of the code is the same as the other two examples, so you can read about it there (requestAnimationFrame, setTimeout, eventListener, etc). Here are the SVG parts.

To start with, you need to define the board, the box, the ball, and the box of chocolates. There are two different ways to define SVG objects using the SVG object model. Here is the one I used to define the board:

       // Create SVG parent element.
        myBoard = document.createElementNS(svgNS, "svg");
        myBoard.style.setProperty("width",bwPixels);
        myBoard.style.setProperty("height",bhPixels);
        myBoard.style.setProperty("top","0px");
        myBoard.style.setProperty("left","0px");
        myBoard.style.setProperty("position","absolute");


I created an SVG element that is the container and parent for the other SVG objects that are on it. Note that svgNS (the SVG namespace) is defined by

          svgNS = "http://www.w3.org/2000/svg";

After creating the SVG container, I defined the properties of that container by using setProperty. I set the width and height to match the ZTE Open screen size. Height and width are obvious, but I needed to set the top and left as well, and make them 0,0. And to make the position absolute. If I don't do these three, Firefox thinks I want the SVG container to be offset by a few pixels to leave a margin.

Is this a bug or a feature? Only time will tell, but if you use SVG, you want to make sure the all your objects are firmly placed exactly on the screen where you want them to be. The container is your board, but that board doesn't come into full existence until you add it to the HTML5 page. (Does an unattached SVG container exist if no one can find it in the forest?)

At the bottom of the page, I assigned an id of pageBody to the body of the document. Then this code attaches the SVG container to the page.

        // You must append the board to the body.
        document.getElementById("pageBody").
             appendChild(myBoard);


You don't see anything yet, because you haven't assigned a color to the container and you don't need to here.

But you want to see something, so code is added for the box, ball,and ground. Here is the code for the box:

        // Create blue box.
        blueBox =
          document.createElementNS(svgNS, "rect");
         
        // Width,  height, radius, and color of box.
        blueBox.x.baseVal.valueAsString =
          blueBoxHor + "px";
        blueBox.y.baseVal.valueAsString =
          blueBoxVer + "px";
        blueBox.width.baseVal.valueAsString =
          "20px";
        blueBox.height.baseVal.valueAsString =
          "20px";       
        blueBox.style.
          setProperty("fill","blue","");
         
        // Attach the box to the game board.
        myBoard.appendChild(blueBox);


Note that this code starts out similar to the container, but then uses a different style of SVG object model definitions. Instead of setting properties, you actually use code to assign values. As I explained in an earlier post, you need to define your data carefully. All of this because when they created SVG (almost 15 years ago), they thought they would use animated lengths so they made it all too complicated, especially because (not thinking of JavaScript), they decided that data types were important. So you can't feed in a number if it wants a string (defining pixels). But if you follow the patterns in this post, SVG is fast and fun.

Essentially you can set properties on objects using assignment or setProperty. The blue box is a rect, the ball is a circle, and the ground is another rect. Set the colors and locations, and your objects appear on the screen, ready to go.

By the way, if you are working with the SVG object model, you'll be safe if you think in terms of objects and properties. That's the terminology for manipulating the SVG object model. But you may remember my post on part 2 of the bouncing ball in SVG, which used the HTML Document Object Model. In that post, my code for a ball looked like this:

        // Width,  height, and radius of the ball
        paddleBall.setAttribute("cx", ballHor);
        paddleBall.setAttribute("cy", ballVer);
        paddleBall.setAttribute("r", 10);


This used setAttribute, not setProperty. If you are in the world of attributes, you are talking to HTML elements and the HTML Document Object Model. You are still working with SVG object model, but you are doing it by going through the HTML DOM. Doing it with setAttribute makes your code run a little slower because it has to tunnel through a layer of translation. But you want to play with the big programmers, who use objects and properties. Leave the elements and attributes for the markup monkeys!

The rest of the code is pretty simple. The box will move toward the ball using two timing loops, and the box will jump out of the way using the mousedown event. But as the box moves forward, each time it uses getBBox to determine its own bounding box and the bounding box of the ball.

If the x value of both bounding boxes match, there might be a collision. But if the ball has jumped out of the way, there won't be a collision because the y values of both won't be the same. If there is a collision, bang!

So there you have it. Using getBBox lets you detect collisions easily. Especially because SVG offers a whole array of ways to stretch, resize, and change the shapes of your objects, and yet you can always find them!

Next time (after a game review or two), I'll compare the pros and cons of the three drawing techniques (CSS, Canvas, and SVG) and then move on to other game programming topics. I'm ignoring a fourth technique called WebGL which is catching on fast and which Firefox OS supports, but since it requires a 3D editor and may need more horsepower than my little ZTE Open has, I'll let it sit on the sidelines now.

But as you can guess by now (spoiler alert!), I'm biased toward SVG and there are plenty of books and articles on Canvas and a few on CSS, but almost none on SVG. So I'll keep writing about it because SVG is definitely fun.

Thursday, November 7, 2013

Bouncing SVG - Part 3 (Game Programming)

In the first two parts of this series I wrote about how to use SVG to animate a bouncing ball. The first one was about putting the SVG in the body with tags and the second was about creating the SVG from scratch with JavaScript. In this, the third part, I want to write about a third way of doing SVG. This new way is not hardly documented anywhere and will take some work, but the payoff might be worth it, especially if performance is important to your game.



I've already talked about the DOM (Document Object Model) and you probably have heard about it. The DOM is actually the API of web browsers and you can use JavaScript to make the DOM do cool tricks. For example, if you have a sequence of paragraphs, you can change their order by manipulating the DOM. Every bit of a web page is part of the DOM. You can "walk" the DOM to see how your web page is constructed and in general mess around a lot.

But because SVG is independent and XML based, when you add it to the HTML DOM, something magical happens. The regular HTML DOM can get at the SVG and that was how the manipulation of SVG was done in Part 2 of this series:
  1. The SVG was added to the page with createElementNS.
  2. JavaScript was able to manipulate it through the HTML DOM with setAttribute.
But there was something hidden going on. There was ... another DOM!

This DOM is called the SVG DOM.

NOTE: actually, the DOM in the first two examples isn't really the HTML DOM, it is the XML DOM which is a sibling to the HTML DOM. It's easier to call it the HTML DOM. Everything about DOM is shadowy and hidden in Mirkwood somewhere. But right now let's just talk about the SVG DOM.

When you add SVG to your HTML5 web page, there are two ways to get at the SVG DOM. One way (in Parts 1 and 2) is going through the HTML DOM. The HTML DOM does some of the work for you, especially in converting some of the messy parts of the original SVG spec. But you pay a price for this conversion. When your calls go to and from the SVG DOM by way of the HTML DOM, things can slow down. For bouncing a ball, you won't notice any difference. But if you are doing something complicated, the difference can make ... a difference.

But you can sneak around the HTML DOM and call the SVG DOM. The way of doing it is different, but the way you do it is more like programming and less like markup. So here's today's program, similar in many ways to earlier ball bouncing, but using JavaScript in a way that is unique to SVG.

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      SVG in the SVG DOM
    </title>
    
    <script>

      // --- Global variables ---

      // Width and height of board in pixels
      var boardWidth = 320;
      var boardHeight = 460;
      var boardWidthPixels = boardWidth + "px";
      var boardHeightPixels = boardHeight + "px";

      // URL for W3C definition of SVG elements
      var svgURL = "http://www.w3.org/2000/svg";
          
      // Variables for ball initial position.
      var ballHor = boardWidth / 2;
      var ballVer = boardHeight /2;
      var ballHorPixels = ballHor + "px";
      var ballVerPixels = ballVer + "px";
      var changeHor = 10;
      var changeVer = 10;
     
      // Covers all bases for requestAnimationFrame.
      var requestAnimationFrame =
      window.requestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.msRequestAnimationFrame; 
     
      // --- Event listeners ---
     
      // Page load event listener (hear it loading?).
      window.addEventListener("load",
        runFirst, false);
               
      // Runs when page loads.    
      function runFirst() { 

        // Define the game board as an SVG element.
        gameBoard =
          document.createElementNS(svgURL, "svg");
         
        // Width and height of the SVG board element.
        gameBoard.width.baseVal.valueAsString =
          boardWidthPixels;
        gameBoard.height.baseVal.valueAsString =
          boardHeightPixels;
         
        // You must append the board to the body.
        document.getElementById("pageBody").
          appendChild(gameBoard);
       
        // Define the ball as an SVG element.
        paddleBall =
          document.createElementNS(svgURL, "circle");
         
        // Width,  height, radius, and color of ball.
        paddleBall.cx.baseVal.valueAsString =
          ballHorPixels;
        paddleBall.cy.baseVal.valueAsString =
          ballVerPixels;
        paddleBall.r.baseVal.valueAsString =
          "10px";
        paddleBall.style.
          setProperty("fill","fuchsia","");
         
        // Attach the ball to the game board.
        gameBoard.appendChild(paddleBall);
        
        // Start the game loop.
        gameLoop();
        }
       
      // Game loop.
      function gameLoop(){
     
          // Endless loop with requestAnimationFrame.
        requestAnimationFrame(gameLoop);
      
        // Move the ball.
        ballMove();        
        }
     
      // --- Move the ball. ---    
      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 < 0)
          changeVer = -changeVer;
       
        // If bottom is hit, reverse direction.
        if (ballVer + changeVer > boardHeight)
          changeVer = -changeVer;

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

        // If left edge hit, reverse direction.
        if (ballHor + changeHor < 0)
          changeHor = -changeHor;
       
        // If right edge is hit, do something.
        if (ballHor + changeHor > boardWidth)
          changeHor = -changeHor;
       
        // Draw the ball with new coordinates.
        paddleBall.cx.baseVal.valueAsString =
          ballHor + "px";
        paddleBall.cy.baseVal.valueAsString =
          ballVer + "px";   
        }    

        </script>
    </head>
   
    <body id="pageBody">
    </body>

</html>


This code starts out very much like Part 2. We're creating SVG objects in the browser with nothing in the body. But after createElementNS, the code looks weird. Here's how the SVG board size is set:

        gameBoard.width.baseVal.valueAsString =
          boardWidthPixels;
        gameBoard.height.baseVal.valueAsString =
          boardHeightPixels;


Actually, there were some new global variables. They were additions to the earlier ones, but instead of numbers, the height and width have to be set in pixels, not just a number. Behind the scenes, SVG uses a quirky numbering system which I'll get in to in another post later.

Anyway, you might think you could type:

                  gameBoard.width = 320;

But you can't. You have to add a few quirky things, but once you know those quirks, it's not that hard. Here's how to understand this code:

       gameBoard.width.baseVal.valueAsString =
          boardWidthPixels;


The first quirky part is that you have to throw in a new keyword, baseVal. This tells JavaScript to tell SVG that you want to use a normal SVG value for a length (length here means a measure of distance, and applied to height or width) the alternative is animVal, for animation, which you don't want. Why, you ask? Well, if you look up the SVG DOM page for rect (which is what we are defining) and can figure out that in normal SVG, you call it rect, but in SVG DOM, you call it SVGRectElement, you'll find it here: https://developer.mozilla.org/en-US/docs/Web/API/SVGRectElement.

Go look at that page. Mozilla has done a good job of putting the pieces there in the right order. But what you need to see at that page is that width and height are defined as a SVGAnimatedLength type. SVG animation was a cool idea back in the year 2000 (Conan O'Brien reference), but it never quite got itself together. You can animate SVG with JavaScript (don't ask about SMIL). Because of this, you have to make a slight twist and define the width and height with normal units, and use baseVal. And when you do that, you further need to feed the width and height values as strings, not as numbers. So we need to set our height and width as pixels.  You can get some clues here in the SVGLength topic on MDN https://developer.mozilla.org/en-US/docs/Web/API/SVGLength.

If you use this technique, you can do all kinds of programming tricks with SVG and you can bypass the DOM. Mozilla has a great page that lists all the various DOM categories and even what's in and what's out. It includes the three big DOM sets (DOM, HTML DOM, and SVG DOM). In the beginning was the DOM and then HTML DOM came forth and said let's make it easier, and finally SVG DOM came in and said let's party! https://developer.mozilla.org/en-US/docs/DOM/DOM_Reference. Talking about these is a pain, however, and I wish they'd give them easier names, like DOM Red, DOM Blue, DOM Green or something. Well, I guess they think they made it easy. The stock DOM is just DOM and it calls an element ... Element. The HTML DOM calls the same element HTMLElement (so you know it's the same if you whack off the HTML part), and the equivalent for SVG is called ... wait for it ... SVGElement. These prefixes actually have a reason, which is that they are used to keep the things with the same name apart. These prefixes are so you know what namespace you are in at any moment (if you're that poor overworked guy, the browser developer).

So all this info is in the Mozilla Developer Network, but you have to pick it apart. The SVG spec also has the same information, and the reason it is hard to follow is that specs are written for browser developers, not game programmers like you and me. But the really cool part is that all of these whacky things in the SVG DOM namespace are implemented in every browser that supports SVG. Mind you, not every blinking object and property actually are implemented because about 15% of SVG is just too obscure or not needed. Things involving Fonts, Text, and Animation are funky and/or just don't work and aren't a high priority for the browser developers.

But all these techniques work on every modern browser. Firefox! Chrome! Even IE! And even their friends on mobile devices and their cousins SeaMonkey! and Opera! And even that weird uncle in the background who made a pile of money in some way people don't want to talk about, Safari!

SVG is everywhere.

Oops, forgot one more cool quirk that SVG allows you to use in the SVG DOM. SVG and CSS are BFF! A lot of the values are right in line with CSS. So after you create the ball using this new SVG DOM technique, you can define the color by a CSS style, like this:

        paddleBall.style.setProperty("fill","fuchsia","");

Because this 3rd way of messing with SVG is working with the SVG DOM, everything is an object and objects have properties. Repeat this until it makes sense:

           HTML DOM = elements and attributes
           SVG DOM =  objects and properties

They are really the same concept, but the first is a markup thing and the second is a programming thing.

So anything that can have a property set can be set using "style". And one of the fun things about SVG is that it has a lot of style.

I'll be writing about this 3rd type of programming for SVG more in this blog but I want to get back to writing about game programming. I've written about three different game technologies you can use for drawing: CSS, Canvas, and SVG, and I'm hoping that you'll now be able to think about which way you want to go with programming. Here's my take on the three:

CSS - cool for a lot of games but needs more investigation on my part.
Canvas - almost everyone is using this now. It's good, but may not be the best in tight spaces.
SVG - lots of interesting possiblities, especially for tight spaces.

I'd like to do more with SVG for sure, but also see how CSS can fit in somewhere. So stay tunes. Next programming post, I want to get started on the next phase of game programming, which is touch! And a little bit more SVG for added flavor.

And, you don't need to pick just one. You can use any or all of these three technologies in the browser simultaneously. One of the best examples of this was a called Glow and showed who was downloading Firefox at any moment.


It showed a map of the world, drawn in SVG, and little points of light every place that someone was downloading Firefox, and the points of light were little dots created with Canvas. It was cool to watch and see how at night in the Americas, the downloads were in Europe, and the opposite was true for daytime in the Americas. Gone now, but you can read about it here.

Wednesday, November 6, 2013

Bouncing SVG - Part 1 (Game Programming)

Earlier in this blog I wrote about bouncing a ball in CSS and several posts about bouncing a ball with Canvas. But there's a third web technology that might be perfect for some types of games, and its name is SVG. You may have heard about it, you may know that SVG stands for Structured Vector Graphics, but you probably don't know more than that, because the story of SVG is one of starts and stops, success and failure, and yes, slowly but surely, SVG keeps marching on. I won't bore you with the whole story, because this set of three posts is all about the three ways to use SVG to bounce balls so you can make choices about the graphic technology you want to use to make games for Firefox OS phones.

In the late 90's, the world was discovering the web. But the web was slow, especially when it came to graphics and pictures. Why not use vector graphics and describe them mathematically? Just a few lines and you have a fast-loading picture. Microsoft came up with one system (VML) and Adobe came up with another (PGML). Some others became interested and a new standard was invented that took parts of both and combined them to make SVG. It was a cool dream, but it didn't quite come together.

Microsoft didn't want to support SVG and they stuck with VML but didn't really promote it as a graphics language. The main use for VML was to represent Office Art for Office 2000, but not much else. Adobe promoted SVG but it was a constant uphill battle because without Microsoft support, nothing much was going to happen. VML was forgotten, and even though there were a dozen books about SVG, nothing much happened. 

One of the main reasons for the sidelining of SVG was that the Internet was speeding up fast and graphics now loaded just fine, thank you. It was a bitmap world!

Until Tim Bernars-Lee wrote a prominent article that called attention to the fact that Microsoft wasn't supporting important standards like SVG. Anyone else might have been ignored, but Tim was the founder of the Internet, so Microsoft decided to hire some new folks and make Internet Explorer support web standards (they'd shut down the team and sent them over to DirectX, allowing Firefox and Chrome to take up the slack).

So SVG was now implemented in most browsers, but the story doesn't end there, at least for game programming. Most everyone who knew about SVG looked at it as a lightweight way to have vector drawings. Professional illustrators had been doing this for years (with ... Illustrator). But as a static art format, SVG wasn't all that interesting.

The final thing that made SVG really useful was that when HTML5 was being created, some bright person decided it might be cool to have SVG be supported as if it were HTML. This was really cool because before that, SVG was seen only as an XML format. Nice, but a pain to work with. 

But by being able to treat SVG as a HTML, you could code that would put SVG shapes, lines, and paths in your web page. For example, the code below will create a red circle in a web page using HTML5.

<!DOCTYPE html>
<head>
</head>
<body>
<h3>This is SVG</h3>
<svg width="120" height="120" >
<circle cx="60" cy="60" r="50" fill="red" />
</svg>
</body>
</html>
And here is what it looks like:

All that I did was to add the SVG element, define its width and height, and then inside the element, I defined a red circle with a center of 60,60 and a radius of 50 pixels. SVG is still XML underneath, but you can treat it as any other element, and SVG has a lot of things it can do: shapes, paths, shading, text. Everything is defined by a markup language, and now it fits right in with HTML like they were siblings (they both have the parent of XML).

And you might ask yourself, how well is SVG supported, now that Internet Explorer supports it (and who cares about them anyway)? Chrome 4 and Firefox 2 were the first supporters, but right now, according to that wonderful site, Can I Use?, all the major browsers support SVG.(Opera Mini was the last holdout). And of course, Firefox, Firefox OS, and Firefox for Android support it too. 

But, if you look closely at the Can I Use? statistics, it says 84% support. The reason for this is that the SVG specification http://www.w3.org/TR/SVG/ is an extremely complicated document and has a lot nooks and crannies that aren't supported by anyone and may never be. The spec is still at version 1.1 (Second Edition) and change is slow. Parts that are not likely to be complete include typography and animation. But 84% of a huge spec is just fine (and the other 16% you don't care about unless you are a mad typographer.

The point here is that SVG is now in every browser, it does graphics with vectors, and its now much easier to use because you can treat it like any other HTML elements. It's right there for the taking! But because of the checkered history, people got excited about SVG (a dozen books!), but then lost interest when Microsoft wouldn't play along. And the Internet got fast, so no one cared anyway.

So why bother? SVG isn't just a pretty face. It has hidden depths, very deep depths. Here's the secret:

SVG CAN MOVE!

SVG can be moved, shaken, stirred, and in general, messed about with. Every element and attribute can be manipulated with JavaScript. So make your game bits and move them around. Because there are no bitmaps, you can have very lightweight graphics, and lightweight is cool on a Firefox OS phone. And Firefox has a pretty extensive set of reference pages on SVG at https://developer.mozilla.org/en-US/docs/Web/SVG. Of course!

Let's move something. How about a bouncing ball? 

But before I start throwing code (and fuchsia balls) at you (and after all that boring Internet history), I need to explain why there are three basic ways to use SVG in HTML5.
  1. The easiest way is to build your SVG art in the body of the browser. I did this just a few paragraphs ago by making a red circle. But the red circle can be manipulated by JavaScript. You can change the size, color, and position very easily. You can stretch it, mangle it, whatever you want. But unlike Canvas, SVG doesn't leave anything behind when it changes. The new size, color, position are preserved in the web page memory. None of this annoying draw, move, erase old, repeat. Just draw and move!
     
  2. The next way is to create all your SVG element and attributes on the fly with JavaScript. Want a circle? Make it in JavaScript. This all of a sudden becomes programming instead of markup language. You create elements, you modify them, and you do it all in JavaScript. You do this by using the HTML DOM (Document Object Model). You create SVG objects, define their attributes, and it is magic! More about this with the next programming post.
     
  3. But there's more. SVG has its own DOM. When you programmed SVG with method #2 (and actually #1 for the JavaScript part), you were talking to the SVG DOM through the HTML DOM.It turns out there is a way to go directly to the SVG DOM, and bypass the HTML DOM. This is faster and you can do even more manipulation. It's definitely tricky,but gives you greater persormance and control. And if you know how to read the SVG specification, all the answers are there. More about all this DOM stuff in the second programming post after this (sandwiched in with game reviews). 
Today's post will cover the first technique. Create an SVG object in the body with SVG tags, and then manipulate it with JavaScript. I'll use a lot of the same structure I used for CSS and Canvas, and the look and feel of the output will be the same, and, like all the other code I've put in this blog, it has been tested on Firefox OS on the ZTE Open phone.

Here's the code:

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      SVG in the body
    </title>
   
    <script>
   
      // Global variables
     
      var boardWidth = 320;
      var boardHeight = 460;     
      var ballHor = boardWidth / 2;
      var ballVer = boardHeight /2;
      var changeHor = 10;
      var changeVer = 10;
     
      // Covers all bases for various browser support.
      var requestAnimationFrame =
      window.requestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.msRequestAnimationFrame; 


      // This function is called on page load.
      function drawGameSVG() {
       
        // The page is loaded.
        console.log("The page is loaded.");   

        // Start the game loop.
        gameLoop();
      }
     
      // Game loop.
      function gameLoop() {
     
        // Move the ball once each loop.
        ballMove();
     
        // Restart the loop with requestAnimationFrame.
        requestAnimationFrame(gameLoop);   
      }

       // Move the ball.   
      function ballMove() {
     
        // Changes are calculated but do not
        // take effect until next time through loop.
       
        // Set the SVG attributes of the ball.
        ball.setAttribute("cx", ballHor);
        ball.setAttribute("cy", ballVer);
         
        // 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;   
      }

     </script>
  </head>
 
  <body onload="drawGameSVG()">

    <!-- Create the SVG board. -->
    <svg width="320" height="460" id="board" >
      <!-- Create the ball. -->
      <circle cx="150" cy="150" r="10" fill="Fuchsia" id="ball" />
     
    </svg>
  </body>

</html>


The body of the page does two things:
  1. Call the drawGameSVG function when the page loads.
  2. Creates an SVG container with the id of "board" and a ball with the idea of "ball". You need to define these with an id so JavaScript can grab them later. SVG always needs a container to start with. The ball is the only visible aspect and the properties of position (cx,cy), radius (r), fill (fuchsia), and id (ball) are needed to have a complete ball.
The JavaScript is nearly the same as the Canvas code. It starts the game loop, uses requestAnimationFrame to keep the loop going, but uses some new commands to actually move the ball once the new position has been calculated:

        // Set the SVG attributes of the ball.
        ball.setAttribute("cx", ballHor);
        ball.setAttribute("cy", ballVer);


When the ball was defined in the body with SVG tags, it had the id of "ball". That id is used here, and the attributes of the ball are modified in the function called ballMove. The method setAttribute is used to change the definition of the "cx" and "cy" positions to match whatever the new ball position is (as defined by ballHor and ballVer). ball is an object, and because HTML5 treats SVG elements as HTML elements, you can change any attribute by using setAttribute.

So, that's it. Not so hard, really. You can check out the MDN SVG pages, and especially look at the tons of samples they have at https://developer.mozilla.org/en-US/docs/Web/SVG/Element. SVG is huge, but I'll try to cover it as I go along, because there's a lot there that can be of value to game developers using HTML5.

Also it might be good to say that if you're not patient enough to do elaborate drawings in SVG by hand coding every twist and turn, you don't have to. There are two very excellent drawing programs that support SVG extremely well. The first is Inkscape, which is a free open source program that is just astounding. I'll talk more about Inkscape later, but it is worth checking out, and is 100% based on SVG. The other SVG art program is Adobe Illustrator, which is not free, but is also now supporting SVG pretty well. But my heart is with the wonderful folks at http://inkscape.org/ I love their motto: "Draw freely."

As with this post, and any others, if I didn't express something well or you have questions, make a comment and I'll try to answer it. This game programming stuff is complicated, especially with all the tons of technologies available free in Firefox OS!