Home > Article > Web Front-end > HTML5 game framework cnGameJS development record - elf object chapter
Return to directory
1. What is a spriteobject (sprite)?
The so-called elf object is an element with behavior in the game. Taking Super Mario as an example, Mary and the enemy are all considered to be an elf object. In the cnGameJS framework, the sprite object has the following characteristics:
1. Add animation: In the previous animation article, we introduced how cnGameJS implements frame animation. As a sprite object, it is the user of animation. For example, if we control Mary to walk in different directions, Mary will generate a walking animation.
2. Contain images: For other sprite objects, it may not need motion animation, then we can just let it use images.
3. Can perform different types of movements: You can make the sprite object move in different directions and with different accelerations.
2. Demo display
Here is a simple demo. We control Mary's action (uniformly accelerated movement) through the mouse. When Mary stops, use picture. When Mary moves, use animation, The left and right arrow keys on the keyboard control Mary's movement.
Effect:
Code:
<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. Implementation
Like the animation spriteSheet object, thesprite object is also divided into three stages: initialization, update, and drawing.
First look at the initialization of spriteFunction :
/** *初始化 **/ 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); } }There are many parameters, mainly including: object position, rotation angle, size, speed in xy direction, acceleration in xy direction, Maximum speed in xy direction. In addition, if the user passes in the image address, the current sprite object is set to use the image, otherwise the spriteSheet animation is used. Let’s first look at how the sprite object uses the image:
/** *设置当前显示图像 **/ 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; } },First check whether the image is being used now. If not, get the downloaded image object from the loader (all image resources are in the game It has been downloaded at the beginning,) and set spriteSheet to undefined (indicating that spriteSheet animation is not used), so that the sprite object can use images. Let’s look at how to use animation:
/** *设置当前显示动画 **/ 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; } } }, 复制代码First, determine whether the animation is being used based on the incoming spriteSheet or the id of the spriteSheet. If not, set the sprite to use the spriteSheet animation. After setting the animation for the sprite object, the core function up
if(this.spriteSheet){//更新spriteSheet动画 this.spriteSheet.x=this.x this.spriteSheet.y=this.y; this.spriteSheet.update(); }This completes the display of sprite object animation. Finally, let’s look at how to implement the last feature: enabling sprites to move at variable speeds. To perform variable speed motion, we need to establish the following
/** *设置移动参数 **/ 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; } }Every time the user calls setMovement, the initial speed of the sprite and the time when the movement starts are retained. In this way, every time it is updated, the current speed of the sprite can be obtained based on the previous two variables, and the current displacement in the XY direction can be calculated:
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); 复制代码When the update updates the displacement of the sprite, you can Through the third stage draw method, the sprite is drawn.
/** *绘制出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(); } },Note that the draw method execution is different whether the sprite uses spriteSheet animation or uses an image. When using sprieSheet animation, the draw method essentially calls the draw method of spriteSheet to draw the frame image. When sprite uses an image, we can also rotate the image before drawing it. The sprite object also provides a getRect method, which returns the rectangle containing the sprite object. This method brings convenience to detect collisions between sprite objects and other objects. For collision detection, please see: HTML5 Game Framework cnGameJS Development Record (Collision Detection) In addition, the sprite object also has functions such as move, moveTo, resize, resizeTo, etc., which facilitates the control of the position and size of the object. All source codes of sprite objects:
/** * *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; }); 复制代码
The above is the detailed content of HTML5 game framework cnGameJS development record - elf object chapter. For more information, please follow other related articles on the PHP Chinese website!