当前位置: 首页 > 文档资料 > HTML5 Canvas 实战 >

8.6 创建Controller类

优质
小牛编辑
125浏览
2023-12-01

现在,我们已经有了游戏中的所有图像和类,接下来的工作是构建游戏引擎。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,或掉入坑中,控制器将把游戏的状态转换到游戏结束状态。话又说回来,如果玩家成功击败所有敌人,控制器将把游戏的状态转换到游戏获胜状态,并祝贺玩家超棒的技艺。游戏的状态机如下图所示:

游戏的状态机
图8-11 游戏的状态机

除了控制游戏状态之外,控制器也负责管理键盘事件。通过addKeyboardListeners()方法来附加键盘事件。