zoukankan      html  css  js  c++  java
  • Html5游戏框架createJs的简单用法

      声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢!

      楼主记忆力不好,最近刚好用了一下createJs框架,怕以后一段时间没用后会忘记,所以在此做个记录,或许以后用得着。

      createJs网上的中文教程挺少的,以前UC有个Xcanvas的论坛有createJs的详细教程,但是随着XCanvas团队的解散,那个网站也关闭了。。网上的大部分都是非常基础的教程,有点千遍一律的感觉。所以楼主就去把createJs下载下来,硬着头皮看英文文档了。凭着楼主这英语六级只考了三百多分的渣渣来说,看起来很费力啊,不过还是勉强摸索出了大概的用法。所以现在就是学了多少就记录多少,之后或许也会不定期更新一下该框架的新的学习心得。毕竟对自己以后还是有帮助的。

      希望本文能帮到那些想学createJs的新手。因为楼主也是刚学的,所以本文或许有不正确之处,因此本文仅当参考,若有不正之处欢迎斧正。

      闲话说到这,直接进入主题。

      楼主用createJs写了个简单的跑酷游戏DEMO,就拿它做例子吧。 看DEMO戳我

      createJs的由来,基础什么的就不说了,就直接说createJs的用法吧。

      首先到createJs官网下载,createJs分成easelJs(图形动画)、preloadJs(文件加载)、soundJs(音频控制)以及tweenJs(补间动画)四部分,大家下载的时候,建议下载两个文件,一个是压缩版文件,用于项目中的引用,再下载个源码文件,用于查看用法、API、demo等。因为楼主目前只用了easelJs和preloadJs,所以暂时就只说这两个,其实就这两个已经非常够用了。

      接下来开始分析代码:

      首先引入js文件

    <script src="easeljs-0.7.1.min.js"></script>
    <script src="preloadjs-0.4.1.min.js"></script>

      然后进行舞台初始化操作:

            function init(){
                stage = new createjs.Stage("cas");
                C_W = stage.canvas.width;
                C_H = stage.canvas.height;
    
                var manifest = [
                    {src:"image/man.png" , id:"man"},
                    {src:"image/ground.png" , id:"ground"},
                    {src:"image/bg.png" , id:"bg"},
                    {src:"image/high.jpg" , id:"high"},
                    {src:"image/coins.png" , id:"coin"}
                ]
    
                loader = new createjs.LoadQueue(false);
                loader.addEventListener("complete" , handleComplete);
                loader.loadManifest(manifest);
    
                drawLoading();
            }

    上面就用到了preloadJs中的方法,实例化一个loader,把需要加载的图片文件放在manifest里面,进行加载,加载完成后调用回调handleCompelete函数:

    function handleComplete(){        //当图片素材load完后执行该方法
                var manImage = loader.getResult("man"),
                    lowground = loader.getResult("ground"),
                    highground = loader.getResult("high"),
                    bgImage = loader.getResult("bg"),
                    coins = loader.getResult("coin");
    
                sky = new createjs.Shape();
                sky.graphics.bf(bgImage).drawRect(0,0,C_W,C_H);
                sky.setTransform(0, 0, 1 , C_H/bgImage.height);
                stage.addChild(sky);
    
                man = createMan(200,326,manImage);
    
                //该框为判定角色的判定区域
                kuang = new createjs.Shape();
                kuang.graphics.beginStroke("rgba(255,0,0,0.5)").drawRect(0 , 0 , man.size().w , man.picsize().h*1.5);
                // stage.addChild(kuang);
    
                mapHandle(lowground , highground , coins);
    
                createjs.Ticker.timingMode = createjs.Ticker.RAF;//设置循环方法,可以是requestAnimationFrame或者是setTimeout
                createjs.Ticker.setFPS(30);//舞台帧率控制
                createjs.Ticker.addEventListener("tick", tick);//绑定舞台每一帧的逻辑发生函数
    
                window.addEventListener("keydown" , function(event){
                    event = event||window.event;
                    if(event.keyCode===32&&man.jumpNum<man.jumpMax){
                        man.jump();
                    }
                })
            }

    获得加载完成后端的图片数据就直接用loader.getResult就可以获取了,跑酷游戏需要一个背景,所以,我们实例化一个sky,然后进行位图绘制,bf方法是beginBitmapFill的缩写,该方法就是开始绘制位图,后面的drawRect是位图的绘制区域,区域当然是整个画布啦,所以就是drawRect(0,0,C_W,C_H)。实例化出来sky后就直接添加到舞台stage里面就行了。接下来是实例化一个角色,createMan方法后面有说,是自己封装的。

      然后进行舞台循环设置,上面有注释了,就不说了。

      舞台设置中,mapHandle是地图数据的初始化:

    var mapIndex = 0,        //地图序列
                Mix = 0,            //地图数组的索引
                allStones = [],        //存放所有的石头
                allCoins = [],        //所有金币
                showSt = [];        //存放显示出来的石头
    
            function mapHandle(lowground , highground , coins){        //初始化地图
                allStones.length = 0;
                var stoneImage = {"A":lowground , "B":highground},kind = null;
                for(var i=0;i<30;i++){            //把需要用到的石头预先放入容器中准备好
                    switch(i){
                        case 0:kind="A";break;
                        case 10:kind="B";break;
                        case 20:kind="C";break;
                    }
                    var st = createStone(C_W , kind , stoneImage);
                    allStones.push(st)
                }
    
                for(var i=0;i<10;i++){            //把需要用到的金币预先放入容器中
                    var coin = createCoin(coins);
                    allCoins.push(coin);
                }
                
                Mix = Math.floor(Math.random()*mapData.length);            //随机地图序列
                for(var i=0;i<8;i++){
                    setStone(false)
                }
            }
    
            function setStone(remove){        //添加陆地的石头
                var arg = mapData[Mix].charAt(mapIndex),
                    coarg = coinCode[Mix].charAt(mapIndex),
                    cc = null;
    
                if(coarg==="#"){
                    for(var i=0;i<allCoins.length;i++){
                        if(!allCoins[i].shape.visible){
                            cc = allCoins[i];
                            cc.shape.visible = true;
                            break;
                        }
                    }
                }
    
                for(var z=0;z<allStones.length;z++){
                    if(!allStones[z].shape.visible&&allStones[z].kind===arg){
                        var st = allStones[z];
                        st.shape.visible = true;
                        st.shape.x = showSt.length===0?0:showSt[showSt.length-1].shape.x+showSt[showSt.length-1].w;
    
                        if(cc){
                            cc.shape.x = showSt.length===0?allStones[z].w/2-cc.size().w/2:showSt[showSt.length-1].shape.x+showSt[showSt.length-1].w+allStones[z].w/2-cc.size().w/2;
                            cc.shape.y = arg==="C"? C_H-loader.getResult("high").height-50 : allStones[z].shape.y-cc.size().h/2-50;
                        }
    
                        if(remove) showSt.shift();
                        showSt.push(st);
                        break;
                    }
                }
    
                mapIndex++;
                if(mapIndex>=mapData[Mix].length){
                    Mix = Math.floor(Math.random()*mapData.length)
                    mapIndex=0;
                }
            }

      下面是人物模块的封装

    (function(w){
        var FRAME_RATE = 13,    //精灵表播放速度
            SCALE_X = 1.5,    //X轴缩放
            SCALE_Y = 1.5,    //Y轴缩放
            GRAVITY = 3,    //重力加速度
            JUMP_SPEED = 2.6,        //垂直速度
            WIDTH = 40,
            HEIGHT = 96,
            PICWIDTH = 64,
            PICHEIGHT = 64,
            PROPORTION = 150/1;  //游戏与实际的距离比例
    
        var Man = function(x , y , img){
            this.x = x;
            this.y = y;
            this.endy = y;
            this.vx = 0.5;
            this.vy = 0;
            this.ground = [];
            this.state = "run";
            this.jumpNum = 0;
            this.jumpMax = 1;
            this.init(img);
        }
    
        Man.prototype = {
            constructors:Man,
    
            init:function(img){
                var manSpriteSheet = new createjs.SpriteSheet({  //实例化精灵表绘制器
                    "images":[img],
                    "frames":{"regX":0,"height":PICWIDTH,"count":45,"regY":1,"width":PICHEIGHT},
                    "animations":{
                        "run":{
                            frames:[21,20,19,18,17,16,15,14,13,12],    //精灵表每一帧的位置
                            next:"run",                    //当精灵表循环完后的下一步动作
                            speed:1,                      //精灵表播放速度
                        }, 
                        "jump":{
                            frames:[34,35,36,37,38,39,40,41,42,43],
                            next:"run",
                            speed:1,
                        },
                        "die":{
                            frames:[8,7,6,5,4,3,2,1,0],
                            next:"die",
                            speed:1,
                        }
                    }
                });
                this.sprite = new createjs.Sprite(manSpriteSheet , this.state);  //实例化精灵
                this.sprite.framerate = FRAME_RATE;      //精灵表绘制速率
                this.sprite.setTransform(this.x, this.y, SCALE_X, SCALE_Y);  //设置精灵的位置
                stage.addChild(this.sprite);    //添加到舞台
            },
    
            update:function(){
                var sprite = this.sprite;
                var time = createjs.Ticker.getInterval()/1000;    //获取当前帧与上一帧的时间间隔
    
                if(this.state==="run"){          
                    if(sprite.x<this.x){
                        sprite.x +=this.vx;
                    }else {
                        sprite.x = this.x
                    }
                }
                if(this.endy>sprite.y||this.state==="jump"){  //角色的动作处理
                    var nexty = sprite.y+time*this.vy*PROPORTION;
                    this.vy += time*GRAVITY;
                    sprite.y += time*this.vy*PROPORTION;
                    if(Math.abs(sprite.y-this.endy)<10&&this.vy>0){
                        this.state = "run";
                        sprite.y=this.endy;
                        this.vy = 0;
                    }
                }
                
                if(sprite.x+(PICWIDTH*SCALE_X-WIDTH)/2<0||sprite.y>C_H+200){
                    this.die();
                    createjs.Ticker.reset();
                    alert("you are Die!");
                }
    
                switch(this.state){
                    case "run":
                        this.jumpNum = 0;
                        break;
                    case "die":
                        if(sprite.currentFrame===0){
                            sprite.paused = true;
                        }
                    break;
                }
            },
    
            run:function(){
                this.sprite.gotoAndPlay("run")
            },
    
            jump:function(){
                this.vy = -JUMP_SPEED;
                this.state = "jump";
                this.sprite.gotoAndPlay("jump");  //让精灵表播放特定的动画
                this.jumpNum++;
            },
    
            die:function(){
                this.state = "die";
                this.sprite.gotoAndPlay("die")
            },
    
            size:function(){
                return {
                    w:WIDTH,
                    h:HEIGHT
                }
            },
    
            picsize:function(){
                return {
                    w:PICWIDTH,
                    h:PICHEIGHT
                }
            }
        }
    
        w.createMan = function(x , y , img){
            return new Man(x , y , img)
        };
    })(window)

    人物模块封装就是简单的在createJs的封装之上进行进一步的封装,封装很简单,就是用createJs实例化一个精灵类,再绑定精灵表,上面的代码中也有注释,基本上都说的很明白了。

    下面贴出封装的石头以及金币模块,简单说下背景的循环,预先实例化一堆石头和金币,然后移动响应的石头,当石头移动到超出舞台区域时,把他的visible属性置为false,再重新添加一个石头在最后的位置进行新的一次移动。金币也一样。地图数据则是通过预先定义好的字符串来实现。

    (function(w){
        var SPEED = 4,
            COIN_STAY_X = 20,
            COIN_STAY_Y = 20,
            COIN_STAY_WIDTH = 30,
            COIN_STAY_HEIGHT = 30,
            COIN_SCALE_X = 0.08,
            COIN_SCALE_Y = 0.08;
    
        //地上的石头类
    
        var Stone = function(x,kind,allImage){
            this.x = x;
            this.kind = kind;
            this.allImage = allImage;
            this.init();
        }
    
        var sp = Stone.prototype;
    
        sp.init=function(){
            this.shape = new createjs.Shape();
            if(this.kind!=="C"){
                this.h = this.allImage[this.kind].height;
                this.w = this.allImage[this.kind].width*2;
                this.y = C_H - this.h;
                this.shape.graphics.beginBitmapFill(this.allImage[this.kind]).drawRect(0, 0, this.w, this.h);
                this.shape.setTransform(this.x, this.y, 1, 1);
            }else {
                this.h = -1000;
                this.w = 170;
                this.y = C_H - this.h;
                this.shape.graphics.beginFill("#000").drawRect(0, 0, this.w, this.h);
                this.shape.setTransform(this.x, this.y, 1, 1);
            }
            this.shape.visible = false;
            this.shape.cache(0 , 0 , this.w , this.h);
            stage.addChild(this.shape);
        }
    
        sp.update=function(){
            this.shape.x -= SPEED;
        }
    
        //金币类
        var Coin = function(image){
            this.sizeX = COIN_SCALE_X;
            this.sizeY = COIN_SCALE_Y;
    
            this.isget = false;
            this.init = function(){
                this.shape = new createjs.Shape();
                this.shape.graphics.beginBitmapFill(image).drawRect(0, 0, image.width, image.height);
                this.shape.setTransform(0, 0, COIN_SCALE_X, COIN_SCALE_Y);
                this.shape.visible = false;
                stage.addChild(this.shape);
            }
            this.init();
    
            this.update = function(){
                if(this.isget){
                    this.sizeX = this.sizeX + ((COIN_STAY_WIDTH/image.width) - this.sizeX)*0.1;
                    this.sizeY = this.sizeY + ((COIN_STAY_HEIGHT/image.height) - this.sizeY)*0.1;
                    this.shape.setTransform(
                        this.shape.x + (COIN_STAY_X - this.shape.x)*0.1,
                        this.shape.y + (COIN_STAY_Y - this.shape.y)*0.1,
                        this.sizeX,
                        this.sizeY
                    );
    
                    if(Math.abs(this.shape.x-COIN_STAY_X)<0.5&&Math.abs(this.shape.y-COIN_STAY_Y)<0.5){
                        this.shape.visible = false;
                        this.isget = false;
                        this.sizeX = COIN_SCALE_X;
                        this.sizeY = COIN_SCALE_Y;
                        this.shape.setTransform(0,0,this.sizeX,this.sizeY);
                    }
                } else{
                    this.shape.x -= SPEED;
                    if(this.shape.x<-image.width*COIN_SCALE_X){
                        this.shape.visible = false;
                    }
                }
            }
    
            this.size = function(){
                return {
                    w:image.width*COIN_SCALE_X,
                    h:image.height*COIN_SCALE_Y
                }
            }
        }
    
        w.createCoin = function(image){
            return new Coin(image)
        }
    
        w.createStone = function(x,kind,allImage){
            return new Stone(x,kind,allImage);
        }
    })(window)

    封装方法跟上面的人物模块封装差不多,不过人物是用精灵类,石头金币则是用形状类了。就是通过位图的绘制,来绘制位图的图片,原理都一样。

    最后是舞台逐帧处理的tick方法:

    function tick(event){        //舞台逐帧逻辑处理函数
                man.update();
    
                kuang.x = man.sprite.x+(man.picsize().w*1.5-man.size().w)/2;    //参考框
                kuang.y = man.sprite.y;
    
                man.ground.length=0;
                var cg = stoneHandle();
    
                if(man.ground[0]&&!cg) {
                    man.ground.sort(function(a,b){return b.h-a.h});
                    man.endy = man.ground[0].y-man.picsize().h*1.5;
                }
    
                allCoins.forEach(function(cc , index){
                    if(cc.shape.visible){
                        if( 
                            Math.abs((kuang.x+man.size().w/2) - (cc.shape.x+cc.size().w/2)) <= (man.size().w+cc.size().w)/2&&
                            Math.abs((kuang.y+man.size().h/2) - (cc.shape.y+cc.size().h/2)) <= (man.size().h+cc.size().h)/2&&
                            !cc.isget
                        ){
                            cc.isget = true;
                            countCoin.innerHTML = parseInt(countCoin.innerHTML)+1
                        }
                        cc.update();
                    }
                })
    
                document.getElementById("showFPS").innerHTML = man.endy
                stage.update(event)
            }

    在每一帧的处理,就像自己写游戏一样啦,就是把舞台里的所有对象逐个进行逻辑运算,进行相应处理。 

    基本上createJs的用法还是相对比较简单并且强大的。比自己去造轮子能省很多功夫。

    源码地址:https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Game-demo/runningMan

  • 相关阅读:
    Struts2SpringHibernate整合示例,一个HelloWorld版的在线书店(项目源码+详尽注释+单元测试)
    Java实现蓝桥杯勇者斗恶龙
    Java实现 LeetCode 226 翻转二叉树
    Java实现 LeetCode 226 翻转二叉树
    Java实现 LeetCode 226 翻转二叉树
    Java实现 LeetCode 225 用队列实现栈
    Java实现 LeetCode 225 用队列实现栈
    Java实现 LeetCode 225 用队列实现栈
    Java实现 LeetCode 224 基本计算器
    Java实现 LeetCode 224 基本计算器
  • 原文地址:https://www.cnblogs.com/axes/p/3628975.html
Copyright © 2011-2022 走看看