• canvas画一个h5小游戏


      这两年,随着移动互联网的发展,h5小游戏也大火了一把。这里我就来讲讲实现一个躲水果的小游戏。如截图所示

      

      再附上demo二维码~

      

      目前游戏的套路,基本上是先载入游戏,然后触发游戏开始,游戏结束时记录游戏分数,诱导你转发盆友圈炫耀,或者再来一次。

      这里我们可以定义一个game_control 对象来控制这一系列流程,同时我们还需要一个人物对象,3个水果对象。

      我们可以定义一个基础原型对象ship作为类,可以记录位置,大小,x,y轴的移动速度,相应的图片,然后人物对象和水果对象就是它的几个实例啦。然后通过canvas的drawImage方法将它们画出在画布中。

    function ship(options){
                    if (options) {
                        var width=options.width,
                            height=options.height;
                        this.x=options.x;
                        this.y=options.y;
                        this.width=width;
                        this.height=height;
                        this.first_x=options.x;
                        this.first_y=options.y;
                        this.speedx=options.speedx;
                        this.speedy=options.speedy;
                        this.csspeedx=options.speedx;
                        this.csspeedy=options.speedy;
                        this.xDirection=options.xDirection||1;//x轴移动方向
                        this.yDirection=options.yDirection||1;//y轴移动方向
                        var canvasOffscreen = document.createElement('canvas');
                        canvasOffscreen.width =width;
                        canvasOffscreen.height =height;
                        canvasOffscreen.getContext('2d').drawImage(options.image, options.sourcex, options.sourcey, options.sourcewidth, options.sourceheight, 0, 0, width, height);
                        this.canvasOffscreen=canvasOffscreen;
                        this.init();
                    }
                }
     
                ship.prototype={
                    init:function(){
                         
                    },
                    reset:function(){
     
                    },
                    draw:function(ctx){
                        //let canvasOffscreen=this.canvasOffscreen;
                        ctx.drawImage(this.canvasOffscreen, this.x, this.y);
                    },
                    move:function(modifier){
                        this.x+=this.xDirection*this.speedx * modifier;
                        this.y+=this.yDirection*this.speedy * modifier;
                        if(this.x>winwidth-this.width){
                            this.x=winwidth-this.width;
                            this.xDirection=-1;
                        }else if(this.x<0){
                            this.x=0;
                            this.xDirection=1
                        }
                        if(this.y>winheight-this.height){
                            this.y=winheight-this.height;
                            this.yDirection=-1;
                        }else if(this.y<0){
                            this.y=0;
                            this.yDirection=1;
                        }
                    }
                }
    

      这个对象有个移动方法需要注意一下,我们需要判断物体到边界时,物体的移动方向需要转变(也就是将yDirection或者xDirection反向)。

      在这里我们可以将3个水果图片,和人物图片做成雪碧图。然后先将他们用canvas画出来,然后游戏进行中的每一帧将这些canvas再画出来,这样效率比每次都从雪碧图截取要高。

    var canvasOffscreen = document.createElement('canvas');
    canvasOffscreen.width = dw;
    canvasOffscreen.height = dh;
    canvasOffscreen.getContext('2d').drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
    
    // 在绘制每一帧的时候,绘制这个图形
    context.drawImage(canvasOffscreen, x, y);
    

      然后通过game_control中的draw方法画出

    draw:function(obj,ctx){
    					var ctx=this.ctx,
    						monsters=this.monsters;
    					var now=Date.now(),
    					def=now-this.then;
    					this.clear();
    					for(var i=0,len=monsters.length;i<len;i++){
    						if (this.then) {
    							monsters[i].move(def/1000);
    						}
    						monsters[i].draw(ctx);
    					}
    					if (this.then) {
    						this.check();
    						this.then = now;
    					}
    					this.objs.draw(ctx);
    				},
    

      game_control 对象定义几个方法,init,start,draw,end,reset等方法。

      init方法主要是初始化游戏的,主要处理图片加载,图片加载完后,几个对象的初始化。

      

    init:function(){
                        var canvas=document.getElementById('game-canvas'),
                            self=this,
                            ctx=canvas.getContext('2d');
                        self.ctx=ctx;
                        canvas.width=winwidth;
                        canvas.height=winheight;
                        let img=new Image();
                        img.onload=function(){
                            var zjb=new hero({
                                image:img,
                                x:gettruesize(250),
                                y:gettruesize(56),
                                gettruesize(50),
                                height:gettruesize(50),
                                source104,
                                sourceheight:104,
                                sourcex:0,
                                sourcey:0
                            });
                            for(var i=0;i<3;i++){
                                var x=60,y=110;
                                if(i==1){x=38,y=330;}
                                if(i==2){x=218,y=338;}
                                var monster=new ship({
                                                    image:img,
                                                    x:gettruesize(x),
                                                    y:gettruesize(y),
                                                    gettruesize(50),
                                                    height:gettruesize(50),
                                                    source104,
                                                    sourceheight:104,
                                                    speedx:gettruesize(getrandom(60,100)),
                                                    speedy:gettruesize(getrandom(60,100)),
                                                    sourcex:104*(i+1),
                                                    sourcey:0
                                                });
                                self.monsters.push(monster);
                            }
                            self.objs=zjb;
                            self.draw();
                            self.bindmove(canvas,zjb);
                        }
                        img.src="all.png";                 
                    }
    

      然后调用给bindmove方法给canvas注册手指触摸事件,如果手机触摸在人物对象这个位置,那么代表游戏开始,调用start方法。

      

    bindmove:function(canvas,hero){
                        let self=this;
                        canvas.addEventListener('touchstart', function(e) {
                            var event = e||window.event,
                                csx = event.touches[0].clientX,
                                csy = event.touches[0].clientY,
                                nanshengcsx = hero.x,
                                nanshengcsy = hero.y;
                            if (csx <= hero.x + hero.width && csx >= hero.x && csy <= hero.y + hero.height && csy >= hero.y) {
                                if (!self.startstate) {
                                    self.start();
                                    timer = setInterval(function(){
                                        self.draw();
                                    }, 1);
                                }
                                document.addEventListener('touchmove', move,false);
                                function move(e){
                                    e.preventDefault();
                                    var event = e||window.event,
                                        nowx = event.touches[0].clientX,
                                        nowy = event.touches[0].clientY;
                                    hero.x = nanshengcsx + nowx - csx;
                                    hero.y = nanshengcsy + nowy - csy;
                                    if(hero.x<0){
                                        hero.x=0;
                                    }else if(hero.x+hero.width>winwidth){
                                        hero.x=winwidth-hero.width;
                                    }
                                    if(hero.y<0){
                                        hero.y=0;
                                    }else if(hero.y+hero.height>winheight){
                                        hero.y=winheight-hero.height;
                                    }
                                }
                                function moveend(e){
                                    document.removeEventListener('touchend',moveend);
                                    document.removeEventListener('touchmove',move);
                                }
                                document.addEventListener('touchend', moveend ,false);
                            }
                        },false);
                    }
    

      

       start方法主要是实现每一帧的循环方法。

    var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
    					window.setTimeout(callback, 20);
    				};
    

      不断的去调用raf(fun)就可以啦,这里我直接用了setInterval方法

    start:function(){
                        var self=this;
                        this.startstate=true;
                        this.then=Date.now();
                        this.starttime=this.then;
                        document.getElementById('tips').style.display="none";
                        timer = setInterval(function(){
                            self.draw();//在画布中画出
                        }, 1);
                    }
    

       在循环方法中,通过手指的移动来计算 人物的x,y 轴的位置,通过时间 和 水果x,y 轴的速度计算出相应的位置,然后再进行一一比较,看是否发生触碰,同时,随着时间的推移,物体移动的速度慢慢新增,这里我们定了每5秒增加速度,这里我们将模型当作矩形(复杂模型我也不造怎么算~~),当发生触碰时,则判定游戏结束,将坚持了的时间输出。

    check:function(){
                        var last=this.then-this.starttime;
     
                        var monsters=this.monsters;
                        var nansheng=this.objs;
                        if (this.monsterSum != Math.floor(last / 5000)){//如果时间经过5秒就增加速度
                            this.monsterSum ++;  
                            for(var i=0;i<monsters.length;i++){
                                monsters[i].speedx+=60;
                                monsters[i].speedy+=60;
                            }
                        }  
                        for(var i=0;i<monsters.length;i++){
                            var monster1=monsters[i];
                            if ((monster1.x - nansheng.width) <= nansheng.x && nansheng.x <= (monster1.x + monster1.width) && (monster1.y - nansheng.height) <= nansheng.y && nansheng.y <= (monster1.y + monster1.height)) {
                                this.end();
                            }
                        }
                    }
    

      

        至于持续性的与后台的数据交互可以通过websocket来实现(不过我没有试过~~,当时做项目的时候只是结束的时候去保存了一下),游戏结束时提示 分享页面或者在玩一次即可。

      

      

      

  • 相关阅读:
    ES6 学习记录
    Windows 服务开发 以及 重启IIS应用池
    IIS部署.net core 3.1踩坑总结
    VS 2019背景全透明以及插件、特效
    深拷贝和浅拷贝的区别
    Vue全家桶以及常用知识点
    C#设计模式
    博客园装扮教程
    Exp5 单元测试
    Exp4 代码评审
  • 原文地址:https://www.cnblogs.com/bobogoodgoodstudy/p/6028256.html
Copyright © 2020-2023  润新知