Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【译】html5游戏入门 #33

Open
fakefish opened this issue Oct 23, 2013 · 0 comments
Open

【译】html5游戏入门 #33

fakefish opened this issue Oct 23, 2013 · 0 comments
Labels

Comments

@fakefish
Copy link
Owner

【译】html5游戏入门

原文链接

简介

如果你想用canvas做个游戏,那么来对地方了。

但是但是你至少知道javascript怎么拼写(╯‵□′)╯︵┻━┻

既然没问题,那先来一下或者下载

创建canvas标签

废话不多说,我们必须创建一个canvas标签,简单起见,用一下不喜欢的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');

游戏循环

为了能够让游戏平滑动画,我们用30帧的频率。

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

现在我们可以先给这两个函数放置play,重要的是setInterval函数会定期照顾他们的。

hello world

现在我们有了这个循环,让我们开始画东西吧~

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);
}

现在如果没出错,那么字母应该在移动,但是有残影出现。想想为什么会这样,因为我们没有清除之前的画面呢,so 我们加点清除画布的代码。

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

现在可以看到字母在屏幕上移动了,恭喜你,你已经快入门了。让我们继续。

创建玩家

接下来创建一个物体用来给玩家控制,我们创建了一个简单的object:

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);
  }
};

我们简单地着色了这个物体,当我们清除画布的时候,画上这个物体。

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

键盘控制

使用jQuery HotKeys

使用jQuery HotKeys,这个插件提供了简单的键盘输入检测
我们可以这么绑定事件

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

不用想哪个按键是哪个号码真舒服,我们刚才实现了“当玩家按上的时候,做一些事情”,碉堡的插件!

玩家的移动

键盘输入检测已经完成了,但我们还要处理键盘输入之后要做什么。
你可能会想使用事件驱动的方式去处理键盘输入,但是这样做系统不一,按键效果不一样,而且脱离了动画循环呢,这样做就可以跨系统了,保证了一致性,也让游戏更平滑了。

有一个好消息,我们有一个key_status.js的文件,提供了类似keydown.left等等。去下载的文件里找

现在我们可以去查询是否有按键了,然后我们就这么写:

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);
}

clamp这个函数可以在下载的util.js里看到

然后我们加点炮弹进去。

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
  };
};

我们需要把子弹的动画添加到没帧的动画里,为了能让子弹变成无限的效果,我们过滤了子弹数组,只保留了激活的子弹.同时删除了已经撞到敌人的子弹.

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();
  });
}

加载和添加图片

虽然目前这些方块飞来飞去看起来很酷,但有图片就更酷了。我们使用了一个叫sprite.js的文件,可以从下载的文件里看到。

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);
  };

  ...
}

碰撞检测

我们已经有了很多敌人飞来飞去了,但他们没有交互呢mb打不到他们,我们是时候加点碰撞检测了.
让我们使用一个简单的方法检测:

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;
}

我们需要检测如下两种碰撞:

  1. 玩家子弹和敌方飞船
  2. 玩家和敌方飞船

让我们给update加入处理碰撞之后的处理

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
};

声音

为了可玩性,我们将要添加声音效果进去,我们用到sound.js这个文件,让事情变得非常简单。

player.shoot = function() {
  Sound.play("shoot");
  ...
}

function Enemy(I) {
  ...

  I.explode = function() {
    Sound.play("explode");
    ...
  }
}

使用这些API就能很快地完成一个简单的游戏.

告别

再说一下游戏地址,也可以下载

well,我希望你开始喜欢用js和html5写简单的游戏,随着学习的深入,将来会有更多地挑战呢.

参考文献

HTML5 Canvas Cheat Sheet
HTML5 Game Engines

译后感

第一次完整的翻译一篇文章,真蛋疼有些句子感觉不好翻,就随便糊弄一下,BTW,我也按这个教程写了例子,好像写完还有很多问题呢(逃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant