1. 程式人生 > >HTML5遊戲製作完全指南

HTML5遊戲製作完全指南

簡介

建立畫布

遊戲迴圈

Hello world

建立player

鍵盤控制

         a:使用jQuery Hotkeys

         b:移動player

新增更多遊戲元素

炮彈

敵人

使用圖片

碰撞檢測

聲音

 

 

簡介

你想使用HTML5的Canvas製作一款遊戲嗎?跟著這個教程,你將立刻上道兒。

閱讀該教程需要至少熟悉javascript相關知識。

你可以先玩這款遊戲或者直接閱讀文章並且下載遊戲原始碼

如果有想一起學習web前端,HTML5及JavaScript的可以來一下我的前端群733581373,好友都會在裡面交流,分享一些學習的方法和需要注意的小細節,每天也會準時的講一些前端的炫酷特效,及前端直播課程學習

建立畫布

在畫任何東西之前,我們必須建立一個畫布。因為這是完全指南,並且我們將用到jQuery.

var CANVAS_WIDTH = 480;
var CANVAS_HEIGHT = 320;

var canvasElement = $("<canvas width='" + CANVAS_WIDTH + 
                      "' height='" + CANVAS_HEIGHT + "'></canvas>");
var canvas = canvasElement.get(0).getContext("2d");
canvasElement.appendTo('body');

 

遊戲迴圈

為了呈現給玩家連貫流暢的遊戲動畫,我們要頻繁地渲染畫布來欺騙玩家的眼睛。

var FPS = 30;
setInterval(function() {
  update();
  draw();
}, 1000/FPS);

現在我們先不管update和draw裡面的實現,重要的是我們要知道setInterval()會週期性的執行update和draw

 

Hello world

現在我們已經搭建好了一個迴圈的架子,我們去修改update和draw方法來寫一些文字到螢幕。

function draw() {
  canvas.fillStyle = "#000"; // Set color to black
  canvas.fillText("Sup Bro!", 50, 50);
}

專家提醒: 當你稍微更改了一些程式碼的時候就執行一下程式,這樣可以更快的找到程式出錯地方。

靜止文字正常的顯示出來了。因為我們已經有了迴圈,所以我們可以很容易地讓文字動起來~~~

var textX = 50;
var textY = 50;

function update() {
  textX += 1;
  textY += 1;
}

function draw() {
  canvas.fillStyle = "#000";
  canvas.fillText("Sup Bro!", textX, textY);
}

執行程式。如果你一步一步照著上面做下來,可以看到文字移動。但是上一次的文字卻還留在螢幕上,因為我們沒有擦除畫布。現在我們在draw方法中加入擦除方法。

function draw() {
  canvas.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  canvas.fillStyle = "#000";
  canvas.fillText("Sup Bro!", textX, textY);
}

現在你可以看到文字在螢幕上移動了,它已經算是一個真正意義上的遊戲,只不過是個半成品。

 

建立player

建立一個包含player所有資訊的物件,並且要有draw方法。這裡建立了一個簡單的物件包含了所有的player資訊。

var player = {
  color: "#00A",
  x: 220,
  y: 270,
  width: 32,
  height: 32,
  draw: function() {
    canvas.fillStyle = this.color;
    canvas.fillRect(this.x, this.y, this.width, this.height);
  }
};

我們現在用一個純色的矩形來代表player.當我們把它加入遊戲當中的時候,我們需要清除畫布並且畫上player.

function draw() {
  canvas.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  player.draw();
}

 

鍵盤控制

使用jQuery Hotkeys

jQuery Hotkeys plugin在處理鍵盤行為的時候,可以更加容易的相容不同的瀏覽器。讓開發者不用因為不同瀏覽器之間的keyCode andcharCode不同而苦惱,我們這樣繫結事件:

$(document).bind("keydown", "left", function() { ... });

移動player

function update() {
  if (keydown.left) {
    player.x -= 2;
  }

  if (keydown.right) {
    player.x += 2;
  }
}

是不是感覺移動不夠快?那麼我們來提高它的移動速度。

function update() {
  if (keydown.left) {
    player.x -= 5;
  }

  if (keydown.right) {
    player.x += 5;
  }

  player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
}

我們可以很容易的新增其他元素,比如炮彈:

function update() {
  if (keydown.space) {
    player.shoot();
  }

  if (keydown.left) {
    player.x -= 5;
  }

  if (keydown.right) {
    player.x += 5;
  }

  player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
}

player.shoot = function() {
  console.log("Pew pew");
  // :) Well at least adding the key binding was easy...
};

 

新增更多遊戲元素

炮彈

我們開始真正意義上的新增炮彈,首先,我們需要一個集合來儲存它:

var playerBullets = [];

然後,我們需要一個構造器來建立炮彈:

function Bullet(I) {
  I.active = true;

  I.xVelocity = 0;
  I.yVelocity = -I.speed;
  I.width = 3;
  I.height = 3;
  I.color = "#000";

  I.inBounds = function() {
    return I.x >= 0 && I.x <= CANVAS_WIDTH &&
      I.y >= 0 && I.y <= CANVAS_HEIGHT;
  };

  I.draw = function() {
    canvas.fillStyle = this.color;
    canvas.fillRect(this.x, this.y, this.width, this.height);
  };

  I.update = function() {
    I.x += I.xVelocity;
    I.y += I.yVelocity;

    I.active = I.active && I.inBounds();
  };

  return I;
}

當玩家開火,我們需要向集合中新增炮彈:

player.shoot = function() {
  var bulletPosition = this.midpoint();

  playerBullets.push(Bullet({
    speed: 5,
    x: bulletPosition.x,
    y: bulletPosition.y
  }));
};

player.midpoint = function() {
  return {
    x: this.x + this.width/2,
    y: this.y + this.height/2
  };
};

修改update和draw方法,實現開火:

function update() {
  ...
  playerBullets.forEach(function(bullet) {
    bullet.update();
  });

  playerBullets = playerBullets.filter(function(bullet) {
    return bullet.active;
  });
}
function draw() {
  ...
  playerBullets.forEach(function(bullet) {
    bullet.draw();
  });
}

敵人

  enemies = [];

function Enemy(I) {
  I = I || {};

  I.active = true;
  I.age = Math.floor(Math.random() * 128);

  I.color = "#A2B";

  I.x = CANVAS_WIDTH / 4 + Math.random() * CANVAS_WIDTH / 2;
  I.y = 0;
  I.xVelocity = 0
  I.yVelocity = 2;

  I.width = 32;
  I.height = 32;

  I.inBounds = function() {
    return I.x >= 0 && I.x <= CANVAS_WIDTH &&
      I.y >= 0 && I.y <= CANVAS_HEIGHT;
  };

  I.draw = function() {
    canvas.fillStyle = this.color;
    canvas.fillRect(this.x, this.y, this.width, this.height);
  };

  I.update = function() {
    I.x += I.xVelocity;
    I.y += I.yVelocity;

    I.xVelocity = 3 * Math.sin(I.age * Math.PI / 64);

    I.age++;

    I.active = I.active && I.inBounds();
  };

  return I;
};

function update() {
  ...

  enemies.forEach(function(enemy) {
    enemy.update();
  });

  enemies = enemies.filter(function(enemy) {
    return enemy.active;
  });

  if(Math.random() < 0.1) {
    enemies.push(Enemy());
  }
};

function draw() {
  ...

  enemies.forEach(function(enemy) {
    enemy.draw();
  });
}

 

使用圖片

player.sprite = Sprite("player");

player.draw = function() {
  this.sprite.draw(canvas, this.x, this.y);
};

function Enemy(I) {
  ...

  I.sprite = Sprite("enemy");

  I.draw = function() {
    this.sprite.draw(canvas, this.x, this.y);
  };

  ...
}

 

碰撞檢測

function collides(a, b) {
  return a.x < b.x + b.width &&
         a.x + a.width > b.x &&
         a.y < b.y + b.height &&
         a.y + a.height > b.y;
}
function handleCollisions() {
  playerBullets.forEach(function(bullet) {
    enemies.forEach(function(enemy) {
      if (collides(bullet, enemy)) {
        enemy.explode();
        bullet.active = false;
      }
    });
  });

  enemies.forEach(function(enemy) {
    if (collides(enemy, player)) {
      enemy.explode();
      player.explode();
    }
  });
}

function update() {
  ...
  handleCollisions();
}
function Enemy(I) {
  ...

  I.explode = function() {
    this.active = false;
    // Extra Credit: Add an explosion graphic
  };

  return I;
};

player.explode = function() {
  this.active = false;
  // Extra Credit: Add an explosion graphic and then end the game
};

 

加入聲音

function Enemy(I) {
  ...

  I.explode = function() {
    this.active = false;
    // Extra Credit: Add an explosion graphic
  };

  return I;
};

player.explode = function() {
  this.active = false;
  // Extra Credit: Add an explosion graphic and then end the game
};

DNT磚家提醒: 跟著上面的步驟,大概讓大家瞭解了一款遊戲的各種元素的製作過程,這類遊戲做一遍就夠,沒有必要做第二遍,沒有很難的演算法,全是流程和經驗性質的東西,倘若想做好看,做炫一點,那就是美工拼了老命切圖的事情,或者開發人員介入做一些效能優化和碰撞優化。最後重複一遍----看過就好,不要當寶。

最後,如果有想一起學習web前端,HTML5及JavaScript的可以來一下我的前端群733581373,好友都會在裡面交流,分享一些學習的方法和需要注意的小細節,每天也會準時的講一些前端的炫酷特效,及前端直播課程學習

如果想看到更加系統的文章和學習方法經驗可以關注的微訊號:‘web前端技術圈’或者‘webxh6’關注後回覆‘2018’可以領取一套完整的學習視訊