首頁 web前端 H5教程 HTML5遊戲框架cnGameJS開發實錄-精靈物件篇

HTML5遊戲框架cnGameJS開發實錄-精靈物件篇

Mar 25, 2017 pm 03:05 PM

返回目錄

1.什麼是精靈物件(sprite)?

  所謂的精靈對象,就是遊戲中的一個具有行為的元素,以超級瑪麗為例,瑪麗,敵人都算是一個精靈對象。在cnGameJS框架中,精靈物件如下幾個特點:

  1.加入動畫:在先前的動畫篇中,我們介紹過cnGameJS如何實作影格動畫。而作為精靈對象,就是動畫的使用者。例如我們控制瑪莉向不同方向的行走,瑪莉會產生行走的動畫。

  2.包含圖像:對於另外一些精靈對象,它可能不需要運動動畫,這時我們就可以只讓它使用圖像。

  3.能進行不同類型的運動:可以讓精靈物件向不同方向,以不同加速度進行移動。

2.demo展現

  這裡以一個簡單的demo進行展現,我們透過滑鼠控制瑪麗的行動(勻加速運動),當瑪麗停止時,使用圖片。當瑪麗移動時,使用動畫,鍵盤左右方向鍵控制瑪麗的移動

  效果:

 HTML5遊戲框架cnGameJS開發實錄-精靈物件篇

#  代碼:

<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

熱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 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

HTML 中的表格邊框 HTML 中的表格邊框 Sep 04, 2024 pm 04:49 PM

HTML 表格邊框指南。在這裡,我們以 HTML 中的表格邊框為例,討論定義表格邊框的多種方法。

HTML 左邊距 HTML 左邊距 Sep 04, 2024 pm 04:48 PM

HTML 左邊距指南。在這裡,我們討論 HTML margin-left 的簡要概述及其範例及其程式碼實作。

HTML 中的巢狀表 HTML 中的巢狀表 Sep 04, 2024 pm 04:49 PM

這是 HTML 中巢狀表的指南。這裡我們討論如何在表中建立表格以及對應的範例。

HTML 表格佈局 HTML 表格佈局 Sep 04, 2024 pm 04:54 PM

HTML 表格佈局指南。在這裡,我們詳細討論 HTML 表格佈局的值以及範例和輸出。

HTML 輸入佔位符 HTML 輸入佔位符 Sep 04, 2024 pm 04:54 PM

HTML 輸入佔位符指南。在這裡,我們討論 HTML 輸入佔位符的範例以及程式碼和輸出。

HTML 有序列表 HTML 有序列表 Sep 04, 2024 pm 04:43 PM

HTML 有序列表指南。在這裡我們也分別討論了 HTML 有序列表和類型的介紹以及它們的範例

在 HTML 中移動文字 在 HTML 中移動文字 Sep 04, 2024 pm 04:45 PM

HTML 中的文字移動指南。在這裡我們討論一下marquee標籤如何使用語法和實作範例。

HTML onclick 按鈕 HTML onclick 按鈕 Sep 04, 2024 pm 04:49 PM

HTML onclick 按鈕指南。這裡我們分別討論它們的介紹、工作原理、範例以及各個事件中的onclick事件。

See all articles