HTML5 Canvas 逐帧动画的实现

和C++游戏开发相同,HTML5逐帧动画需要的图像元素也是一张绘制了每一帧图像效果的图片。通过循环绘制各帧的图像来实现动画的效果。

本示例中演示的是一个小人,默认状态下,小人朝右方站立;按下左/右方向键的时候,小人朝左/右方奔跑(在画布中没有位移);松开按键后保持奔跑的方向站立。

其中,向左或向右站立分别是一张6帧的图片,向左或向右奔跑分别是一张12帧的图片。

代码如下:

HTML代码:

[html]  view plain  copy
  1. <canvas id="canvas" width="600" height="400">  
  2.     <p>Your browser does not support the canvas element!</p>  
  3. </canvas>  
JavaScript代码如下:

以下这段代码已经在本人的博文中多次重用,所以就不解释了。

[javascript]  view plain  copy
  1. Array.prototype.remove = function(obj) {  
  2.     for (i in this) {  
  3.         if (this[i] === obj) {  
  4.             this.splice(i, 1);  
  5.         }  
  6.     }  
  7. }  
  8.   
  9. function BasicObject(x, y, order) {  
  10.     this.x = x;  
  11.     this.y = y;  
  12.     this.order = isNaN(order) ? 0 : order;  
  13.       
  14.     this.addTo = function(list) {  
  15.         list.push(this);  
  16.         list.sort(function(a, b) {return a.order - b.order;});  
  17.     }  
  18.       
  19.     this.removeFrom = function(list) {  
  20.         list.remove(this);  
  21.     }  
  22. }  
逐帧动画的基础对象,继承自基础对象类,添加了图像、总帧数两个属性,以及绘制逐帧对象的方法

[javascript]  view plain  copy
  1. function FrameAnimationObject(x, y, order, image, frame) {  
  2.     BasicObject.call(this, x, y, order);  
  3.     this.image = image;  
  4.     this.frame = frame;  
  5.     this.currentFrame = 0;  
  6.       
  7.     this.draw = function(context) {  
  8.         var sw = this.image.width / this.frame;  
  9.         var sx = this.currentFrame * sw;  
  10.         context.drawImage(this.image, sx, 0, sw, this.image.height, this.x, this.y, sw, this.image.height);  
  11.         this.currentFrame++;  
  12.         this.currentFrame = (this.currentFrame >= this.frame) ? 0 : this.currentFrame;  
  13.     }  
  14. }  
  15. FrameAnimationObject.prototype = new BasicObject();  

奔跑小人的类,继承自逐帧动画基础对象,指定了需求使用的图像资源,并添加了响应键盘事件的方法

[javascript]  view plain  copy
  1. function Person(x, y, order) {  
  2.     FrameAnimationObject.call(this, x, y, order);  
  3.     this.image = new Image();  
  4.     this.image.src = "stop_right.png"  
  5.     this.frame = 6;  
  6.       
  7.     this.onkeydown = function(event) {    
  8.         if (event.keyCode == 37) {    
  9.             this.image.src = "run_left.png";    
  10.             this.frame = 12;    
  11.         }    
  12.         else if (event.keyCode == 39) {    
  13.             this.image.src = "run_right.png";  
  14.             this.frame = 12;      
  15.         }    
  16.           
  17.         this.currentFrame = (this.currentFrame >= this.frame) ? 0 : this.currentFrame;    
  18.     }    
  19.         
  20.     this.onkeyup = function(event) {    
  21.         if (event.keyCode == 37) {    
  22.             this.image.src = "stop_left.png";    
  23.         }    
  24.         else if (event.keyCode == 39) {    
  25.             this.image.src = "stop_right.png";    
  26.         }    
  27.         this.frame = 6;    
  28.         this.currentFrame = (this.currentFrame >= this.frame) ? 0 : this.currentFrame;    
  29.     }    
  30. }  
  31. Person.prototype = new FrameAnimationObject();  

动画引擎类以及程序入口

[javascript]  view plain  copy
  1. function Engin() {  
  2.     var canvas = document.getElementById("canvas");  
  3.     var context = canvas.getContext("2d");  
  4.       
  5.     var buffer = document.createElement("canvas");  
  6.     buffer.width = canvas.width;  
  7.     buffer.height = canvas.height;  
  8.     var bufferCtx = buffer.getContext("2d");  
  9.       
  10.     var objs = new Array();  
  11.       
  12.     const FPS = 20;  
  13.       
  14.     this.manage = function() {  
  15.         bufferCtx.clearRect(0, 0, buffer.width, buffer.height);  
  16.         context.clearRect(0, 0, canvas.width, canvas.height);  
  17.           
  18.         for (x in objs) {  
  19.             if (objs[x].update) {  
  20.                 objs[x].update(objs);  
  21.             }  
  22.         }  
  23.           
  24.         for (x in objs) {  
  25.             if (objs[x].draw) {  
  26.                 objs[x].draw(bufferCtx);  
  27.             }  
  28.         }  
  29.           
  30.         context.drawImage(buffer, 0, 0);  
  31.     }  
  32.       
  33.     document.onkeydown = function(event) {  
  34.         for (x in objs) {  
  35.             if (objs[x].onkeydown) {  
  36.                 objs[x].onkeydown(event);  
  37.             }  
  38.         }  
  39.     }  
  40.       
  41.     document.onkeyup = function(event) {  
  42.         for (x in objs) {  
  43.             if (objs[x].onkeyup) {  
  44.                 objs[x].onkeyup(event);  
  45.             }  
  46.         }  
  47.     }  
  48.       
  49.     this.run = function() {  
  50.         var p = new Person(canvas.width / 2, canvas.height / 2);  
  51.         p.addTo(objs);  
  52.           
  53.         setInterval(this.manage, 1000 / FPS);  
  54.     }  
  55. }  
  56.   
  57. window.onload = function() {  
  58.     new Engin().run();  
  59. }  

需要说明的是,本次将键盘事件的响应放到了动画对象的类中来实现,并在引擎类中通过设定document的键盘事件来引用,这昂做事为了依照上一篇博文总所说的将动画对象的逻辑操作封装在最外层,同时避免了引擎类的过分膨胀。当动画对象逐渐增多时,效果更加明显。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值