搜索
首页web前端H5教程HTML5游戏框架cnGameJS开发实录-精灵对象篇

返回目录

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

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

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

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

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

2.demo展现

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

  效果:

 1281.png

  代码:

<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(&#39;gameCanvas&#39;,{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开发实录-精灵对象篇的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
H5和HTML5:网络开发中常用的术语H5和HTML5:网络开发中常用的术语Apr 13, 2025 am 12:01 AM

H5与HTML5指的是同一个东西,即HTML5。HTML5是HTML的第五个版本,带来了语义化标签、多媒体支持、画布与图形、离线存储与本地存储等新功能,提升了网页的表现力和交互性。

H5指的是什么?探索上下文H5指的是什么?探索上下文Apr 12, 2025 am 12:03 AM

H5referstoHTML5,apivotaltechnologyinwebdevelopment.1)HTML5introducesnewelementsandAPIsforrich,dynamicwebapplications.2)Itsupportsmultimediawithoutplugins,enhancinguserexperienceacrossdevices.3)SemanticelementsimprovecontentstructureandSEO.4)H5'srespo

H5:工具,框架和最佳实践H5:工具,框架和最佳实践Apr 11, 2025 am 12:11 AM

H5开发需要掌握的工具和框架包括Vue.js、React和Webpack。1.Vue.js适用于构建用户界面,支持组件化开发。2.React通过虚拟DOM优化页面渲染,适合复杂应用。3.Webpack用于模块打包,优化资源加载。

HTML5的遗产:当前了解H5HTML5的遗产:当前了解H5Apr 10, 2025 am 09:28 AM

HTML5hassignificantlytransformedwebdevelopmentbyintroducingsemanticelements,enhancingmultimediasupport,andimprovingperformance.1)ItmadewebsitesmoreaccessibleandSEO-friendlywithsemanticelementslike,,and.2)HTML5introducednativeandtags,eliminatingthenee

H5代码:可访问性和语义HTMLH5代码:可访问性和语义HTMLApr 09, 2025 am 12:05 AM

H5通过语义化元素和ARIA属性提升网页的可访问性和SEO效果。1.使用、、等元素组织内容结构,提高SEO。2.ARIA属性如aria-label增强可访问性,辅助技术用户可顺利使用网页。

H5与HTML5相同吗?H5与HTML5相同吗?Apr 08, 2025 am 12:16 AM

"h5"和"HTML5"在大多数情况下是相同的,但它们在某些特定场景下可能有不同的含义。1."HTML5"是W3C定义的标准,包含新标签和API。2."h5"通常是HTML5的简称,但在移动开发中可能指基于HTML5的框架。理解这些区别有助于在项目中准确使用这些术语。

H5的功能是什么?H5的功能是什么?Apr 07, 2025 am 12:10 AM

H5,即HTML5,是HTML的第五个版本,它为开发者提供了更强大的工具集,使得创建复杂的网页应用变得更加简单。H5的核心功能包括:1)元素允许在网页上绘制图形和动画;2)语义化标签如、等,使网页结构清晰,利于SEO优化;3)新API如GeolocationAPI,支持基于位置的服务;4)跨浏览器兼容性需要通过兼容性测试和Polyfill库来确保。

h5链接怎么做h5链接怎么做Apr 06, 2025 pm 12:39 PM

如何创建 H5 链接?确定链接目标:获取 H5 页面或应用程序的 URL。创建 HTML 锚点:使用 <a> 标记创建锚点并指定链接目标URL。设置链接属性(可选):根据需要设置 target、title 和 onclick 属性。添加到网页:将 HTML 锚点代码添加到希望链接出现的网页中。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。