最新文章专题视频专题问答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:22
文档

HTML5游戏框架cnGameJS开发实录-精灵对象篇

HTML5游戏框架cnGameJS开发实录-精灵对象篇:返回目录1.什么是精灵对象(sprite)? 所谓的精灵对象,就是游戏中的一个具有行为的元素,以超级玛丽为例,玛丽,敌人都算是一个精灵对象。在cnGameJS框架中,精灵对象如下几个特点: 1.添加动画:在之前的动画篇中,我们介绍过cnGameJS如何实现帧动画。
推荐度:
导读HTML5游戏框架cnGameJS开发实录-精灵对象篇:返回目录1.什么是精灵对象(sprite)? 所谓的精灵对象,就是游戏中的一个具有行为的元素,以超级玛丽为例,玛丽,敌人都算是一个精灵对象。在cnGameJS框架中,精灵对象如下几个特点: 1.添加动画:在之前的动画篇中,我们介绍过cnGameJS如何实现帧动画。
 返回目录

1.什么是精灵对象(sprite)?

  所谓的精灵对象,就是游戏中的一个具有行为的元素,以超级玛丽为例,玛丽,敌人都算是一个精灵对象。在cnGameJS框架中,精灵对象如下几个特点:

  1.添加动画:在之前的动画篇中,我们介绍过cnGameJS如何实现帧动画。而作为精灵对象,就是动画的使用者。例如我们控制玛丽向不同方向的行走,玛丽会产生行走的动画。

  2.包含图像:对于另外一些精灵对象,它可能不需要运动动画,这时我们就可以只让它使用图像。

  3.能进行不同类型的运动:可以让精灵对象向不同方向,以不同加速度进行移动。

2.demo展现

  这里以一个简单的demo进行展现,我们通过鼠标控制玛丽的行动(匀加速运动),当玛丽停止时,使用图片。当玛丽移动时,使用动画,键盘左右方向键控制玛丽的移动。

  效果:

  代码:

<body>
<div><canvas id="gameCanvas">请使用支持canvas的浏览器查看</canvas></div>
</body>
<script src="http://files.cnblogs.com/Cson/cnGame_v1.0.js"></script>
<script>
var Src="http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player.png";

/* 初始化 */
cnGame.init('gameCanvas',{width:300,height:150});
var floorY=cnGame.height-40;
var gameObj=(function(){
 /* 玩家对象 */
 var player=function(options){
 this.init(options); 
 this.speedX=0;
 this.moveDir;
 this.isJump=false;
 }
 cnGame.core.inherit(player,cnGame.Sprite);
 player.prototype.initialize=function(){
 this.addAnimation(new cnGame.SpriteSheet("playerRight",Src,{frameSize:[50,60],loop:true,width:150,height:60}));
 this.addAnimation(new cnGame.SpriteSheet("playerLeft",Src,{frameSize:[50,60],loop:true,width:150,height:120,beginY:60}));
 }
 player.prototype.moveRight=function(){
 if(cnGame.core.isUndefined(this.moveDir)||this.moveDir!="right"){
 this.moveDir="right";
 this.speedX<0&&(this.speedX=0);
 this.setMovement({aX:10,maxSpeedX:15});
 this.setCurrentAnimation("playerRight");
 }
 }
 player.prototype.moveLeft=function(){
 if(cnGame.core.isUndefined(this.moveDir)||this.moveDir!="left"){
 this.moveDir="left";
 this.speedX>0&&(this.speedX=0);
 this.setMovement({aX:-10,maxSpeedX:15});
 this.setCurrentAnimation("playerLeft");
 }
 }
 player.prototype.stopMove=function(){
 
 if(this.speedX<0){
 this.setCurrentImage(Src,0,60);
 }
 else if(this.speedX>0){
 this.setCurrentImage(Src);
 } 
 this.moveDir=undefined;
 this.resetMovement();
 
 }
 player.prototype.update=function(){
 player.prototype.parent.prototype.update.call(this);//调用父类update
if(cnGame.input.isPressed("right")){
 this.moveRight(); 
 }
 else if(cnGame.input.isPressed("left")){
 this.moveLeft();
 }
 else{
 this.stopMove();
 }
 
 
 }

 return {
 initialize:function(){
 cnGame.input.preventDefault(["left","right","up","down"]);
 this.player=new player({src:Src,width:50,height:60,x:0,y:floorY-60});
 this.player.initialize();
 },
 update:function(){
 this.player.update();
 },
 draw:function(){
 this.player.draw();
 }

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

3.实现

  和动画篇spriteSheet对象一样,sprite对象同样划分三个阶段:初始化,更新,绘制。

  首先看sprite的初始化函数:

/**
 *初始化
 **/
 init:function(options){
 
 /**
 *默认对象
 **/ 
 var defaultObj={
 x:0,
 y:0,
 imgX:0,
 imgY:0,
 width:32,
 height:32,
 angle:0,
 speedX:0,
 speedY:0,
 aX:0,
 aY:0,
 maxSpeedX:postive_infinity,
 maxSpeedY:postive_infinity,
 maxX:postive_infinity,
 maxY:postive_infinity,
 minX:-postive_infinity,
 minY:-postive_infinity
 };
 options=options||{};
 options=cg.core.extend(defaultObj,options);
 this.x=options.x;
 this.y=options.y;
 this.angle=options.angle;
 this.width=options.width;
 this.height=options.height;
 this.angle=options.angle;
 this.speedX=options.speedX;
 this.speedY=options.speedY;
 this.aX=options.aX;
 this.aY=options.aY;
 this.maxSpeedX=options.maxSpeedX;
 this.maxSpeedY=options.maxSpeedY;
 this.maxX=options.maxX;
 this.maxY=options.maxY;
 this.minX=options.minX;
 this.minY=options.minY;

 
 this.spriteSheetList={};
 if(options.src){ //传入图片路径
 this.setCurrentImage(options.src,options.imgX,options.imgY);
 }
 else if(options.spriteSheet){//传入spriteSheet对象
 this.addAnimation(options.spriteSheet); 
 setCurrentAnimation(options.spriteSheet);
 }
 
 }

  参数很多,主要包括:对象位置,旋转角度,尺寸,xy方向的速度,xy方向的加速度,xy方向的最大速度。另外如果用户传入图片地址,则设置当前sprite对象使用图片,否则使用spriteSheet动画。

  先看看sprite对象如何使用图像:

/**
 *设置当前显示图像
 **/
 setCurrentImage:function(src,imgX,imgY){
 if(!this.isCurrentImage(src,imgX,imgY)){
 imgX=imgX||0;
 imgY=imgY||0;
 this.image=cg.loader.loadedImgs[src]; 
 this.imgX=imgX;
 this.imgY=imgY; 
 this.spriteSheet=undefined;
 }
 },

  首先检测现在是否正在使用该图像,如果不是,则从loader里获取下载好的image对象(所有图像资源在游戏开始时已下载好,),并且设置spriteSheet为undefined(表示不使用spriteSheet动画),这样sprite对象就可以使用图像了。

  再看看如何使用动画:

/**
 *设置当前显示动画
 **/
 setCurrentAnimation:function(id){//可传入id或spriteSheet
 if(!this.isCurrentAnimation(id)){
 if(cg.core.isString(id)){
 this.spriteSheet=this.spriteSheetList[id];
 this.image=this.imgX=this.imgY=undefined;
 }
 else if(cg.core.isObject(id)){
 this.spriteSheet=id;
 this.addAnimation(id);
 this.image=this.imgX=this.imgY=undefined;
 }
 }
 
 },

  首先根据传入的spriteSheet或spriteSheet的id判断是否正在使用该动画,如果不是,则设置sprite使用spriteSheet动画。

  设置好sprite对象使用动画后,核心函数update就负责调用spriteSheet的update,更新sprite使用的动画,需要注意的是使spriteSheet的xy为sprite的xy:

if(this.spriteSheet){//更新spriteSheet动画
 this.spriteSheet.x=this.x
 this.spriteSheet.y=this.y;
 this.spriteSheet.update();
 }

  这样就完成的sprite对象动画的展示。

  最后看看如何实现最后一个特点:使sprite能进行变速的运动。

  要进行变速运动,我们需要确立如下几个变量:初始速度,经过的时间,以及加速度。现在看cnGameJS负责变速运动的部分:

/**
 *设置移动参数
 **/
 setMovement:function(options){
 isUndefined=cg.core.isUndefined;
 isUndefined(options.speedX)?this.speedX=this.speedX:this.speedX=options.speedX;
 isUndefined(options.speedY)?this.speedY=this.speedY:this.speedY=options.speedY;
 
 isUndefined(options.aX)?this.aX=this.aX:this.aX=options.aX;
 isUndefined(options.aY)?this.aY=this.aY:this.aY=options.aY;
 isUndefined(options.maxX)?this.maxX=this.maxX:this.maxX=options.maxX;
 isUndefined(options.maxY)?this.maxY=this.maxY:this.maxY=options.maxY;
 isUndefined(options.minX)?this.minX=this.minX:this.minX=options.minX;
 isUndefined(options.minY)?this.minY=this.minY:this.minY=options.minY;

 
 if(this.aX!=0){
 this.startTimeX=new Date().getTime();
 this.oriSpeedX=this.speedX;
 isUndefined(options.maxSpeedX)?this.maxSpeedX=this.maxSpeedX:this.maxSpeedX=options.maxSpeedX; 
 }
 if(this.aY!=0){
 this.startTimeY=new Date().getTime();
 this.oriSpeedY=this.speedY;
 isUndefined(options.maxSpeedY)?this.maxSpeedY=this.maxSpeedY:this.maxSpeedY=options.maxSpeedY; 
 }
 
 }

  每次用户调用setMovement,就保留sprite的初速度,和运动开始的时间。这样在每次update的时候,就可以根据前面两个变量,获取到sprite现时的速度,并计算现时的XY方向上的位移:

if(this.aX!=0){
 var now=new Date().getTime();
 var durationX=now-this.startTimeX;
 var speedX=this.oriSpeedX+this.aX*durationX/1000;
 if(this.maxSpeedX<0){
 this.maxSpeedX*=-1;
 }
 if(speedX<0){
 this.speedX=Math.max(speedX,this.maxSpeedX*-1) ;
 }
 else{
 this.speedX=Math.min(speedX,this.maxSpeedX);
 }
 }
 if(this.aY!=0){
 var now=new Date().getTime();
 var durationY=now-this.startTimeY;
 this.speedY=this.oriSpeedY+this.aY*durationY/1000; 
 }
 this.move(this.speedX,this.speedY);

  当update更新了sprite的位移,就可以通过第三个阶段draw方法,把sprite绘制出来。

/**
 *绘制出sprite
 **/
 draw:function(){
 var context=cg.context;
 if(this.spriteSheet){
 this.spriteSheet.x=this.x
 this.spriteSheet.y=this.y;
 this.spriteSheet.draw();
 }
 else if(this.image){
 context.save()
 context.translate(this.x, this.y);
 context.rotate(this.angle * Math.PI / 180);
 context.drawImage(this.image,this.imgX,this.imgY,this.width,this.height,0,0,this.width,this.height);
 context.restore();
 }
 
 },

  注意sprite在使用spriteSheet动画或在使用图像,draw方法执行都不相同。当使用sprieSheet动画时,draw方法实质上是调用了spriteSheet的draw方法绘制帧图像,而当sprite使用图像,我们还可以让图像旋转之后再绘制。

  sprite对象还提供一个getRect方法,返回包含该sprite对象的矩形。该方法为检测sprite对象和其他对象的碰撞带来方便。有关碰撞检测请看:HTML5游戏框架cnGameJS开发实录(碰撞检测篇)

  另外sprite对象同样具有move,moveTo,resize,resizeTo等功能,方便对该对象的位置和尺寸进行操控。

  sprite对象所有源码:

/**
 *
 *sprite对象
 *
**/
cnGame.register("cnGame",function(cg){
 
 var postive_infinity=Number.POSITIVE_INFINITY; 
 
 var sprite=function(id,options){
 if(!(this instanceof arguments.callee)){
 return new arguments.callee(id,options);
 }
 this.init(id,options);
 }
 sprite.prototype={
 /**
 *初始化
 **/
 init:function(options){
 
 /**
 *默认对象
 **/ 
 var defaultObj={
 x:0,
 y:0,
 imgX:0,
 imgY:0,
 width:32,
 height:32,
 angle:0,
 speedX:0,
 speedY:0,
 aX:0,
 aY:0,
 maxSpeedX:postive_infinity,
 maxSpeedY:postive_infinity,
 maxX:postive_infinity,
 maxY:postive_infinity,
 minX:-postive_infinity,
 minY:-postive_infinity
 };
 options=options||{};
 options=cg.core.extend(defaultObj,options);
 this.x=options.x;
 this.y=options.y;
 this.angle=options.angle;
 this.width=options.width;
 this.height=options.height;
 this.angle=options.angle;
 this.speedX=options.speedX;
 this.speedY=options.speedY;
 this.aX=options.aX;
 this.aY=options.aY;
 this.maxSpeedX=options.maxSpeedX;
 this.maxSpeedY=options.maxSpeedY;
 this.maxX=options.maxX;
 this.maxY=options.maxY;
 this.minX=options.minX;
 this.minY=options.minY;

 this.spriteSheetList={};
 if(options.src){ //传入图片路径
 this.setCurrentImage(options.src,options.imgX,options.imgY);
 }
 else if(options.spriteSheet){//传入spriteSheet对象
 this.addAnimation(options.spriteSheet); 
 setCurrentAnimation(options.spriteSheet);
 }
 
 },
 /**
 *返回包含该sprite的矩形对象
 **/
 getRect:function(){
 return new cg.shape.Rect({x:this.x,y:this.y,width:this.width,height:this.height});
 
 },
 /**
 *添加动画
 **/
 addAnimation:function(spriteSheet){
 this.spriteSheetList[spriteSheet.id]=spriteSheet; 
 },
 /**
 *设置当前显示动画
 **/
 setCurrentAnimation:function(id){//可传入id或spriteSheet
 if(!this.isCurrentAnimation(id)){
 if(cg.core.isString(id)){
 this.spriteSheet=this.spriteSheetList[id];
 this.image=this.imgX=this.imgY=undefined;
 }
 else if(cg.core.isObject(id)){
 this.spriteSheet=id;
 this.addAnimation(id);
 this.image=this.imgX=this.imgY=undefined;
 }
 }
 
 },
 /**
 *判断当前动画是否为该id的动画
 **/
 isCurrentAnimation:function(id){
 if(cg.core.isString(id)){
 return (this.spriteSheet&&this.spriteSheet.id===id);
 }
 else if(cg.core.isObject(id)){
 return this.spriteSheet===id;
 }
 },
 /**
 *设置当前显示图像
 **/
 setCurrentImage:function(src,imgX,imgY){
 if(!this.isCurrentImage(src,imgX,imgY)){
 imgX=imgX||0;
 imgY=imgY||0;
 this.image=cg.loader.loadedImgs[src]; 
 this.imgX=imgX;
 this.imgY=imgY; 
 this.spriteSheet=undefined;
 }
 },
 /**
 *判断当前图像是否为该src的图像
 **/
 isCurrentImage:function(src,imgX,imgY){
 imgX=imgX||0;
 imgY=imgY||0;
 var image=this.image;
 if(cg.core.isString(src)){
 return (image&&image.srcPath===src&&this.imgX===imgX&&this.imgY===imgY);
 }
 },
 /**
 *设置移动参数
 **/
 setMovement:function(options){
 isUndefined=cg.core.isUndefined;
 isUndefined(options.speedX)?this.speedX=this.speedX:this.speedX=options.speedX;
 isUndefined(options.speedY)?this.speedY=this.speedY:this.speedY=options.speedY;
 
 isUndefined(options.aX)?this.aX=this.aX:this.aX=options.aX;
 isUndefined(options.aY)?this.aY=this.aY:this.aY=options.aY;
 isUndefined(options.maxX)?this.maxX=this.maxX:this.maxX=options.maxX;
 isUndefined(options.maxY)?this.maxY=this.maxY:this.maxY=options.maxY;
 isUndefined(options.minX)?this.minX=this.minX:this.minX=options.minX;
 isUndefined(options.minY)?this.minY=this.minY:this.minY=options.minY;

 
 if(this.aX!=0){
 this.startTimeX=new Date().getTime();
 this.oriSpeedX=this.speedX;
 isUndefined(options.maxSpeedX)?this.maxSpeedX=this.maxSpeedX:this.maxSpeedX=options.maxSpeedX; 
 }
 if(this.aY!=0){
 this.startTimeY=new Date().getTime();
 this.oriSpeedY=this.speedY;
 isUndefined(options.maxSpeedY)?this.maxSpeedY=this.maxSpeedY:this.maxSpeedY=options.maxSpeedY; 
 }
 
 },
 /**
 *重置移动参数回到初始值
 **/
 resetMovement:function(){
 this.speedX=0;
 this.speedY=0;
 this.aX=0;
 this.aY=0;
 this.maxSpeedX=postive_infinity;
 this.maxSpeedY=postive_infinity;
 this.maxX=postive_infinity;
 this.minX=-postive_infinity;
 this.maxY=postive_infinity;
 this.minY=-postive_infinity;
 },
 /**
 *更新位置和帧动画
 **/
 update:function(){
 if(this.aX!=0){
 var now=new Date().getTime();
 var durationX=now-this.startTimeX;
 var speedX=this.oriSpeedX+this.aX*durationX/1000;
 if(this.maxSpeedX<0){
 this.maxSpeedX*=-1;
 }
 if(speedX<0){
 this.speedX=Math.max(speedX,this.maxSpeedX*-1) ;
 }
 else{
 this.speedX=Math.min(speedX,this.maxSpeedX);
 }
 }
 if(this.aY!=0){
 var now=new Date().getTime();
 var durationY=now-this.startTimeY;
 this.speedY=this.oriSpeedY+this.aY*durationY/1000; 
 }
 this.move(this.speedX,this.speedY);
 
 
 if(this.spriteSheet){//更新spriteSheet动画
 this.spriteSheet.x=this.x
 this.spriteSheet.y=this.y;
 this.spriteSheet.update();
 }
 },
 /**
 *绘制出sprite
 **/
 draw:function(){
 var context=cg.context;
 if(this.spriteSheet){
 this.spriteSheet.x=this.x
 this.spriteSheet.y=this.y;
 this.spriteSheet.draw();
 }
 else if(this.image){
 context.save()
 context.translate(this.x, this.y);
 context.rotate(this.angle * Math.PI / 180);
 context.drawImage(this.image,this.imgX,this.imgY,this.width,this.height,0,0,this.width,this.height);
 context.restore();
 }
 
 },
 /**
 *移动一定距离
 **/
 move:function(dx,dy){
 dx=dx||0;
 dy=dy||0;
 var x=this.x+dx;
 var y=this.y+dy;
 this.x=Math.min(Math.max(this.minX,x),this.maxX);
 this.y=Math.min(Math.max(this.minY,y),this.maxY);
 return this;
 
 },
 /**
 *移动到某处
 **/
 moveTo:function(x,y){
 this.x=Math.min(Math.max(this.minX,x),this.maxX);
 this.y=Math.min(Math.max(this.minY,y),this.maxY);
 return this;
 },
 /**
 *旋转一定角度
 **/
 rotate:function(da){
 this.angle+=da;
 return this;
 },
 /**
 *旋转到一定角度
 **/
 rotateTo:function(){
 this.angle=da;
 return this;
 
 },
 /**
 *改变一定尺寸
 **/
 resize:function(dw,dh){
 this.width+=dw;
 this.height+=dh;
 return this;
 },
 /**
 *改变到一定尺寸
 **/
 resizeTo:function(width,height){
 this.width=width;
 this.height=height;
 return this;
 }
 
 }
 this.Sprite=sprite; 
 
});

文档

HTML5游戏框架cnGameJS开发实录-精灵对象篇

HTML5游戏框架cnGameJS开发实录-精灵对象篇:返回目录1.什么是精灵对象(sprite)? 所谓的精灵对象,就是游戏中的一个具有行为的元素,以超级玛丽为例,玛丽,敌人都算是一个精灵对象。在cnGameJS框架中,精灵对象如下几个特点: 1.添加动画:在之前的动画篇中,我们介绍过cnGameJS如何实现帧动画。
推荐度:
标签: 游戏 html5 html
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top