zoukankan      html  css  js  c++  java
  • H5游戏开发之Stick Hero

       自从上次发布一个小恐龙游戏以后,到现在10天了,前后又写了3个游戏,挑了一个感觉比较有挑战的游戏和大家分享一下。

         效果演示

     

     这是我模拟一个苹果游戏《stick hero》游戏写的一个小游戏,在这里记录一下,希望大家会喜欢。

       一直按下鼠标,会出一根棍子,棍子会变长,小人会根据棍子长度来移动。判断小人是否停留在柱子上,因为放在网上以后,鼠标判断有点卡,请大家见谅。

     那我们还是从头开始介绍一下这游戏的开发过程吧。

    图片加载

    这次的图片加载器是用的《H5手把手教你玛丽游戏》的图片加载器,个人感觉非常好用,可能是我没接触更好的图片加载器,大神都是用自己框架写的,感觉研究起来我很吃力,基础跟不上,最近一个大哥叫我去研究OOP思想来编写框架开发游戏,这也是我以后的方向,很感谢这位大哥给我的指导。

    function loadImg(imgCount,callback){
        var img = {},
            total = imgCount.length,
            loaded = 0;
        for(var i = 0;i < total;i++){
            var imgs = img[imgCount[i].id] = new Image();
            imgs.src = imgCount[i].src;
            imgs.onload = function(){
                loaded++;
            };
        }
        
        if(typeof callback == "function"){
            function check(){
                if(loaded >= total)
                    callback();
                else
                    setTimeout(check,300);
            }
            check();
        }
        return img;
    }
    View Code

    调用的方式和我上次那个差不多,也是传id和src,和回调函数,确保图片加载完以后执行。

            var imgs = null,
                game = null;
                
            function init(){
                imgs = loadImg([
                    {id:"bg",src:"img/bg2.png"},
                    {id:"player",src:"img/player.png"}
                ],start);
            }
            init();
            
            function start(){
                game = new Game({
                    500,
                    height:600,
                    FPS:30,
                    
                });
                game.init();
                game.move();
            }
    精灵类

    这次比较复杂的是存在着精灵,精灵存在动画,所以加了2个类,Sprite和Animation,在这个游戏中,我把柱子也当做精灵处理,因为每次的柱子他的宽度和初始位置是随机的,而且在检测人物是否站在柱子上的时候比较好检测。

    function Sprite(option){
        for(var attr in option){
            this[attr] = option[attr];
        }
    }
    Sprite.prototype = {
        constructor:Sprite,
        x:0,
        y:340,
        w:0,
        h:0,
        maxX:999,
        maxY:999,
        animation:null,
        accX:0,
        accY:0,
        init:function(){
            if(this.animation){
                this.animation.init();
                this.animation.setNow(0);
            }
        },
        //每次更变人物的移动动画,让人物动起来。
        update:function(sleep,long){
            this.x += this.accX;
            this.animation.update(sleep);
            if(this.x >= long+40){
                this.x = long+40;
                this.animation.setNow(0);
                this.checkCollide();
            }
        },
        //人物的绘制
        draw:function(ct){
            this.animation.draw(ct,this.x,this.y);
        },
        //矩形的绘制
        drawRect:function(ct){
            ct.fillRect(this.x,this.y,this.w,this.h);
        },
        //检测人物是否在柱子上
        checkCollide:function(){
            var Px1 = this.x;
            var Px2 = this.x + 40;
            
            var Rx1 = game.colRect.x;
            var Rx2 = game.colRect.x + game.colRect.w ;
            if(Px1 > Rx2 || Px2 < Rx1){
                this.y += this.accY;
                if(this.y >= this.maxY){
                    clearInterval(game.mainLoop);
                    alert("挑战失败!    ");
                }
            }else{
                game.initStart();
            }
        }
    };
    View Code

     下面是生成人物和柱子的代码,通过参数可以区分他们。

    function createPlayer(){
        var config = {
            //人物走路速度
            accX:4,
            //人物掉落速度
            accY:7,
            //人物初始位置
            x:0,
            y:340,
            maxY:600,
            //人物移动过程
            animation:new Animation({
                frame:[
                   {x:20,y:0,w:80,h:80,action:100},
                   {x:120,y:0,w:80,h:80,action:100},
                   {x:220,y:0,w:80,h:80,action:100},
                   {x:320,y:0,w:80,h:80,action:100},
                ]
            })
        };
        return new Sprite(config);
    }
    function createRect(){
        var config = {
            //每次随机获取宽度和x位置,这样让游戏更有挑战
            w:(Math.random()*40 + 20)|0,
            x:(Math.random()*300+150)|0,
            y:400,
            h:200,
        };
        return new Sprite(config);
    }

     下面介绍的是人物的移动,通过组图的不断更换,让人物动起来。

    function Animation(option){
        for(var attr in option){
            this[attr] = option[attr];
        }
    }
    Animation.prototype = {
        constructor:Animation,
        img:null,
        //移动过程
        frame:null,
        //动作的索引值
        index:null,
        //一个动作的进行时间
        time:null,
        //当前为多少帧
        frameNow:null,
        len:-1,
        
        init:function(){
            this.img = imgs["player"]||null;
            this.frame = this.frame||[];
            this.len = this.frame.length - 1;
            this.index = 0;
            this.setNow(this.index);
        },
        setNow:function(index){
            this.index = index;
            this.frameNow = this.frame[this.index];
        },
        //action为每个动作进行多长时间(前面传过来)
        update:function(sleep){
            if(this.time >= this.frameNow.action){
                this.time = 0;
                if(this.index >= this.len){
                    this.index = 0;
                }else{
                    this.index++;
                }
                
                this.setNow(this.index);
            }else{
                this.time += sleep;
            }
        },
        //人物的绘制
        draw:function(ct,x,y){
            var f = this.frameNow;
            ct.drawImage(this.img,f.x,f.y,f.w,f.h,x,y,60,60);
        }
        
    };
    View Code
    游戏类

    这个类里面一个主循环控制着我们所有移动的进行,这里我分步来说一下我遇到的问题。

    1.如何实现一个柱子倒下的过程,开始我的想法是画一个矩形,然后通过rotate来实现倾斜,因为以前没有用过rotate方法,进入尝试了一次,才知道他的倾斜是将整个画布倾斜,这样连背景一起倾斜,根本无法达到效果,然后通过在纸上画了一下,用数学知识解决了这个问题,我把矩形换成换线,改变他的lineWidth让他看起来像一个矩形。

    stick:function(){
            //当鼠标按下以后执行,并且在棍子移动时不会再次触发。
            if(this.moused && !this.clicked){
                this.time += this.sleep;
                //让棍子垂直向上伸展,通过循环让他的长度累加
                this.drawStick(this.time);   
                
            }else if(!this.moused && this.long > 0){
                //当鼠标松开(mouseup)以后,让棍子倒下去
                this.clicked = true;
                this.length = this.stickY - this.long;
                this.fallRect(this.length);
            }
        },
        //棍子向上伸展
        drawStick:function(time){
            this.time = time;
            this.long += (time/200)|0;
            this.ct.beginPath();
            this.ct.lineWidth = 5;
            this.ct.moveTo(this.stickX,this.stickY);
            this.ct.lineTo(this.stickX,this.stickY - this.long);
            this.ct.stroke();
        },
        //棍子向下掉落,记录下棍子的长度,就是人物行走的距离
        fallRect:function(length){
            this.length = length;
            if(this.angle < 30){
                this.angle += this.sleep/50;
                
                this.ct.beginPath();
                this.lineWidth = 5;
                this.ct.moveTo(this.stickX,this.stickY);
                
                var hudu = (2*Math.PI / 360) * 3 * this.angle;
                this.fallX = this.stickX + this.long*Math.sin(hudu);
                this.fallY = this.stickY - this.long*Math.cos(hudu);
                
                if(this.fallY >= this.stickY){
                    this.fallY = this.stickY;
                }
                this.ct.lineTo(this.fallX,this.fallY);
                this.ct.stroke();
            }else{
                this.ct.beginPath();
                this.lineWidth = 5;
                this.ct.moveTo(this.stickX,this.stickY);
                this.ct.lineTo(this.fallX,this.fallY);
                this.ct.stroke();
                this.success = true;
            }
        },
    View Code

     2.当我以为这个游戏已经结束的时候出现了一个bug,就是每次棍子的绘制路径都被保留下来了,这是我canvas控制能力不足,每次绘制之前加一个beginPath就好了。

    结束语

    在这里,感谢帮助我的每一个人,以后我也会成为大牛,写更多更好的博文,尽自己的力量去帮助更多人。

    最近在实验室学习,突然很想回家了,毕竟好久没看见家人了,还有10天就能回家了,心里还是很高兴。

    只有半年的时间就要去找工作了,有时间都去研究JS,感觉JS真是非常强大,我现在的水平想开发框架还是太难了,不过慢慢来吧,欲速则不达,一步一步积累终有一天我能自己开发框架。

    谢谢大家,如有什么疑问或者建议请留言。

  • 相关阅读:
    robot framework 文本校验,文本与关键字重复的处理
    python pip切本地源
    sqlalchemy 多个数据库地址配置
    python SQLAlchemy的简单配置和查询
    根据列表中字典中的某个value排序
    python SQLAlchemy中子查询subquery的使用
    python SQLAlchemy中query与query()
    weekly paper read
    C++调用windowsAPI
    English 邮件
  • 原文地址:https://www.cnblogs.com/xiaohaoxuezhang/p/4242438.html
Copyright © 2011-2022 走看看