Thursday, September 13, 2012

Removing Multiple Objects from a Physijs Scene

‹prev | My Chain | next›

I would like to be able to restart my Three.js / Physijs fruit jumping game. This seems as simple as cycling through all the scene's children and removing any fruit:
function reset() {
  scene.children.forEach(function(object) {
    if (object.is_fruit) {
      scene.remove(object);
    }
  });
}
I will leave the player and the ground as-is, though I will reset the player back to its starting position. Only resetting does not seem to work. Fruit seems to hang around and, if I check scene.children, it does not seem to correspond to what is actually in the scene:


There should at least be 5 objects in the scene: the camera, the ground, the player, and two fruit. But the scene is only reporting three. Strange.

In the end, I can come up with no other way to do this than to reach under the Physijs covers:
  for (var i in scene._objects) {
    if (scene._objects[i].is_fruit) {
     scene.remove(scene._objects[i]);
    }
  }
That is not all that satisfying a solution, but it works.

Day #508

Wednesday, September 12, 2012

Image Graphics in Three.js Games

‹prev | My Chain | next›

Up tonight, I would like to add some sweet graphics to my simple fruit Three.js Physijs jumping game. My graphics skills begin and end with crayons, so I draw a fruit monster (uploaded to http://gamingJS.com/images/purple_fruit_monster.png:


And do the same for fruit (uploaded to http://gamingJS.com/images/fruit.png):


Three.js's MeshBasicMaterial accepts image settings, so this seems a good place to start:
  player = new Physijs.BoxMesh(
    new THREE.CubeGeometry(20, 50, 1),
    new THREE.MeshBasicMaterial({
      map: THREE.ImageUtils.loadTexture('/images/purple_fruit_monster.png')
    })
  );
I am coding this in my copy Mr Doob's Amazing Code Editor at http://gamingjs.com/code-editor/, so I do not have to worry about CORS.

Aside for some noise on the side of the image, that seems to work:


Until my purple fruit monster falls below the blue horizon:


The image is PNG with alpha transparency around the monster. This does not seem to be working. Perhaps all that I need to add is the transparency flag to the material:
  player = new Physijs.BoxMesh(
    new THREE.CubeGeometry(40, 50, 1),
    new THREE.MeshBasicMaterial({
      map: THREE.ImageUtils.loadTexture('/images/purple_fruit_monster.png'),
      transparent: true
    })
  );
The result is an improvement. The transparency is visible, but the edge noise remains:


In the end, I opt for an empty material for the player object proper:
  player = new Physijs.BoxMesh(
    new THREE.CubeGeometry(40, 50, 1),
    new THREE.Material
  );
The player will interact with the rest of the scene, but will be invisible. To see where the player is, I add a plane with the image attached:
  var player_material = new THREE.MeshBasicMaterial({
    map: THREE.ImageUtils.loadTexture('/images/purple_fruit_monster.png'),
    transparent: true
  })
  var player_picture = new THREE.Mesh(new THREE.PlaneGeometry(40, 50), player_material); 
  player_picture.rotation.x = Math.PI/2;
  player.add(player_picture);
Which does the trick:


After doing the same for my fruit, I have awesome game play and sweet graphics:


That seems a fine place to call it a night.


Day #507

Tuesday, September 11, 2012

Asploding and Regenerating Fruit

‹prev | My Chain | next›

Today I switch back to my simple jumping game in Three.js / Physijs. So far, I have simple movement and scoring implemented. I need to generalize the goal (to jump on fruit) and implement a game over scenario (hit the ground).

I start by copying the single fruit code into a launchFruit() function:
function launchFruit() {
  var fruit = new Physijs.ConvexMesh(
    new THREE.CylinderGeometry(20, 20, 1, 24),
    new THREE.MeshNormalMaterial({color: 0xB22222})
  );
  fruit.rotation.x = Math.PI/2;
  fruit.position.x = 200;
  fruit.position.y = 20;
  fruit.is_fruit = true;
  scene.add(fruit);
  fruit.setLinearVelocity(
    new THREE.Vector3(-1e2, 0, 0)
  );
}
New in there is the initial linear velocity from right to left (toward the player), but everything is unchanged. Next, I add a call to gameStep() after the animate() function is started:
document.addEventListener("DOMContentLoaded", function() {
  init();
  // ...

  animate();
  gameStep();
});
In gameStep(), I throw a new fruit at the player every 3 seconds (eventually, I need to add some randomization):
var step = 0;
function gameStep() {
  if ((step % (3*60)) == 0) {
    launchFruit();
  }
  
  step++;  
  setTimeout(gameStep, 1000 / 60); // process the game logic
                                   // at a target 60 FPS.    
}
That works, but after the game has been running for a while, I notice that things start to slow down in the game. The slowness is because I am tasking the game to keep track of hundreds of fruits that are no longer needed after they have rolled well off the screen.

So I include a reapFruit() call along with launchFruit():
var step = 0;
function gameStep() {
  if ((step % (3*60)) == 0) {
    launchFruit();
    reapFruit();
  }
  // ...
}
Fruit are removed from the simulation whenever a fruit is found well to the left of the screen:
function reapFruit() {
  scene.children.forEach(function (object) {
    if (object.is_fruit && object.position.x < -250) {
      console.log("removing old fruit");
      scene.remove(object); 
    }
  });
}
Last up tonight, I need to modify the player to react to collecting fruit. I also need a game-over mechanism. I can apply both as Physijs events on the game player:
  player.addEventListener('collision', function(object) {
    if (object.is_fruit) {
      console.log(object);
      score += 10;
      writeScoreBoard("Score: " + score);
      player.setLinearVelocity(new THREE.Vector3(0, 100, 0));
      scene.remove(object);
    }
    if (object == ground) {
      game_over = true;
      writeScoreBoard(
       "Game Over!<br><br>" +
        "Score: " + score
      );
    }
  });
If the player hits a fruit, my score increases, I bounce straight up, and the fruit is removed from the scene. If my player hits the ground, the game is over.

With that, I have the game more or less working. I collect points whenever I strike fruit. The game is over when I hit the ground:


I do not want to make the game overly complex, so that should about do it. If you have any suggestions for improvement, please fix and share: source code editor.


Up tomorrow, I will replace the box and circles with something a little more player and fruit like.


Day #506

Monday, September 10, 2012

Expiring the Root Page of Application Cache.

‹prev | My Chain | next›

I need to take a (hopefully) quick break from my regularly scheduled Three.js programming to answer a question that has vexed me for a couple of night now: how to expire the HTML5 application cache? Actually, most of the cache is easy to expire, but there is one part that I cannot suss.

The application cache is a mechanism for creating offline applications. Mr Doob's Amazing Code Editor uses it so that users can still work with the Code Editor even when not connected to the Internet. Since this is an editor, offline capability seems like a good thing.

The application cache is established by the presence of the manifest attribute on the <html> element of a web page:
<!DOCTYPE html>
<html manifest="editor.appcache">
 <head>
  <title>code editor</title>
The appcache manifest file then describes the elements that are cacheable, those that should always be requested over the network, and any fallback. The manifest is stored in the same location as the web page. The manifest for Mr Doob's Code Editor looks like:
CACHE MANIFEST
# 2012-09-10

CACHE:
/favicon.ico
index.html
files/inconsolata.woff
js/editor.js
js/appcache.js
js/rawdeflate.js
js/rawinflate.js
js/codemirror/codemirror.css
js/codemirror/codemirror.js
js/codemirror/mode/css.js
js/codemirror/mode/htmlmixed.js
js/codemirror/mode/javascript.js
js/codemirror/mode/xml.js


NETWORK:
*
An application cache manifest needs to start with the CACHE MANIFEST directive. The CACHE directive introduces a list of files that will be loaded into cache. These files will be available offline and not requested from the server—even during a hard reload. The NETWORK directive introduces the files that will always be loaded over the Internet—even if they are needed by the application. In the case of the Code Editor, the catch-all of '*' is used to indicate that anything not explicitly referenced by CACHE but needed by the application, should be loaded via the internet.

As for my woes, it begins with the commented date immediately following the opening CACHE MANIFEST directive. The comment has no effect on the application cache itself. What it does serve to do is to expired the application cache. If the network is available, when I load up the application at http://gamingJS.com/code-editor no files are loaded except for the application cache manifest.

This presents a problem if js/editor.js was updated. Unless the application cache has changed, the browser will not reload js/editor.js. Even during a hard reload. Even if the user clears her cache and reloads. The js/editor.js file remains in application cache.

Since no new files have been added to the application, I cannot add a file to the manifest, so the convention is to update the timestamp after CACHE MANIFEST to force a reload. And this works just fine:


My problem is that, the code editor is very new. At the very least, I need to make a few changes to it. Mr Doob has made clear his intention to make major changes as well. I need to reference it in Gaming JavaScript at the http://gamingjs.com/code-editor. But that URL is not in the application manifest. The actual page of index.html is included in the manifest, but this is not what is stored in application cache.

Unfortunately, in its early days, much of Code Editor is stored in this web page. When there are changes, I have no way to update them. I (and anyone else with the old cached application) are stuck with the original version of the application. The only solution is to open up chrome://appcache-internals/ to manually remove the old version. This is not exactly ideal.

My ultimate solution to this conundrum is a decidedly pre-HTML5 solution:
    <script>
if (window.location.href.indexOf('.html')) < 0 {
  window.location.href = 'index.html'
}
    </script>
And that seems to do the trick.


Dang it. That was a ton of explanation for a very simple solution. I wish I had thought of that sooner. But, like I said at the outset, this had been bugging me for days. Writing it down turned out to be my rubber ducky.

Update: In the end, I don't think that works as desired. Subsequent reload are not picking up changes. So I am forced to adopt the HTML5 Rocks swapCache() solution:
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

  window.applicationCache.addEventListener('updateready', function(e) {
    if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
      // Browser downloaded a new app cache.
      // Swap it in and reload the page to get the new hotness.
      window.applicationCache.swapCache();
      if (confirm('A new version of this site is available. Load it?')) {
        window.location.reload();
      }
    } else {
      // Manifest didn't changed. Nothing new to server.
    }
  }, false);

}, false);
Day #505

Sunday, September 9, 2012

Kid Physics in the Code Editor

‹prev | My Chain | next›

Up tonight, I would like to make the physics in my Three.js / Physijs jumping game a bit more "kid like". Specifically, I would like the player to fall faster. I would like changes in direction to be more immediate.

I am going to eat my own dog food here. I plan to use the excellent code editor from Mr Doob for Gaming JavaScript. To do it right, I need to use it myself. My starting point, in the code editor, is current version of the game.

After hiding the code (and clicking on the document for proper event captures), the arrow keys move the player—the rectangle—around:


Falling faster is a simple matter of increasing gravity:
  scene = new Physijs.Scene({ fixedTimeStep: 2 / 60 });
  scene.setGravity(new THREE.Vector3( 0, -50, 0 ));
I also increase the Physijs timestep for an added boost.

To move the players differently, I would like to experiment in the Chrome JavaScript console. Mostly, I just want the code completion to remind me what methods Physijs exposes, but I also appreciate the immediate feedback that the console can provide—even more so than the code editor.

The problem is that the player, along with all other top level game variables, is not available in the JavaScript console:


Fortunately, it is available in a frame:


With that sorted out, I end up with this implementation for the game movement:
function left()  { move(-50, 0); }
function right() { move(50, 0); }
function up()    { move(player.getLinearVelocity().x, 50); }

function move(x, y) {
  player.setLinearVelocity(
    new THREE.Vector3(x, y, 0)
  );
}
Which seems to work well enough. And, since I am using the code editor, I can share it for others to try out.


Day #504

Saturday, September 8, 2012

Multiple Projects in Mr Doob's Code Editor

‹prev | My Chain | next›

Tonight, I continue playing with Mr Doob's Amazing Code Editor. I was able to integrate easily enough onto the Gaming JavaScript website under the /code-editor URL space. Tonight I hope to enable it to save projects with new names and to be able to open older projects.

Currently, when you save a Code Editor project, it saves immediately. I change the immediate save() calls to instead invoke openSaveDialog(), which I code up to do pretty much what you might expect:
      var openSaveDialog = function() {
        saveDialog.style.display = '';
      };
For the saveDialog object itself, I follow the Code Editor coding style of building DOM elements by hand:
      var saveDialog = document.createElement( 'div' );
      saveDialog.className = 'dialog';
      saveDialog.style.position = 'absolute';
      saveDialog.style.right = '15px';
      saveDialog.style.top = '60px';
      saveDialog.style.display = 'none';
      document.body.appendChild( saveDialog );

      var saveFileLabel = document.createElement( 'label' );
      // ...

      var saveFileField = document.createElement( 'input' );
      // ...

      var buttonSaveDialog = document.createElement( 'button' );
      // ...
      buttonSaveDialog.addEventListener( 'click', function ( event ) {

          save(saveFileField.value);
          saveDialog.style.display = 'none';

      }, false );
      saveDialog.appendChild( buttonSaveDialog );
When the save button is pressed, I invoke the new save() function, this time with the value entered in the text field.

In the save() function, I then use this to update the filename:
      var save = function (title) {

        documents[ 0 ].code = code.getValue();
        documents[ 0 ].filename = title;

        localStorage.codeeditor = JSON.stringify( documents );
        // ...
      }
With that, I get a new save dialog after pressing the save button from the toolbar:


And, when I save the project, it shows up in localStorage with the correct filename:


I add a simple check to create a new project if the filename does not match:
      var save = function (title) {

        if ( documents[ 0 ].filename != title) {
          documents.unshift({
            filetype: 'text/plain',
            autoupdate: documents[ 0 ].autoupdate,
          });
        }

        documents[ 0 ].code = code.getValue();
        documents[ 0 ].filename = title;

        localStorage.codeeditor = JSON.stringify( documents );
        // ...
      }
That gives me multiple projects. Next I need to be able to open different projects. This mostly involves even more tedious hand generation of HTML from JavaScript, but I am eventually able to get it working:


I do not think this is quite the end of getting the editor to suite my needs, but it is good progress.


Day #504

Thursday, September 6, 2012

Copying Mr Doob's Code Editor for Fun and Physics

‹prev | My Chain | next›

Up today, I would like to see if I can get Physijs simulations working in Mr Doob's code editor. Right up until the beta release date of Gaming JavaScript, I had meant to include a Physijs-based game. Unfortunately, I did not realize that web workers need to be served from the same machine as the original web page. Since I have kids developing locally, this presented a seemingly unassailable obstacle.

Until Mr Doob's Code Editor. At least, that is the hope.

The Physijs physics engine is loaded like any other script:
<head>
  <script src="http://gamingJS.com/Three.js">
  </script>
  <script src="http://gamingJS.com/Detector.js">
  </script>
  <script src="http://gamingJS.com/physi.js">
  </script>
  <title>Jumping</title>
</head>
But inside a Physijs script, one needs to specify the location of the underlying ammo.js physics engine as well as a web worker for doing physics calculations:
// Physics
Physijs.scripts.ammo = 'http://gamingJS.com/ammo.js';
Physijs.scripts.worker = 'http://gamingJS.com/physijs_worker.js';
Since I am loading the web page from a http://localhost server, that web worker URL will not work. And indeed, if I load the page, I get the dreaded "SECURITY_ERR: DOM Exception 18":


In fact, since my web worker resides on a different server than Mr Doob's Code Editor, I still get this error if I try to paste my code into the editor.

I see no other option but to copy Mr Doob's Code Editor into http://gamingJS.com so that both Code Editor and physics worker will be served from the same server.

So I clone the Code Editor:
➜  repos  git clone https://github.com/mrdoob/code-editor.git
➜  repos  cd code-editor
And export it into my Gaming JavaScript repository:
➜  code-editor git:(master) mkdir ../gamingjs/code-editor
➜  code-editor git:(master) git archive HEAD | tar -C ../gamingjs/code-editor -xf -
In my Gaming JavaScript repository, which is just a GitHub pages repository, I add the code editor and push it up to GitHub:
➜  gamingjs git:(gh-pages) ✗ git add code-editor/
➜  gamingjs git:(gh-pages) ✗ git ci -m "Add Mr Doob's Code Editor"
➜  gamingjs git:(gh-pages) gp origin gh-pages
With that, I have my very own copy of Mr Doob's excellent Code Editor at http://gamingjs.com/code-editor/.

More importantly, I am able to use the physijs web worker already on gamingJS.com to make physics happen:


Best of all, since this is Mr Doob's Code Editor, I can save my code so that others can check it out.

Please excuse me now while I go rewrite Gaming JavaScript completely to use this. This is just fantastic.

Day #502