8.6 创建Controller类
现在,我们已经有了游戏中的所有图像和类,接下来的工作是构建游戏引擎。Canvas Hero游戏使用标准的MVC架构进行构建,MVC架构使数据、表示和控制分离。本节,我们将创建Controller类,它负责实例化模型和视图,初始化游戏,控制游戏状态,并管理键盘事件。
操作步骤
按照以下步骤,创建Canvas Hero游戏的控制器:
1. 定义Controller类的构造函数:
/* 游戏控制器
*
* 控制器负责实例化模型和视图,初始化游戏,
* 控制游戏状态,并管理键盘事件
*/
function Controller(canvasId){
this.imageSources = {
levelBounds: "img/level_bounds.png",
level: "img/level.png",
heroSprites: "img/hero_sprites.png",
heroHitSprites: "img/hero_hit_sprites.png",
badGuySprites: "img/bad_guy_sprites.png",
badGuyHitSprites: "img/bad_guy_hit_sprites.png",
background: "img/background.png",
readyScreen: "img/readyScreen.png",
gameoverScreen: "img/gameoverScreen.png",
winScreen: "img/winScreen.png"
};
this.images = {};
this.states = {
INIT: "INIT",
READY: "READY",
PLAYING: "PLAYING",
WON: "WON",
GAMEOVER: "GAMEOVER"
};
this.keys = {
ENTER: 13,
UP: 38,
LEFT: 37,
RIGHT: 39,
A: 65
};
this.anim = new Animation(canvasId);
this.state = this.states.INIT;
this.model = new Model(this);
this.view = new View(this);
this.avgFps = 0;
this.leftKeyup = true;
this.rightKeyup = true;
this.addKeyboardListeners();
this.loadImages();
}
2. 定义loadImages()方法,该方法加载游戏的所有图像,并在图像全部加载完成后调用initGame()方法初始化游戏:
Controller.prototype.loadImages = function(){
/* 我们需要先加载“loading”图像,并把它插入到DOM中,
* 然后,再加载其它的图像
*/
this.view.canvas.style.background = "url('img/loadingScreen. png')";
var that = this;
var loadedImages = 0;
var numImages = 0;
for (var src in this.imageSources) {
numImages++;
}
for (var src in this.imageSources) {
this.images[src] = new Image();
this.images[src].onload = function(){
if (++loadedImages >= numImages) {
that.initGame();
}
};
this.images[src].src = this.imageSources[src];
}
};
3. 定义addKeyboardListeners()方法,该方法为游戏附加键盘事件监听器:
Controller.prototype.addKeyboardListeners = function(){
var that = this;
document.onkeydown = function(evt){
that.handleKeydown(evt);
};
document.onkeyup = function(evt){
that.handleKeyup(evt);
};
};
4. 定义handleKeyUp()方法,当某个键被释放时,会调用该方法:
Controller.prototype.handleKeyup = function(evt){
keycode = ((evt.which) || (evt.keyCode));
switch (keycode) {
case this.keys.LEFT:
this.leftKeyup = true;
if (this.leftKeyup && this.rightKeyup) {
this.model.hero.stop();
}
break;
case this.keys.UP:
break;
case this.keys.RIGHT:
this.rightKeyup = true;
if (this.leftKeyup && this.rightKeyup) {
this.model.hero.stop();
}
break;
}
};
5. 定义handleKeyDown()方法,当某个键被按下时,会调用该方法:
Controller.prototype.handleKeydown = function(evt){
var that = this;
keycode = ((evt.which) || (evt.keyCode));
switch (keycode) {
case this.keys.ENTER: //回车键
if (this.state == this.states.READY) {
this.state = this.states.PLAYING;
//启动游戏
this.anim.start();
}
else if (this.state == this.states.GAMEOVER || this.state == this.states.WON) {
this.resetGame();
this.state = this.states.PLAYING;
}
break;
case this.keys.LEFT:
this.leftKeyup = false;
this.model.hero.moveLeft();
break;
case this.keys.UP:
this.model.hero.jump();
break;
case this.keys.RIGHT:
this.rightKeyup = false;
this.model.hero.moveRight();
break;
case this.keys.A: // attack 攻击
var model = this.model;
var hero = model.hero;
hero.attack();
setTimeout(function(){
for (var n = 0; n < model.badGuys.length; n++) {
(function(){
var badGuy = model.badGuys[n];
if (model.nearby(hero, badGuy)
&& ((badGuy.x - hero.x > 0 && hero.isFacingRight())
|| (hero.x - badGuy.x > 0 && !hero.isFacingRight()))) {
badGuy.damage();
}
})();
}
}, 200);
break;
}
};
6. 定义initGame()方法,该方法初始化游戏:
Controller.prototype.initGame = function(){
var model = this.model;
var view = this.view;
model.initLevel();
model.initHero();
model.initBadGuys();
model.initHealthBar();
//设置stage方法
this.anim.setStage(function(){
model.updateStage();
view.stage();
});
//现在,游戏准备装备就绪
this.state = this.states.READY;
view.drawScreen(this.images.readyScreen);
};
7. 定义resetGame()方法,该方法通过重新初始化游戏的相关对象来重置游戏:
Controller.prototype.resetGame = function(){
var model = this.model;
model.level = null;
model.hero = null;
model.healthBar = null;
model.badGuys = [];
model.initLevel();
model.initHero();
model.initBadGuys();
model.initHealthBar();
};
工作原理
游戏控制器最重要的作用,是通过游戏的状态来控制游戏的流程。在Canvas Hero游戏中,游戏的第一个状态是加载状态,在该状态下,玩家可以在游戏加载过程中,阅读如何玩该游戏。一旦游戏加载完成,控制器负责把游戏的状态转换到就绪状态,在该状态中,游戏等待玩家按回车键继续。一旦玩家按下回车键,控制器把游戏的状态转换到玩游戏状态。
此时此刻,游戏就真正开始,并且玩家对英雄有完全的控制权。如果玩家的生命值降到0,或掉入坑中,控制器将把游戏的状态转换到游戏结束状态。话又说回来,如果玩家成功击败所有敌人,控制器将把游戏的状态转换到游戏获胜状态,并祝贺玩家超棒的技艺。游戏的状态机如下图所示:
除了控制游戏状态之外,控制器也负责管理键盘事件。通过addKeyboardListeners()方法来附加键盘事件。