Showing posts with label Inkscape. Show all posts
Showing posts with label Inkscape. Show all posts

Tuesday, November 12, 2013

Touch and SVG Spirals (Game Programming)

I've written a lot about bouncing balls as a way to make the comparison of CSS, Canvas, and SVG standardized. Graphics are about moving things, and that little ball bounces just fine on Firefox OS on my ZTE Open. In my next non-game post, I'll write up a comparison of the three graphics systems with pros and cons. But before I do that, I want to add one more bit about SVG ... and introduce the important issue of touch.

SVG isn't just about simple shapes like balls and boxes. Vector art (formerly known as line art before there were computers) can do incredible things and Adobe Illustrator has a strong place in the graphic design and illustration fields because you can rescale your art to fit a magazine, web page, or whatever. Scalable Vector Graphics is what SVG stands for. SVG does beautiful art by creating paths, which are just a series of lines connecting points.

A Little Bit about SVG

Here's an example of vector art, taken from the Open Clip Art site, a lively spiral created by Martin Bryce.


And here's a small part of the code that created it:

<path
       id="path2987"
       style="color:#000000"
       d="m-176.51-690.97c-59.728-0.23053-121.12 6.8953-145.25 18.438-2.2422 1.0724-4.4748 2.2103-6.6875 3.4375v18.344h-24.312v-1.4375c-13.611 11.42-25.872 25.146-35.688 39.406v22.031h-12.188c-4.0378 11.373-4.9902 23.682-5.625 35.719h16.438c4.2265-15.781 9.1152-32.046 20.281-46.031 19.959-24.998 48.083-49.881 76.781-65.312v-8.6562h19.219c24.836-8.4996 70.064-14.135 116.81-15.562-6.5418-0.21078-13.145-0.34939-19.781-0.375zm19.781 0.375c42.823 1.3798 82.471 6.8046 103.97 17.406v-1.8438h24.312v19.188c15.165 14.106 27.136 32.286 35.687
...
34.366 16.224 77.094 18.531 117.78 18.531 7.1247 0 13.769-0.0951 20.031-0.40625z"
       fill="#f33" />

The code goes on a few pages, and I'm 100% that Martin Bryce didn't sit down with graph paper and plot out those commands. What you're looking at is the definition of a series of points that make up one of the lines. Even though the final result in the image above has lots of wiggly lines, all those wiggles are just a set of points that define the line.

Martin used an art program such as Inkscape or Adobe Illustrator (or maybe something else, but those are the big two). The art program lets you draw with a mouse or use a drawing tablet to make your drawing. Why is this so cool?
  1. You can scale the drawing to be bigger or smaller, or stretch it.
     
  2. When you copy the code into your web page, it takes up less bytes than a bitmap.
  3. And you can get at all of this through JavaScript code and do great mangling!
So that's enough about SVG for a few minutes. It's cool. Check it out. Read about the SVG path command here. Complicated but Inkscape or Illustrator can do all the heavy lifting for you. For Inkscape, check out the book called The Book of Inkscape (very well written by one of the developers) and for Illustrator, track down any copy of any version of the Illustrator Wow! series.

So, go look at those and come back in a minute to ponder the mysterious world of Touch.

Touch

Bouncing a ball around is fine, but if you have a game, you want to interact with the elements on the page. There are a few ways to do that, but the most popular is touch. Touch the screen and make things happen.

For Firefox OS, you can fake touch by using mouse clicks. Mozilla can interpret the mouse code as a touch. No hover, however. Maybe some day, but you can't hover your finger over your phone screen and get any hover.

Code for Touch and Click

So here's the code for responding to a touch on the screen. The touch will move an SVG spiral (simpler than Martin's) to whatever point on the screen you touched, and the x and y coordinates of your touch will be displayed on the screen as well.

<!DOCTYPE HTML>
<html>
   
  <head>
  <title>svg spiral for touch</title>
  <meta charset="UTF-8">
 
  <style>
    #myDiv
    {   
      position:absolute;
      top: 0px;
      left: 0px;
    }
   
    #myPara
    {
      position:absolute;
      top: 50px;
      left: 50px;
    }
  </style>

    <script type="text/javascript">
       
      // Global variables
     
      var screenX = 320;        // Screen x value
      var screenY = 460;        // Screen y value
      var spiralX = 150;        // Spiral x value
      var spiralY = 150;        // Spiral y value

      // Add load event listener to run first function.
      window.addEventListener("load", runFirst, false);
                
      // This function runs when the document loads.
      function runFirst() {

        // Create SVG parent element.
        mySvg = document.createElementNS(
          "http://www.w3.org/2000/svg", "svg");
        mySvg.width.baseVal.valueAsString = "320px";
        mySvg.height.baseVal.valueAsString = "460px";

        // Create SVG screen.
        myScreen = document.createElementNS(
          "http://www.w3.org/2000/svg", "rect");
        myScreen.x.baseVal.value = 0;
        myScreen.y.baseVal.value = 0;
        myScreen.width.baseVal.value = screenX;
        myScreen.height.baseVal.value = screenY;
        myScreen.style.setProperty("stroke-width","1","");
        myScreen.style.setProperty("stroke","red","");
        myScreen.style.setProperty("fill","none","");
               
        // Append SVG parent to div of web page.
        document.getElementById(
        "myDiv").appendChild(mySvg);

        // Append screen to SVG parent element.
        mySvg.appendChild(myScreen);
      
        // Add mouse event listener.
        // Listener is attached to the SVG object.
        // Mousedown is better than click.
        mySvg.addEventListener(
          "mousedown", whereMouse, false);
               
        // Create spiral.
        mySpiral = document.createElementNS(
          "http://www.w3.org/2000/svg", "path");
               
        mySpiral.setAttribute("d",
          "M 8.3052015,10.567223 C "+
          "8.5290778,10.974677 "+
          "7.8664138,11.070027 "+
          "7.6279854,10.93932 6.9818595,10.585111 "+
          "7.1280823,9.668097 7.5610072,9.2127904 "+
          "8.3354083,8.3983538 9.6552076,8.6603337 "+
          "10.33685,9.4509311 11.337187,10.611165 "+
          "10.946898,12.380531 9.7935902,13.276087 "+
          "8.2564118,14.469722 6.0240157,13.946083 "+
          "4.9191211,12.427708 3.5287239,10.516989 "+
          "4.1879167,7.8159392 6.0726185,6.5039261 "+
          "8.3552449,4.9149023 11.527841,5.7107754 "+
          "13.045714,7.9625424 14.834475,10.616172 "+
          "13.901276,14.262005 11.281979,15.984951 "+
          "8.257897,17.974161 4.1377526,16.903234 "+
          "2.2102568,13.916097 0.02011351,10.521923 "+
          "1.2290373,5.9267386 4.5842299,3.7950617 "+
          "8.3482488,1.4036424 13.418989,2.7507484 "+
          "15.754578,6.4741538 c 2.592948,4.1336852 "+
          "1.107525,9.6803612 -2.98421,12.2196622") ;

        mySpiral.style.setProperty("stroke-width","1","");
        mySpiral.style.setProperty("stroke","black","");
        mySpiral.style.setProperty("fill","none","");
       
        mySpiral.setAttribute("transform",
          "translate(" + spiralX + "," + spiralY + ")");
    
        // Append spiral to SVG parent element.
        mySvg.appendChild(mySpiral);
       
        // Initial message.
        myPara.innerHTML = "Touch the screen.";
      }
   
      // Where did the mouse go down?
      function whereMouse(evt){
     
        // Get mouse coordinates.
        mouseX = evt.clientX;
        mouseY = evt.clientY;
       
        // Convert to string for display.
        myCoord = mouseX.toString() + " right, "
          + mouseY.toString() + " down";
        myPara.textContent = myCoord;
       
        // Calculate offset of click to spiral.
        spiralX = mouseX - 8;
        spiralY = mouseY - 8;
       
        // Change spiral position.
        mySpiral.setAttribute("transform",
          "translate(" + spiralX + "," + 

          spiralY + ")");              
      }
             
    </script>
  </head>
   
  <body id="myBody"> 
    <p id="myPara">Text goes here.</p>
    <div id="myDiv" />
  </body>

</html>


The structure follows the same as the last post on SVG. Create an SVG pane, stick an object on it, and then wait for events to happen. There's the usual load event handler, but there is a new one that waits for a mousedown event. Note that I'm using a mousedown event, not a click. For touch, you don't want to wait until the click ends. 

You need to register the mousedown event in the code after you create the SVG object, because the event handler is attached to the SVG pane. This is helpful so that the click goes right to the drawing board.

The mousedown event handler is pretty standard for a mouse event. You get the x and y properties and then you ... apply them to the spiral.

My Spiral

Not as pretty as Martin's, but simpler. Here's the code:

        // Create spiral.
        mySpiral = document.createElementNS(
          "http://www.w3.org/2000/svg", "path");
               
        mySpiral.setAttribute("d",
          "M 8.3052015,10.567223 C "+
          "8.5290778,10.974677 "+
          "7.8664138,11.070027 "+
          "7.6279854,10.93932 6.9818595,10.585111 "+
          "7.1280823,9.668097 7.5610072,9.2127904 "+
          "8.3354083,8.3983538 9.6552076,8.6603337 "+
          "10.33685,9.4509311 11.337187,10.611165 "+
          "10.946898,12.380531 9.7935902,13.276087 "+
          "8.2564118,14.469722 6.0240157,13.946083 "+
          "4.9191211,12.427708 3.5287239,10.516989 "+
          "4.1879167,7.8159392 6.0726185,6.5039261 "+
          "8.3552449,4.9149023 11.527841,5.7107754 "+
          "13.045714,7.9625424 14.834475,10.616172 "+
          "13.901276,14.262005 11.281979,15.984951 "+
          "8.257897,17.974161 4.1377526,16.903234 "+
          "2.2102568,13.916097 0.02011351,10.521923 "+
          "1.2290373,5.9267386 4.5842299,3.7950617 "+
          "8.3482488,1.4036424 13.418989,2.7507484 "+
          "15.754578,6.4741538 c 2.592948,4.1336852 "+
          "1.107525,9.6803612 -2.98421,12.2196622") ;

        mySpiral.style.setProperty("stroke-width","1","");
        mySpiral.style.setProperty("stroke","black","");
        mySpiral.style.setProperty("fill","none","");
       
        mySpiral.setAttribute("transform",
          "translate(" + spiralX + "," + spiralY + ")");
    
        // Append spiral to SVG parent element.
        mySvg.appendChild(mySpiral);
       

This creates an SVG object, and uses a path to define it. There's no fill because this is an open spiral. This spiral uses the SVG transform property to make the spiral translate to a new position. The transform property has a lot of cool options, and its main use is that you can move SVG objects, resize them, or otherwise make them do cool things on the fly with your code. MDN has a good page on transform here

And the last bit is always important. Attach your new SVG object to an SVG object. Don't leave it floating in space.

By the way, I didn't plot out this path either, even though it is simpler than Martin's. I used Inkscape! First I created a 32x32 workspace and then drew a spiral. Inkscape has some built-in spirals (not part of SVG but still cool) so I plopped one down and then saved it (save it as SVG, not as Inkscape SVG) and pasted the code into my web page. Very easy. There's a lot of Inkscape tutorials and other books, but that book by Dmitry Kirsanov is very cool.

So, we've got our spiral, and then when you click on it, the mousedown event handler gets the x and y coordinates and uses the SVG transform/translate attributes to move the spiral to a new position and display the new coordinates.

After the calculation, use this to move the spiral:

       mySpiral.setAttribute("transform",
          "translate(" + spiralX + "," + spiralY + ")");    
          
 

I had also set up a place to put messages with 

        myPara.innerHTML = "Touch the screen.";

And defined the absolute location in the CSS style section. Then to use it, I just put this in the mousedown event handler:

        // Convert to string for display.
        myCoord = mouseX.toString() + " right, "
          + mouseY.toString() + " down";
        myPara.textContent = myCoord;


So after all that, here is what the page looks like on my ZTE Open:


The spiral is near the middle and the message tells you to touch the screen. And when you do, this is what happens:



You can do this all day!

By the way, you want to be careful where you define your objects when working with SVG. In this example, the anchors were in the body. I found that if I put the paragraph after the div, the click wasn't handled if the click was over the paragraph. It's always important to remember that the flow of objects is set by the order in the web page and sometimes that can confuse you when you're throwing about objects.

Next

There's so much to talk about for Firefox OS game programming. Yes, it's HTML5 game programming, but things are different once you're talking about phones. Here's my schedule, subject to change, for the next few non-game-review posts:
  1. Comparison of CSS, Canvas, and SVG
  2. Screen Orientation
  3. Device Orientation (not the same as Screen Orientation)
  4. Collision Detection
  5. A simple first game
And that's just for starters. Stay tuned, but not iTuned.

Wednesday, November 6, 2013

Bouncing SVG - Part 2 (Game Programming)

In my first post on SVG (http://firefoxosgaming.blogspot.com/2013/11/bouncing-svg-part-1-game-programming.html), I covered the simplest way to use SVG in a game. Create your images using SVG tags in the body of your HTML5 document and then manipulate them using setAttribute to make things move.

That's not a bad way to work, but I have found that creating objects through JavaScript seems to make for faster action on the page. But there's a logical reason. The SVG tags have to be parsed and then translated into the DOM. For something simple like bouncing a ball, you won't see any difference. In fact, for the different ways I've written about for bouncing a single ball, you aren't likely to notice any difference because the work done by the browser is easy. In fact, for a lot of action games, you'll have to slow down the programming to be fair to the user. Ball bouncing needs to be fast, but not too fast. Although when I watch Olympic ping pong, it seems too fast to me.



So if you create your own SVG objects on the fly in JavaScript, the creation is faster and it is just cooler. I personally find it exciting to think that I'm starting with a blank web page and I'm adding thing to it in JavaScript. Maybe its a matter of taste. But it's nice to have options.

So, here's option 2 for SVG. Make it all in JavaScript and the DOM. Actually, in option 1, you were using the DOM to get at the attributes of the ball you created with tags. The main reason I started with tags is that there are tons of books, websites, and blogs explaining how to create SVG images using tags. For example, want to make an ellipse? Check out Mozilla's docs on the SVG ellipse.

But there aren't very many docs or examples on how to do scripting with SVG, because most people began by thinking that SVG is a way to represent static vector images and stopped there. Well, don't stop, keep going!

Here is the code for a bouncing ball using the second technique of SVG, creating art on the fly and using the DOM to get at it.

<!DOCTYPE HTML>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      SVG in the XML DOM
    </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 requestAnimationFrame.
      var requestAnimationFrame =
      window.requestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.msRequestAnimationFrame; 

     
      // URL for W3C definition of SVG elements
      var svgURL = "http://www.w3.org/2000/svg";
        
      // Page load event listener (hear it loading?)
      window.addEventListener("load",
        runFirst, false);
               
      // Run this first.
      function runFirst() { 
     
        // Define the game board as an SVG element.
        gameBoard =
          document.createElementNS(svgURL, "svg");
         
        // Width and height of the SVG board element
        gameBoard.setAttribute("width", boardWidth);
        gameBoard.setAttribute("height", boardHeight);        

        // 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, and radius of the ball
        paddleBall.setAttribute("cx", ballHor);
        paddleBall.setAttribute("cy", ballVer);
        paddleBall.setAttribute("r", 10);
        // Fuchsia = #FF00FF
        paddleBall.setAttribute( "fill", "#FF00FF");
         
        // Attach the ball to the game board.
        gameBoard.appendChild(paddleBall);
       
        // Start the game loop.
        gameLoop();
        }
       
      // Game loop - governed by requestAnimationFrame.
      function gameLoop(){
     
        // Restart the 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 < -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 the ball with new coordinates.
        paddleBall.setAttribute("cx", ballHor);
        paddleBall.setAttribute("cy", ballVer);
        }
       
      </script>
    </head>
   
    <body id="pageBody">
    </body>

</html>


Most of this is the same as earlier ball bouncing examples. HTML5, load the code, start the loop, check for changes, repeat! But if you read this from top to bottom, you'll notice that the body of the page is now empty. There's nothing there! Well, almost nothing. The body now has an id of "pageBody" and you'll need this to anchor your SVG objects to.

Here's the basic process for using SVG in a web page using JavaScript:
  • Create the object using createElementNS.
  • Modify it by setting the attributes.
  • Add the object to the page or another object.
createElementNS

This is similar to createElement but it creates an element in a specified namespace. This is needed so you don't get your SVG objects mixed up with your other objects. SVG is definitely its own animal, but it plays well with others if you feed it properly.

createElementNS starts out by creating the SVG pane. I call it a pane because I don't want to call it a canvas, but the idea is similar to the canvas in Canvas. The SVG pane is where you place all your SVG objects. All the objects have to fit inside the boundaries of the object or they won't display (you might want to do this to have objects hide off-screen until they are ready for their big scene).

The first use of createElementNS is this:

   gameBoard = document.createElementNS(svgURL, "svg");

I had previously defined an URL (path to a web site) for svgURL.

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

SVG uses this URL to clue the browser in that we are talking about SVG as defined in the year 2000. Maybe someday they will change this, but right now this works for everyone for SVG. It says "I'm SVG and I'm special."

The second parameter of createElementNS is "svg". You can call it anything you want, but it is the name of the newly created element. However, you want to assign the value of createElementNS to a variable. I picked gameBoard and that's what you use to grab on to the SVG pane.

setAttribute

Once you've created your SVG object, it's just floating in space somewhere but it has no color, size, or odor. That's no fun. You need to assign it values. For the SVG pane, you want to give it a size and nothing else because for this example, the SVG pane is just a container that the ball will bounce around in. So this code will define the size:

        gameBoard.setAttribute("width", boardWidth);
        gameBoard.setAttribute("height", boardHeight);


 The board width and height were previously defined as 320x460, the size of my lovely little ZTE Open phone.

appendChild

The third step is to attach your SVG object to the web page (or another SVG object). You do this by using appendChild. Here's the code to attach the object:

        document.getElementById("pageBody").appendChild(gameBoard);

This can be tricky to read as it has three parts:
  1. The word "document" which is the page document.
  2. getElementbyID("pageBody") which is the way that you grab the page body.
  3. appendChild(gameBoard) which adds the SVG pane to the body.
The three pieces are joined by dots. Essentially you're adding a new element to the existing page element which in turn is part of the whole document.

At this moment, when you  add the SVG pane as a child of the page, the SVG pane is now part of the page. Because we didn't give it any color, it doesn't look different. But its there and it says, "I am SVG and I am 320x460 wide and high. Hear me roar!"

Not much fun, yet. Now to create the familiar Fuchsia ball, you just repeat the three step process above.
  1. Create the ball.
  2. Give it attributes.
  3. Attach it to the SVG container.
Here's the code that does this:

        // Define the ball as an SVG element.
        paddleBall =
          document.createElementNS(svgURL, "circle");
         
        // Width,  height, and radius of the ball
        paddleBall.setAttribute("cx", ballHor);
        paddleBall.setAttribute("cy", ballVer);
        paddleBall.setAttribute("r", 10);
        // Fuchsia = #FF00FF
        paddleBall.setAttribute( "fill", "#FF00FF");
         
        // Attach the ball to the game board.
        gameBoard.appendChild(paddleBall);


At the moment this code runs, the ball will appear on the screen. The rest of the code is similar to the other examples. And in the ballMove section, you move the ball with this code:

        paddleBall.setAttribute("cx", ballHor);
        paddleBall.setAttribute("cy", ballVer);


which was used in the first SVG example.

There you have it. Create your objects, give 'em attributes, attach them to something, and bang 'em around! What could be easier? This technique isn't well documented, but it works and you can get the attribute names and values from the Mozilla docs at https://developer.mozilla.org/en-US/docs/Web/SVG/Element. There are lots of elements, but luckily Moz has sorted them into 13 categories further down the page. Working with paths can be tricky, but you can draw a path with Inkscape, save it as SVG, and see what the path actually is in numbers and letters.

But there's one more way to do SVG that is even cooler. In a complicated game, this third way will make everything fly. Stay tuned!

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!