»
Tiếng AnhTiếng PhápTiếng Việt

In - Trò chơi tránh thiên thạch với HTML5 và JavaScript - JavaScriptBank.com

Phiên bản đầy đủ: jsB@nk » Trò chơi » Kĩ năng » Trò chơi tránh thiên thạch với HTML5 và JavaScript
URL: http://www.javascriptbank.com/creative-html5-javascript-asteroid-game.html

Trò chơi tránh thiên thạch với HTML5 và JavaScript © JavaScriptBank.comHôm nay, jsB@nk muốn giới thiệu đến bạn cách thức để xây dựng một ứng dụng trò chơi đơn giản với kĩ thuật HTMl5 và JavaScript; tên ứng dụng này là Asteroid, và được jsB@nk đặt là Trò chơi tránh thiên thạch bởi cách chơi của nó: chỉ cần dùng các phím mũi tên để di chuyển nhân vật của mình (chiếc phi thuyền) né tránh các vật thể di chuyển ngẫu nhiên xung quanh.Điểm đặc biệt của trò chơi này là nó được xây dựng hoàn toàn dựa trên kĩ thuật HTML5 với tập lệnh canvas - một ví dụ mẫu JavaScript khá tốt để giúp chúng ta làm giúp chúng ta tiếp cận với kĩ thuật mới này.Hãy tìm hiểu thêm về canvas và HTML5 nếu bạn muốn thông qua các bài viết, hiệu ứng JavaScript khác trên jsB@nk: - JavaScript xoay ảnh với CANVAS trong HTML5 - Ứng dụng đồ họa tuyệt vời với HTML5 - Các hàm JavaScript mới trong HTML5 - 12 trò chơi JavaScript đầy sáng tạo bạn nên chơi

Phiên bản đầy đủ: jsB@nk » Trò chơi » Kĩ năng » Trò chơi tránh thiên thạch với HTML5 và JavaScript
URL: http://www.javascriptbank.com/creative-html5-javascript-asteroid-game.html



CSS
<style type="text/css"> /*     This script downloaded from www.JavaScriptBank.com     Come to view and download over 2000+ free javascript at www.JavaScriptBank.com*/* {  -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */  -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit *//* make transparent link selection, adjust last value opacity 0 to 1.0 */  -webkit-tap-highlight-color: rgba(0,0,0,0);   -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */  -webkit-tap-highlight-color: rgba(0,0,0,0); }body {  margin: 0px;}canvas {  display: block;  background-color: #113;}</style>


JavaScript
<script type="text/javascript">/*     This script downloaded from www.JavaScriptBank.com     Come to view and download over 2000+ free javascript at www.JavaScriptBank.com*/var Vector2 = function (x,y) {  this.x= x || 0;   this.y = y || 0; };Vector2.prototype = {  reset: function ( x, y ) {    this.x = x;    this.y = y;    return this;  },  toString : function (decPlaces) {     decPlaces = decPlaces || 3;     var scalar = Math.pow(10,decPlaces);     return "[" + Math.round (this.x * scalar) / scalar + ", " + Math.round (this.y * scalar) / scalar + "]";  },    clone : function () {    return new Vector2(this.x, this.y);  },    copyTo : function (v) {    v.x = this.x;    v.y = this.y;  },    copyFrom : function (v) {    this.x = v.x;    this.y = v.y;  },      magnitude : function () {    return Math.sqrt((this.x*this.x)+(this.y*this.y));  },    magnitudeSquared : function () {    return (this.x*this.x)+(this.y*this.y);  },    normalise : function () {        var m = this.magnitude();            this.x = this.x/m;    this.y = this.y/m;    return this;    },    reverse : function () {    this.x = -this.x;    this.y = -this.y;        return this;   },    plusEq : function (v) {    this.x+=v.x;    this.y+=v.y;        return this;   },    plusNew : function (v) {     return new Vector2(this.x+v.x, this.y+v.y);   },    minusEq : function (v) {    this.x-=v.x;    this.y-=v.y;        return this;   },  minusNew : function (v) {     return new Vector2(this.x-v.x, this.y-v.y);   },      multiplyEq : function (scalar) {    this.x*=scalar;    this.y*=scalar;        return this;   },    multiplyNew : function (scalar) {    var returnvec = this.clone();    return returnvec.multiplyEq(scalar);  },    divideEq : function (scalar) {    this.x/=scalar;    this.y/=scalar;    return this;   },    divideNew : function (scalar) {    var returnvec = this.clone();    return returnvec.divideEq(scalar);  },  dot : function (v) {    return (this.x * v.x) + (this.y * v.y) ;  },    angle : function (useRadians) {        return Math.atan2(this.y,this.x) * (useRadians ? 1 : Vector2Const.TO_DEGREES);      },    rotate : function (angle, useRadians) {        var cosRY = Math.cos(angle * (useRadians ? 1 : Vector2Const.TO_RADIANS));    var sinRY = Math.sin(angle * (useRadians ? 1 : Vector2Const.TO_RADIANS));      Vector2Const.temp.copyFrom(this);     this.x= (Vector2Const.temp.x*cosRY)-(Vector2Const.temp.y*sinRY);    this.y= (Vector2Const.temp.x*sinRY)+(Vector2Const.temp.y*cosRY);        return this;   },        equals : function (v) {    return((this.x==v.x)&&(this.y==v.x));  },    isCloseTo : function (v, tolerance) {      if(this.equals(v)) return true;        Vector2Const.temp.copyFrom(this);     Vector2Const.temp.minusEq(v);         return(Vector2Const.temp.magnitudeSquared() < tolerance*tolerance);  },    rotateAroundPoint : function (point, angle, useRadians) {    Vector2Const.temp.copyFrom(this);     //trace("rotate around point "+t+" "+point+" " +angle);    Vector2Const.temp.minusEq(point);    //trace("after subtract "+t);    Vector2Const.temp.rotate(angle, useRadians);    //trace("after rotate "+t);    Vector2Const.temp.plusEq(point);    //trace("after add "+t);    this.copyFrom(Vector2Const.temp);      },     isMagLessThan : function (distance) {    return(this.magnitudeSquared()<distance*distance);  },    isMagGreaterThan : function (distance) {    return(this.magnitudeSquared()>distance*distance);  }      // still AS3 to convert :   // public function projectOnto(v:Vector2) : Vector2  // {  //     var dp:Number = dot(v);  //   //     var f:Number = dp / ( v.x*v.x + v.y*v.y );  //   //     return new Vector2( f*v.x , f*v.y);  //   }  //   //   // public function convertToNormal():void  // {  //   var tempx:Number = x;   //   x = -y;   //   y = tempx;   //     //     // }      // public function getNormal():Vector2  // {  //     //   return new Vector2(-y,x);   //     // }  //   //   //   // public function getClosestPointOnLine ( vectorposition : Point, targetpoint : Point ) : Point  // {  //   var m1 : Number = y / x ;  //   var m2 : Number = x / -y ;  //     //   var b1 : Number = vectorposition.y - ( m1 * vectorposition.x ) ;  //   var b2 : Number = targetpoint.y - ( m2 * targetpoint.x ) ;  //     //   var cx : Number = ( b2 - b1 ) / ( m1 - m2 ) ;  //   var cy : Number = m1 * cx + b1 ;  //     //   return new Point ( cx, cy ) ;  // }  // };Vector2Const = {  TO_DEGREES : 180 / Math.PI,      TO_RADIANS : Math.PI / 180,  temp : new Vector2()  };(function () {var spareBullets = [];window.Bullet = function (ctx, x, y, angle) {  // this is rather nasty - so I'm not sure why I'm doing it...  if (this === window) {    if (spareBullets.length) {      var bullet = spareBullets.pop();      bullet.init(x, y, angle);      bullet.fresh = false;      return bullet;    } else {      return new Bullet(ctx, x, y, angle);    }  }    this.ctx = ctx;  // initialise  this.init(x, y, angle);  return this;};Bullet.prototype = {  init: function (x, y, angle) {    this.fresh = true;    this.pos = new Vector2(x,y);    this.vel = new Vector2(Bullet.speed,0);    this.vel.rotate(angle);    this.enabled = true;        // 15 is the length of the ship    this.pos.plusEq(this.vel.clone().normalise().multiplyEq(15));      },    checkEnabled: function ()  {    var ctx = this.ctx;        if (this.enabled == false) {      return;    }        if (this.pos.x < 0 || this.pos.x > ctx.canvas.width) this.enabled = false;    if (this.pos.y < 0 || this.pos.y > ctx.canvas.height) this.enabled = false;        if (this.enabled == false) {      spareBullets.push(this);    }  },    update: function () {    this.pos.plusEq(this.vel);         this.checkEnabled();    return this;      },    draw: function () {    var ctx = this.ctx,        pos = this.pos;            ctx.save();    ctx.lineWidth = 2;     ctx.strokeStyle = "#fff";     ctx.beginPath();     ctx.arc(pos.x, pos.y, 2, 0, Math.PI*2, true);     ctx.stroke();    ctx.restore();    return this;      }};// staticBullet.speed = 5;})();Asteroid = function (x,y,radius){  this.pos = new Vector2(x,y);   this.vel = new Vector2(0,0);     this.points;     this.enabled = true;       // temp vector to calculate distance from circle in hitTest  this.diff = new Vector2(0,0);     this.reset = function (radius) {    this.points = [];     this.radius = radius;         var temp = new Vector2(radius, 0);        for (var angle = 0; angle<360; angle+= random(0, 45)) {      temp.reset(random(radius / 2, radius),0);       temp.rotate(angle);            this.points.push(temp.clone());     }        };    this.reset(radius);     this.update = function(canvas) {        this.pos.plusEq(this.vel);     if(this.pos.x+this.radius < 0) this.pos.x = canvas.width+this.radius;     else if (this.pos.x-this.radius > canvas.width) this.pos.x = -this.radius;           if(this.pos.y+this.radius < 0) this.pos.y = canvas.height+this.radius;     else if (this.pos.y-this.radius > canvas.height) this.pos.y = -this.radius;           };    this.draw = function(ctx) {    ctx.save();     ctx.translate(this.pos.x, this.pos.y);     ctx.strokeStyle = "#fff";    ctx.fillStyle = '#000';    ctx.lineWidth = 2;     ctx.beginPath();       for(var i = 0; i<this.points.length; i++) {            var p = this.points[i % this.points.length];       ctx.lineTo(p.x, p.y);           }        ctx.closePath();     ctx.fill();    ctx.stroke();    ctx.restore();   };    this.hitTest = function(x,y) {        this.diff.copyFrom(this.pos);     this.diff.x-=x;     this.diff.y-=y;         var distanceSq = (this.diff.x * this.diff.x) + (this.diff.y*this.diff.y);    return distanceSq < (this.radius * this.radius);      };  };ShipMoving = function(x,y) {  this.pos = new Vector2(x,y);   this.angle = 0;   this.vel = new Vector2(0,0);   this.temp = new Vector2(0,0);     this.thrustPower = 0.1;   this.rotateSpeed = 5;     this.thrusting = false;  this.invulnerable = false;  this.thrustAmount = 0;    this.dead = [];    this.update = function() {    this.pos.plusEq(this.vel);   };    this.thrust = function() {    this.temp.reset(this.thrustPower,0);     this.temp.rotate(this.angle);     this.vel.plusEq(this.temp);   };    this.rotateLeft = function() {    this.angle -= this.rotateSpeed;   };    this.rotateRight = function() {    this.angle += this.rotateSpeed;   };    this.hit = function () {    var n = 20;    while (n--) {      this.dead.push(new Vector2(random(3, 6), 0));      this.dead[this.dead.length - 1].rotate(Math.random() * Math.PI * 2, true);    }  };    this.isdead = function () {    return !!this.dead.length;  };    this.draw = function(c) {        c.save();    c.translate(this.pos.x, this.pos.y);     c.rotate(this.angle * Vector2Const.TO_RADIANS);    if (this.invulnerable == false && !this.isdead()) {      c.lineWidth = 4;       if (this.thrustAmount) {        c.beginPath();        c.moveTo(-11, -3);        c.lineTo(-11, 3);        c.lineTo(-12 -this.thrustAmount, 0);        c.closePath();         c.fillStyle = 'hsla(3, 100%, 50%, 0.9)';        c.fill();              c.strokeStyle = 'hsla(32, 100%, 50%, 0.7)';        c.stroke();      }          c.lineWidth = 2;       c.strokeStyle = "#fff";           c.beginPath();      c.moveTo(-10, -10);      c.lineTo(-10, 10);      c.lineTo(14, 0);      c.closePath();       c.stroke();          } else if (this.dead.length) {      var i = this.dead.length;      c.lineWidth = 2;       c.fillStyle = 'hsla(1, 100%, 50%, 0.75)';       while (i--) {        this.dead[i].multiplyEq(1.05);        c.beginPath();        c.arc(this.dead[i].x, this.dead[i].y, 2, 0, Math.PI * 2, true);        c.closePath();         c.fill();      }    }        if (this.thrusting && this.thrustAmount < 10) {      this.thrustAmount++;    } else if (this.thrustAmount > 0) {      this.thrustAmount--;    }        c.restore();  };}; // canvas element and 2D contextvar canvas = document.createElement('canvas'),  c = canvas.getContext('2d'),  touch = 'createTouch' in document;canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas);c.strokeStyle = "#ffffff";var mouseX, mouseY,   halfWidth = canvas.width/2,   halfHeight = canvas.height/2,  bullets = [],  spareAsteroids = [],  ship = new ShipMoving(halfWidth, halfHeight),  thrusting = false,  rotateLeft = false,   rotateRight = false,  grad = c.createLinearGradient(0, 0, 0, canvas.height),  asteroids = [],  trail = 0.85;  grad.addColorStop(0, 'hsla(240,80%,2%,' + trail + ')');grad.addColorStop(1, 'hsla(240,100%,15%,' + trail + ')');timer = setInterval(draw, 1000/35); for (var i = 0; i < (touch ? 5 : 10); i++) {  asteroids.push(new Asteroid(random(0, canvas.width), random(0, canvas.height), 50));  asteroids[i].vel.reset(1,0).rotate(random(0,360));}function draw() {  c.fillStyle = '#000'; //grad;  c.fillRect(0,0,canvas.width, canvas.height);     var bullet;  for (var i=0; i<bullets.length; i++) {    bullet = bullets[i];    if (bullet.enabled) {      bullet.update();      bullet.draw();    }  }  for (i = 0; i < asteroids.length; i++) {      var asteroid = asteroids[i],         hit = false;        if (!ship.invulnerable && !ship.isdead() && asteroid.hitTest(ship.pos.x, ship.pos.y)) {      // you lose!      ship.hit();    }        if(!asteroid.enabled) continue;         if (!ship.isdead()) {      for (var j = 0; j < bullets.length; j++) {        if (bullets[j].enabled) {          hit = asteroid.hitTest(bullets[j].pos.x, bullets[j].pos.y);          if (hit) {            bullets[j].enabled = false;            break;          }                }      }          }        if (hit) {      if (asteroid.radius < 15) {        asteroid.enabled = false;       } else {        asteroid.reset(asteroid.radius/2);        asteroid.vel.reset(random(-5,5),random(-5,5));              makeNewAsteroid(asteroid.pos.x, asteroid.pos.y, asteroid.radius).vel.reset(random(-5,5),random(-5,5));        makeNewAsteroid(asteroid.pos.x, asteroid.pos.y, asteroid.radius).vel.reset(random(-5,5),random(-5,5));      }    } else {      asteroid.update(canvas);      asteroid.draw(c);     }  }  if (ship.thrusting) ship.thrust();   if (rotateLeft) ship.rotateLeft();   if (rotateRight) ship.rotateRight();   ship.update();   if (ship.pos.x<0) ship.pos.x = canvas.width;   else if (ship.pos.x>canvas.width) ship.pos.x = 0;  if (ship.pos.y<0) ship.pos.y = canvas.height;   else if (ship.pos.y>canvas.height) ship.pos.y = 0;   ship.draw(c);}function makeNewAsteroid(x, y, radius) {  var newasteroid;     if (spareAsteroids.length > 0) {    newasteroid = spareAsteroids.pop();     newasteroid.pos.set(x, y);     newasteroid.radius = radius;     } else {    newasteroid = new Asteroid(x, y, radius);     asteroids.push(newasteroid);   }    return newasteroid;}function fire() {  if (ship.isdead()) {    return;  }    // only allow n bullets  var limit = 5,      i = bullets.length;    while (i--) {    if (bullets[i].enabled) {      limit--;    }  }    if (limit !== 0) {    var bullet = Bullet(c, ship.pos.x, ship.pos.y, ship.angle);    if (bullet.fresh) bullets.push(bullet);      }  }canvas.addEventListener( 'mousemove', onMouseMove, false );document.addEventListener( 'keydown', onKeyDown, false );document.addEventListener( 'keyup', onKeyUp, false );document.addEventListener( 'touchstart', onTouchStart, false );document.addEventListener( 'touchmove', onTouchMove, false );document.addEventListener( 'touchend', onTouchEnd, false );var swipe = [];if (touch) {  ship.thrustPower = 0.5;}function onTouchStart(e) {  swipe = [];    if (e.touches.length == 1) {    // rotate & fire    var v = new Vector2(e.touches[0].pageX-canvas.width/2, e.touches[0].pageY-canvas.height/2);    ship.angle = v.angle();    fire();  } else if (e.touches.length == 2) {    ship.thrusting = true;    ship.thrust();  } else if (e.touches.length == 3) {    ship.invulnerable = true;  }}function onTouchMove(e) {  e.preventDefault();} // window.addEventListener('devicemotion', function(event) {//   var v = new Vector2(event.accelerationIncludingGravity.x, event.accelerationIncludingGravity.y);//   ship.angle += v.angle() * 0.05;// }, false);function onTouchEnd(e) {   ship.thrusting = false;  ship.invulnerable = false;} function onKeyDown(e) {    if(e.keyCode == 38) ship.thrusting = true;  else if (e.keyCode == 40) ship.invulnerable = true;  else if(e.keyCode == 37) rotateLeft = true;   else if (e.keyCode == 39) rotateRight = true;  else if (e.which == 32) fire();}function onKeyUp(e) {  if (e.keyCode == 38) ship.thrusting = false;  else if (e.keyCode == 40) ship.invulnerable = false;  else if(e.keyCode == 37) rotateLeft = false;   else if (e.keyCode == 39) rotateRight = false;}function onMouseMove(event) {  mouseX = event.offsetX;  mouseY = event.offsetY;}function random(v1, v2){  return ((Math.random()*(v2-v1))+v1);  }setTimeout(function () {  window.scrollTo(1, 0);}, 1000);</script>


HTML
<canvas height="609" width="1139"></canvas>


Files
/javascript/game/Creative_HTML5_and_JavaScript_Asteroid_Game/demo.html