0 Comments

使用JavaScript和Canvas写一个游戏框架(3)

发布于:2013-09-12  |   作者:广州网站建设  |   已聚集:人围观

下面来看一看draw函数。


  1. /**  
  2.     渲染循环  
  3. */  
  4. this.draw = function ()  
  5. {  
  6.     // 计算从上一帧到现在的时间  
  7.     var thisFrame = new Date().getTime();  
  8.     var dt = (thisFrame - this.lastFrame)/1000;  
  9.     this.lastFrame = thisFrame;  
  10.  
  11.     // 清理绘制上下文  
  12.     this.backBufferContext2D.clearRect(0, 0, this.backBuffer.width, this.backBuffer.height);  
  13.     this.context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);  
  14.  
  15.     // 首先更新所有游戏对象  
  16.     for (x in this.gameObjects)  
  17.     {  
  18.         if (this.gameObjects[x].update)  
  19.         {  
  20.             this.gameObjects[x].update(dt, this.backBufferContext2D, this.xScroll, this.yScroll);  
  21.         }  
  22.     }  
  23.  
  24.     // 然后绘制所有游戏对象  
  25.     for (x in this.gameObjects)  
  26.     {  
  27.         if (this.gameObjects[x].draw)  
  28.         {  
  29.             this.gameObjects[x].draw(dt, this.backBufferContext2D, this.xScroll, this.yScroll);  
  30.         }  
  31.     }  
  32.  
  33.     // 将后台缓冲复制到当前显示的画布  
  34.     this.context2D.drawImage(this.backBuffer, 0, 0);  
  35. };  

这个draw函数就是所有渲染循环的核心。在前面的例子中,渲染循环的函数会直接修改要绘制到屏幕上的对象(笑脸)。如果只需绘制一个对象,这样做没有问题。但是,一个游戏要由几十个单独的对象组成,所以这个draw函数并没有直接在渲染循环中直接处理要绘制的对象,而是维护了一个保存着这些对象的数组,让这些对象自己来更新和绘制自己。

首先,计算自上一帧渲染所经过的时间。即便我们在代码里写了每秒钟调用30次draw函数,但谁也无法保证事实如此。通过计算自上一帧渲染所经过的时间,可以做到尽可能让游戏的执行与帧速率无关。


  1. // 计算从上一帧到现在的时间  
  2. var thisFrame = new Date().getTime();  
  3. var dt = (thisFrame - this.lastFrame)/1000;  
  4. this.lastFrame = thisFrame;  

接着清理绘制上下文。
广州网站建设,网站建设,广州网页设计,广州网站设计


  1. // 清理绘制上下文  
  2. this.backBufferContext2D.clearRect(0, 0, this.backBuffer.width, this.backBuffer.height);  
  3. this.context2D.clearRect(0, 0, this.canvas.width, this.canvas.height);  

然后,就是调用游戏对象(这些对象是由GameObject类定义的,下一篇文章将介绍该类)自己的更新(update)和绘制(draw)方法。注意,这两个方法是可选的(这也是我们在调用它们之前先检查它们是否存在的原因),但差不多每一个对象都需要更新和绘制自已。


  1. // 首先更新所有游戏对象  
  2. for (x in this.gameObjects)  
  3. {  
  4.     if (this.gameObjects[x].update)  
  5.     {  
  6.         this.gameObjects[x].update(dt, this.backBufferContext2D, this.xScroll, this.yScroll);  
  7.     }  
  8. }  
  9.  
  10. // 然后绘制所有游戏对象  
  11. for (x in this.gameObjects)  
  12. {  
  13.     if (this.gameObjects[x].draw)  
  14.     {  
  15.         this.gameObjects[x].draw(dt, this.backBufferContext2D, this.xScroll, this.yScroll);  
  16.     }  
  17. }  

最后,把后台缓冲复制到前台缓冲,最终用户就可以看到下一帧了。


  1. // 将后台缓冲复制到当前显示的画布  
  2. this.context2D.drawImage(this.backBuffer, 0, 0);  

理解了draw函数,下面再分别讲一讲addGameObject和removeGameObject函数。
广州网站建设,网站建设,广州网页设计,广州网站设计


  1. /**  
  2.     向gameObjects集合中添加一个GameObject  
  3.     @param gameObject The object to add  
  4. */  
  5. this.addGameObject = function(gameObject)  
  6. {  
  7.     this.gameObjects.push(gameObject);  
  8.     this.gameObjects.sort(function(a,b){return a.zOrder - b.zOrder;})  
  9. };  
  10.  
  11. /**  
  12.     从gameObjects集合中删除一个GameObject  
  13.     @param gameObject The object to remove  
  14. */  
  15. this.removeGameObject = function(gameObject)  
  16. {  
  17.     this.gameObjects.removeObject(gameObject);  
  18. }  

利用addGameObject和removeGameObject(在Utils.js文件里通过扩展Array.prototype添加)函数,可以在GameObjectManager所维护的GameObject集合(即gameObjects变量)中添加和删除游戏对象。

GameObjectManager类是我们这个游戏框架中最复杂的一个类。在下一篇文章中,我们会讲解游戏框架的另外几个类:GameObject、VisualGameObject、Bounce和ApplicationManager。

好了,现在放松一下,看一看Demo吧

原文:http://www.brighthub.com/content/matthewcaspersonshubfoliohasmoved.aspx

译文:http://www.cn-cuckoo.com/2011/08/14/game-development-with-javascript-and-the-canvas-element-3-2604.html

标签:
飞机