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

  • 相关阅读:
    Appium
    monkeyrunner
    Weex
    linux:合并类别代码,查看文本文件的头部、尾部行内容 及查看行数
    linux:使用screen防止异常中断
    Nginx Server 配置格式
    请求测试BTC
    This request has been blocked; the content must be served over HTTPS
    npm install:sill install loadAllDepsIntoIdealTree 不继续执行
    VSCode Remote-WSL 修改子系统版本
  • 原文地址:https://www.cnblogs.com/axes/p/3628975.html
Copyright © 2011-2022 走看看