topical media & game development

talk show tell print

mobile-game-ch17-lander-explosion.htm / htm



  <!DOCTYPE HTML>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Lander</title>
      <script src='mobile-game-ch17-js-jquery.min.js'></script>
      <script src='mobile-game-ch17-js-underscore.js'></script>
      <script src='mobile-game-ch17-js-quintus.js'></script>
      <script src='mobile-game-ch17-js-quintus-input.js'></script>
      <script src='mobile-game-ch17-js-quintus-sprites.js'></script>
      <script src='mobile-game-ch17-js-quintus-scenes.js'></script>
  
      <meta name="viewport" content="width=480, user-scalable=no">
      <style>
        body { padding:0px; margin:0px; }
        #quintus { background-color:#CCC; }
      </style>
    </head>
    <body>
      <canvas id='quintus' width='480' height='320'></canvas>
      
      <script>
        var Q = Quintus()
                .include("Input,Sprites,Scenes")
                .setup()
                .controls();
  
        Q.Ship = Q.MovingSprite.extend({
          step: function(dt) {
            if(this.dead) return;
            var p = this.p;
  
            // Set our horizontal force
            p.fx = 0;
            if(Q.inputs['left']) { p.fx -= p.thrustX; }
            if(Q.inputs['right']) { p.fx += p.thrustX; }
  
            // Set our vertical force
            if(Q.inputs['fire']) {
              p.fy = -p.thrustY;
              p.asset = "lander-thrust.png";
              } else {
              p.fy = 0;
              p.asset = "lander.png";
            }
  
            // Calculate our y and x acceleration
            p.ay = p.gravity + p.fy / p.m;
            p.ax = p.fx / p.m;
  
            // Let our super-class update our x and y
            this._super(dt);
  
            var col;
            if(col = this.checkCollision()) {
              if(col == 1 && Math.abs(p.vy) < 30) {
                if(p.vy > 0) { 
                  p.vy = 0;
                }
              } else {
                this.parent.insert(new Q.Explosion(p.x,p.y,p.vx,p.vy,this.imageData));
                this.parent.remove(this);
                this.dead=true;
              }
            }
  
            // Force our lander to stay in our box 
            // and zero out our velocity when we hit a wall
            if(p.y < 0) { p.y = 0;  p.vy = 0; }
            if(p.y > Q.height- p.h) { p.y = Q.height - p.h; p.vy = 0; }
            if(p.x < 0) { p.x = 0; p.vx = 0; }
            if(p.x > Q.width - p.w) { p.x = Q.width - p.w; p.vx = 0; }
          },
  
          checkCollision: function() {
            var bgData = Q.backgroundPixels;
  
            // Get a integer based position from our
            // x and y values
            var bgx = Math.floor(this.p.x);
            var bgy = Math.floor(this.p.y);
  
            // Calculate the initial offset into our background
            var bgOffset = bgx * 4 + bgy * bgData.width * 4 + 3;
  
            // Pull out our data easy access
            var pixels = this.imageData.data;
            var bgPixels = bgData.data;
  
            for(var sy=0;sy < this.imageData.height;sy++) {
              for(var sx=0;sx < this.imageData.width;sx++) {
                // Check for an existing pixel on our ship
                if(pixels[sx*4 + sy * this.imageData.width * 4 + 3]) {
  
                  // Then check for a matching existing pixel on the background
                  // starting from our bgOffest and then indexing in from there
                  if(bgPixels[bgOffset + sx*4 + sy * bgData.width * 4]) {
  
                    // Next check if we are at the bottom of the lander
                    // if so return 1, to indicate that we might be landing
                    // instead of crashing
                    if(sy > this.imageData.height - 2) {
                      return 1;
                      } else {
                      // Otherwise return 2 and...Boom!
                      return 2;
                    }
                  }
                }
              }
            }
            return 0;
          }
  
        });
  
        Q.Explosion = Q.GameObject.extend({
          init: function(x,y,vx,vy,imgData) {
  
            // Set up a container for our pixels
            this.particles = []
  
            // Grab the lander's image data
            var landerData = imgData.data;
  
            // Create a 3x3 pixel-data 
            // image data container to use for blitting down the road
            this.pixelData = Q.ctx.createImageData(3,3);
            this.drawPixel = this.pixelData.data; 
  
            // Pixels are going to be exploding out from 
            // the center of the lander
            var centerX = imgData.width / 2;
            var centerY = imgData.height / 2;
  
            // Loop over each fourth pixel of the lander image
            for(var sy=0;sy < imgData.height;sy+=4) {
              for(var sx=0;sx < imgData.width;sx+=4) {
  
                // Offset into the 1 dimension pixel data array
                var loc = sx*4 + sy * imgData.width * 4;
  
                // If theres a lander pixel here
                if(landerData[loc + 3]) {
  
                  // Get the direction of the pixel from center
                  var distX = sx - centerX;
                  var distY = sy - centerY;
  
                  // Add a new particle
                  this.particles.push({
                    x: x + sx,  // starting position x
                    y: y + sy,  // starting position y
                    lifetime: 5,  // remaining lifetime
                    r: landerData[loc] + 20,  // make it a little redder
                    g: landerData[loc+1],
                    b: landerData[loc+2],
                    a: landerData[loc+3],
                    // For particle velocity, use the ships velocity,
                    // plus a random direction emanating from the center of the ship
                    vx: vx/6 +  distX * 5 *(Math.random()+0.5), 
                    vy: vy/6 + distY * 5 * (Math.random()+0.5)
                  });
                }
              }
            }
          },
  
          step: function(dt) {
  
            var bgData = Q.backgroundPixels;
            var pixels = bgData.data;
  
            for(var i =0,len=this.particles.length;i<len;i++) {
              var v = this.particles[i];
              if(v.lifetime > 0) {
  
                var oldx = v.x, oldy = v.y;
                v.vy += 20 * dt;
                v.x += dt * v.vx;
                v.y += dt * v.vy;
                var loc = Math.floor(v.x)*4 + Math.floor(v.y) * bgData.width * 4;
                if(pixels[loc + 3]) {
                  v.x = oldx;
                  v.y = oldy;
                  v.vy *= -0.2;
                  v.vx *= -0.2;
                }
                v.lifetime -= dt;
              }
              if(v.lifetime <= 0) { Q.stageScene('level'); return; }
            }
  
          },
          draw: function(ctx) {
            for(var i=0,len=this.particles.length;i<len;i++) {
              var v = this.particles[i];
  
              if(v.lifetime > 0) {
                for(var l=0;l<36;l+=4) {
                  this.drawPixel[l+0] = v.r;
                  this.drawPixel[l+1] = v.g;
                  this.drawPixel[l+2] = v.b;
                  this.drawPixel[l+3] = v.a;
                }
  
                ctx.putImageData(this.pixelData,v.x,v.y);
              }
            }
  
          }
        });
  
        Q.load(['lander.png','background.png', 
                'lander-thrust.png','map.png'], function() {
  
          Q.scene("level",new Q.Scene(function(stage) {
            stage.insert(new Q.Sprite({ asset: "background.png" }));
            stage.insert(new Q.Sprite({ asset: "map.png" }));
  
            var ship = stage.insert(new Q.Ship({
              asset: 'lander.png',
              x:       10, // X Position
              y:       170, // Y Position
              gravity: 20,  // Gravity
              m:       1,   // Ship’s Mass
              thrustX: 40,  // Horizontal Thrust
              thrustY: 80,  // Vertical Thrust    
            }));
  
            Q.backgroundPixels = Q.imageData(Q.asset('map.png'));
            ship.imageData = Q.imageData(Q.asset('lander.png'));
          }));
  
          Q.stageScene("level");
        });
      </script>
    </body>
  </html>
  
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.