最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

HTML5游戏框架cnGameJS开发实录-实现动画原理

来源:动视网 责编:小采 时间:2020-11-27 15:10:27
文档

HTML5游戏框架cnGameJS开发实录-实现动画原理

HTML5游戏框架cnGameJS开发实录-实现动画原理: 在游戏中,游戏角色的动画效果是一个游戏必不可少的一部分。这节我们以构造超级马里奥的角色为例,讲解cnGameJS里动画的实现。1.原理: 一个动画如果要实现一连串动作,我们可以把每个动作的快照保留起来,并放在一个大图上面,然后每次帧更新的时候,就在
推荐度:
导读HTML5游戏框架cnGameJS开发实录-实现动画原理: 在游戏中,游戏角色的动画效果是一个游戏必不可少的一部分。这节我们以构造超级马里奥的角色为例,讲解cnGameJS里动画的实现。1.原理: 一个动画如果要实现一连串动作,我们可以把每个动作的快照保留起来,并放在一个大图上面,然后每次帧更新的时候,就在
  

 在游戏中,游戏角色的动画效果是一个游戏必不可少的一部分。这节我们以构造超级马里奥的角色为例,讲解cnGameJS里动画的实现。

1.原理:

  一个动画如果要实现一连串动作,我们可以把每个动作的快照保留起来,并放在一个大图上面,然后每次帧更新的时候,就在每个动作的快照之间循环显示,最终得出一个动画。因此我们首先要准备一个类似下面的这种图片:

  看到不?把每个动作放在图片的不同位置上,之后就可以通过改变显示位置实现动画效果了。

  当cnGameJS调用start方法开始游戏后,将会调用传入的gameObj的initialize方法进行初始化,并且生成一个游戏循环,循环里每次调用gameObj的update和draw方法。因此我们可以把动画的初始化放在gameObj的initialize中,update和draw分别放在gameObj的update和draw中,实现动画播放。

效果:

代码:

<body>
<canvas id="gameCanvas">请使用支持canvas的浏览器查看</canvas>
</body>
<script src="http://files.cnblogs.com/Cson/cnGame_v1.0.js"></script>
<script>
var Src="http://pic002.cnblogs.com/images/2012/273330/2012021312050269.png";
/* 初始化 */
cnGame.init('gameCanvas',{width:50,height:60});
var gameObj={
 initialize:function(){
 this.marie=cnGame.SpriteSheet("marie",Src,{frameSize:[50,60],width:150,height:60,loop:true});
 },
 update:function(){
 this.marie.update();
 },
 draw:function(){
 this.marie.draw();
 }

}
cnGame.loader.start([Src],gameObj);
</script>

2.实现

  正如上面看到的,我们只需要用很少的代码量,就可以实现一个帧动画的播放,接下来将介绍cnGameJS里的帧动画是怎样封装的。

  大家很容易可以发现,cnGameJS都遵循一个特定的模式,把对象的阶段分为三个:initialize(初始化),update(帧更新)和draw(绘制)。这样我们可以很方便地把不同功能的代码写在对应的阶段内。spriteSheet帧动画也不例外,同样按照这种模式来写。

  初始化:用户对一些必要的信息进行设定。

spriteSheet.prototype={
 /**
 *初始化
 **/
 init:function(id,src,options){
 
 /**
 *默认对象
 **/ 
 var defaultObj={
 x:0,
 y:0,
 width:120,
 height:40,
 frameSize:[40,40],
 frameDuration:100,
 direction:"right", //从左到右
 beginX:0,
 beginY:0,
 loop:false,
 bounce:false 
 };
 options=options||{};
 options=cg.core.extend(defaultObj,options);
 this.id=id; //spriteSheet的id
 this.src=src; //图片地址
 this.x=options.x; //动画X位置
 this.y=options.y; //动画Y位置
 this.width=options.width; //图片的宽度
 this.height=options.height; //图片的高度
 this.image=cg.loader.loadedImgs[this.src]; //图片对象
 this.frameSize=options.frameSize; //每帧尺寸
 this.frameDuration=options.frameDuration; //每帧持续时间
 this.direction=options.direction; //读取帧的方向(从做到右或从上到下)
 this.currentIndex=0; //目前帧索引
 this.beginX=options.beginX; //截取图片的起始位置X
 this.beginY=options.beginY; //截图图片的起始位置Y
 this.loop=options.loop; //是否循环播放
 this.bounce=options.bounce; //是否往返播放
 this.onFinsh=options.onFinsh; //播放完毕后的回调函数
 this.frames=caculateFrames(options); //帧信息集合
 this.now=new Date().getTime(); //当前时间
 this.last=new Date().getTime(); //上一帧开始时间
 },

  上面的参数比较多,都是一些对帧动画属性的预设置。需要注意的是我们调用了私有方法caculateFrames来计算每个帧的信息,并保存到frames内,为帧绘制做准备。

  帧更新:

  在每一帧的更新过程中,我们首先获取当前时间作为帧的开始时间,并且和上一次帧的开始时间相减,就得出上一次帧的用时。如果用时超过之前设置的每帧的用时,则可以进行帧更新。然后判断是否循环或者往返播放动画,按情况更新对应的帧索引。在最终确定帧的索引后,就可以从frames数组中获取该帧的信息,并返回。

/**
 *更新帧
 **/ 
 update:function(){
 
 this.now=new Date().getTime();
 var frames=this.frames;
 if((this.now-this.last)>this.frameDuration){//如果间隔大于帧间间隔,则update
 var currentIndex=this.currentIndex;
 var length=this.frames.length;
 this.last=this.now;
 
 if(currentIndex>=length-1){
 if(this.loop){ //循环
 return frames[this.currentIndex=0]; 
 }
 else if(!this.bounce){//没有循环并且没有往返滚动,则停止在最后一帧
 this.onFinsh&&this.onFinsh();
 this.onFinsh=undefined;
 return frames[currentIndex];
 }
 }
 if((this.bounce)&&((currentIndex>=length-1&&path>0)||(currentIndex<=0&&path<0))){ //往返
 path*=(-1);
 }
 this.currentIndex+=path;
 
 }
 return frames[this.currentIndex];
 },

  帧绘制:

  在帧更新后,已经获取到当前帧的索引,因此draw方法就可以从保存所有帧信息的frames获取到当前帧的信息(包括图像截取的起始位置等),从而在指定位置截取大图片,并画出该图片区域的图像:

/**
 *在特定位置绘制该帧
 **/
 draw:function(){
 
 var currentFrame=this.getCurrentFrame();
 var width=this.frameSize[0];
 var height=this.frameSize[1];
 cg.context.drawImage(this.image,currentFrame.x,currentFrame.y,width,height,this.x,this.y,width,height);
 }

最后,还提供跳到特定帧等方法。

动画模块所有源码:

/**
 *包含多帧图像的大图片
 **/ 
 spriteSheet=function(id,src,options){
 if(!(this instanceof arguments.callee)){
 return new arguments.callee(id,src,options);
 }
 this.init(id,src,options);
 }
 spriteSheet.prototype={
 /**
 *初始化
 **/
 init:function(id,src,options){
 
 /**
 *默认对象
 **/ 
 var defaultObj={
 x:0,
 y:0,
 width:120,
 height:40,
 frameSize:[40,40],
 frameDuration:100,
 direction:"right", //从左到右
 beginX:0,
 beginY:0,
 loop:false,
 bounce:false 
 };
 options=options||{};
 options=cg.core.extend(defaultObj,options);
 this.id=id; //spriteSheet的id
 this.src=src; //图片地址
 this.x=options.x; //动画X位置
 this.y=options.y; //动画Y位置
 this.width=options.width; //图片的宽度
 this.height=options.height; //图片的高度
 this.image=cg.loader.loadedImgs[this.src]; //图片对象
 this.frameSize=options.frameSize; //每帧尺寸
 this.frameDuration=options.frameDuration; //每帧持续时间
 this.direction=options.direction; //读取帧的方向(从做到右或从上到下)
 this.currentIndex=0; //目前帧索引
 this.beginX=options.beginX; //截取图片的起始位置X
 this.beginY=options.beginY; //截图图片的起始位置Y
 this.loop=options.loop; //是否循环播放
 this.bounce=options.bounce; //是否往返播放
 this.onFinsh=options.onFinsh; //播放完毕后的回调函数
 this.frames=caculateFrames(options); //帧信息集合
 this.now=new Date().getTime(); //当前时间
 this.last=new Date().getTime(); //上一帧开始时间
 },
 /**
 *更新帧
 **/ 
 update:function(){
 
 this.now=new Date().getTime();
 var frames=this.frames;
 if((this.now-this.last)>this.frameDuration){//如果间隔大于帧间间隔,则update
 var currentIndex=this.currentIndex;
 var length=this.frames.length;
 this.last=this.now;
 
 if(currentIndex>=length-1){
 if(this.loop){ //循环
 return frames[this.currentIndex=0]; 
 }
 else if(!this.bounce){//没有循环并且没有往返滚动,则停止在最后一帧
 this.onFinsh&&this.onFinsh();
 this.onFinsh=undefined;
 return frames[currentIndex];
 }
 }
 if((this.bounce)&&((currentIndex>=length-1&&path>0)||(currentIndex<=0&&path<0))){ //往返
 path*=(-1);
 }
 this.currentIndex+=path;
 
 }
 return frames[this.currentIndex];
 },
 /**
 *跳到特定帧
 **/
 index:function(index){
 this.currentIndex=index;
 return this.frames[this.currentIndex]; 
 },
 /**
 *获取现时帧
 **/
 getCurrentFrame:function(){
 return this.frames[this.currentIndex]; 
 },
 /**
 *在特定位置绘制该帧
 **/
 draw:function(){
 
 var currentFrame=this.getCurrentFrame();
 var width=this.frameSize[0];
 var height=this.frameSize[1];
 cg.context.drawImage(this.image,currentFrame.x,currentFrame.y,width,height,this.x,this.y,width,height);
 }
 
 }
 this.SpriteSheet=spriteSheet;
 
});

文档

HTML5游戏框架cnGameJS开发实录-实现动画原理

HTML5游戏框架cnGameJS开发实录-实现动画原理: 在游戏中,游戏角色的动画效果是一个游戏必不可少的一部分。这节我们以构造超级马里奥的角色为例,讲解cnGameJS里动画的实现。1.原理: 一个动画如果要实现一连串动作,我们可以把每个动作的快照保留起来,并放在一个大图上面,然后每次帧更新的时候,就在
推荐度:
标签: 原理 游戏 动画
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top