PHP Game Coding: SVG Movement

flashEncapsulating Movement

Any sane person would abandon PHP for JavaScript, Ajax, jQuery or some other client-side language that would work directly with Web-based SVG graphic elements and attributes. In doing so, though, it would give up on both the OOP capacity of PHP (lacking in these other languages) and low cost (no open socket server) inter-internet games (i.e., remote multiplayer games.)

Ironically (for some), the easiest part of creating action games is the game physics. You just need to take a formula from physics (e.g., deceleration, acceleration) and turn it into an algorithm. Eventually, we’ll get to that luxury, but first we need to work out the mechanics of changing the position of a SVG graphic on a grid. Before getting into that discussion, click the Play button to see the end results (goal) and the Download button to see the code:
PlayDownload

As you will see, there’s not a lot to play with, but it does deal with two velocity issues; velocity itself and capacity. It’s like comparing the velocity of a 2014 Rolls-Royce Wraith with that of a 1988 Trabant 601. Both cars can attain speeds of 100 km/hr (62 mph), but the Wraith can do it much faster and go far above that speed because it has a more powerful engine. It has greater capacity.

The Space Grid

In the previous post on using SVG graphics in making games, you can see the grid setup, and in that grid you can determine distance and collision using simple geometry. If you’ve spend any time with SVG graphics, you will find a animation system to move graphics along paths. The problem with that system (for now at least) is working out position and collision detection. Movement along paths has grid-like parameters in defining X and Y locations on a grid, but paths can also be defined in terms of curves, and knowing the position of an object at any given time can be problematic. Further, movement is a function of timing using the SVG animateMotion element. For example, consider the following path:

    animateMotion fill=”freeze” path=”M 0 0 L 100 150″ dur=”.5s”

It moves an SVG object from 0,0 to 100,150 in a half a second (0.5 seconds). There is no checking along the way for collision. Using a BĂ©zier curve the following movement goes from 0,0 to 300,0 in two seconds (2s) but it curves downward before reaching its destination.

    animateMotion fill=”freeze” path=”M 0 0 T 100 150 T 300 0″ dur=”2s”

Again, what it may have collided with is unknown given both the timing of the motion and the curve. This is not to say that every point could not somehow be tracked, but at this point I’d rather take a more familiar route to movement and collision detection.

Moving SVG objects involves changing their X and Y values. I’m calling the frequency with which the X and Y values are updated, “capacity” and the amount of change “velocity.” Rather than using the animateMotion SVG element, this example changes the object’s X value through timed updates and variable values in the number of pixels each timed update generates. For example, an update of every 50 milliseconds is faster than one of every 100 milliseconds—there’s less time between each update pause. Likewise, an X increment of 10 pixels will cause faster movement than an update of 5 pixels.

A timed loop fires a function that changes the ship’s position:

?View Code JAVASCRIPT
function moveShip()
{
     // Change the ship's position
     shipX += $this->velocity;
     shipX = shipX % 500;
     oopz.setAttribute("x", shipX);
}

As you can see the code is JavaScript using a PHP variable ($this->velocity) to set the speed. I would have preferred to do it using all PHP, but needed to use the JavaScript setAttribute method for moving the ship’s X position without having to create a new object. Changing the speed using capacity (loop timing) and velocity (amount of variable increment) requires PHP to create another SVG object, and for demonstration purposes, that’s fine. In an action game, though, it’d eat up a lot of resources.

The “ship” (rectangle) only moves from left to right at this time, and when it leaves “the galaxy” it loops around and comes in the other end. Using the modulus of 500 (% 500), the value will always be calculated correctly when moving from left to right (in both JavaScript and PHP); however, moving from right to left, as soon as the X position is 0, it fails. (See this post on game algorithms for a detailed explanation and comparison of how the modulus operator works differently in Python than PHP and JavaScript). It’s an easy fix using conditional statements, but that’s so…I don’t know…inelegant? See what you can do. For now, continue on to see how the Move class is created and used.

The Move Class

The first class to examine is Move. It has a single responsibility: set the velocity and capacity of the ship. It does this by wrapping an XML SGV document inside an HTML5 document and putting the whole thing into a string using HEREDOC.

<?php
class Move
{
   private $velocity;
   private $capacity;
 
   public function setVelocity($speed,$ship)
   {
      $this->velocity=$speed;
      $this->capacity=$ship;
 
      $ship =<<<SHIP
     <!DOCTYPE HTML>
<html>
    <head>
    <script type="text/ecmascript">
      // Single global variable
      var shipX = 0; // Ship x position.
 
      // Engages each time 'Make it so' is clicked
      function drawSVG()
      {
        //Interval Timer loop
        moveLoop = setInterval(moveShip, $this->capacity);
      }
 
      function moveShip()
      {
        // Change the ship's position
        shipX += $this->velocity;
        shipX = shipX % 500;
        oopz.setAttribute("x", shipX);
      }
 
    </script>
    </head>
    <body onload="drawSVG()">
<!-- Create the SVG galaxy. -->
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 
<svg width="500" height="400" viewBox="0 0 500 400"
     xmlns="http://www.w3.org/2000/svg" version="1.1">
    <desc>Oopz</desc>
 
    <!-- Show outline of 2D Galaxy using 'rect' element -->
    <rect x="0" y="0" width="500" height="400"
        fill="#DCDCDC" stroke="blue" stroke-width="1"/>
    <!-- Space craft Oopz -->
    <rect x="100" y="100" width="30" height="20"
        fill="#cf5300" stroke="#369" stroke-width=".4" id="oopz" />
    </svg>
</body>
</html>
 
SHIP;
      return $ship;
   }
}

The Move class’ return value is the package of code with the values being updated by a little JavaScript engine (timed loop) with the values for speed and capacity set by PHP. In any event, the whole thing is encapsulated in a class with access provided for specifying capacity and speed through the setVelocity() method.

The Client Class

Originally, I used a little trigger script to fire up the Move class but decided to better encapsulate the process using a Client class with a private method to handle the superglobal variables. Superglobals are available in all scopes, but by designating private variables for the velocity and capacity and passing the values inside of a private method, I’d have their values nicely encapsulated with no concerns about those variables being changed in any scope outside of the Client class.

<?php
ERROR_REPORTING( E_ALL | E_STRICT );
ini_set("display_errors", 1);
function __autoload($class_name) 
{
    include $class_name . '.php';
}
class Client
{
   private $speed;
   private $ship;
 
   public function __construct()
   {
      $this->engage();
   }
 
   private function engage()
   {
      $trigger=$_POST["doit"];
      if(isset($trigger))
      {
         $this->speed= intval($_POST["speed"]);
         $this->ship= intval($_POST["ship"]); 
         $launcher=new Move();
         echo $launcher->setVelocity($this->speed,$this->ship);
         unset($trigger);
      }
   }
}
$worker = new Client();
?>

The engage() method assigns the superglobal values ($_POST) to private variables and used them in creating an instance of the Move class and then calling the object’s setVelocity() method with the two private variables values used as arguments.

To make everything easy, the HTML document has a two-part form: the first part has a set of radio buttons for the capacity and the second part is for a set of radio buttons for the velocity values. Both must be used or the PHP to correctly work. (If you want, your can add a verification system or start with checked radio buttons for each set.) You can see the HTML code detail in the following listing:

<!doctype html>
<html>
<head>
    		<link rel="stylesheet" href="move.css" type="text/css">
<meta charset="UTF-8">
<title>Velocity</title>
</head>
 
<body>
<h3>Velocity and Capacity</h3>
<ul>
        <form action="Client.php" method="post" target="galaxy">
<h4>Ship Type</h3>
<input type="radio" name="ship" value="100" id="ob">
            <label for="ob">SS Norkova (Norkova Modular Cargo)</label>
            <input type="radio" name="ship" value="30" id="ex">
            <label for="ex">USS Ghandi NCC-26632 (Ambassador Class Scientific)</label>
            <input type="radio" name="ship" value="16" id="ss">
            <label for="ss">USS Bellerophon NCC-74705 (Intrepid Class Starship)</label>
<h4>Velocity</h3>
<input type="radio" name="speed" value="1" id="df">
            <label for="df">Drift</label>
            <input type="radio" name="speed" value="5" id="cr">
            <label for="crx">Cruise</label>
            <input type="radio" name="speed" value="20" id="wp">
            <label for="wp">Full Sub-Warp</label>
            <input type="submit" value="Make it so" name="doit">   
        </form></ul>
<iframe name="galaxy">Space</iframe>
</body>
</html>

The CSS that accompanies the HTML can be seen in the following listing:

@charset "UTF-8";
/* CSS Document */
/* 003159 (dk blue) f5cc04 (lt yellow orange) f2b608 (med yellow orange) f3732d (singed orange) f4383d (rubbed red) palette name : flash */
body
{
    font-family: fantasy;
    color: #003159;
    background-color: #F5CC04;
}
 
h3
{
    background-color:#F4383D;
    font-family: Impact, Haettenschweiler, "Franklin Gothic Bold", "Arial Black", sans-serif;
    color: #DBDEE7;
    width: 500px;
    padding: 5px;
}
 
h4
{
    background-color:#003159;
    font-family: Impact, Haettenschweiler, "Franklin Gothic Bold", "Arial Black", sans-serif;
    color: #f3732d;
    width: 250px;
    padding-left: 1em;
}
 
iframe
{
    background-color:#DBDEE7;
    width: 520px;
    height: 400px;
    margin: 5px;
    padding: 5px;
}

What Next?

The arcade game project using SVG graphics with PHP is proceeding, and eventually, I’d like to make a two-player arcade game using PHP. However, this blog is advertised as and dedicated to PHP Design Patterns. Once all of the kinks are worked out I think that we can see a two-player game with design pattern structure. However, making arcade games using SVG graphics, a little JavaScript and HTML5 wrapped in PHP OOP will have to proceed a gradual pace. This will give readers a change to chime in with ideas and OOP code to move it along.

In the meantime, though, I’d like to move ahead with some more PHP design patterns than have not yet been discussed on this blog. Not to worry, though, we’ll return to the game projects and even see some game work in sample design patterns.

Share

Copyright © 2013 William Sanders. All Rights Reserved.

0 Responses to “PHP Game Coding: SVG Movement”


Comments are currently closed.