微信小游戏实践

作者: 悟C | 来源:发表于2018-05-08 07:25 被阅读42次

    最近基于微信开发的H5小游戏越来越多,微信上每天都有各种小游戏的分享。于是我也初次浅尝,在微信上实现flappy bird这个曾经火爆大江南北的H5小游戏。 效果图如下:

    效果图1-1

    这是一款简单的小游戏,鸟儿会在重力的作用下,往下掉落。玩家需要点击屏幕,让鸟儿飞起并顺利的穿过管子才能得分,如果鸟儿撞击管子或者落地,则游戏结束。

    从上面一小段简单的描述我们了解实现这个游戏的几个点:

    • 点击屏幕让自由坠落的鸟飞起
    • 顺利穿过管道得分
    • 小鸟撞击管道或落地游戏结束

    根据这几点和效果,我们来实现这个游戏,项目结构如下:
    直接看代码,点这里

    │  ├── base                                   // 定义游戏开发基础类
    │  │   ├── animatoin.js                       // 帧动画的简易实现
    │  │   ├── pool.js                            // 对象池的简易实现
    │  │   └── sprite.js                          // 游戏基本元素精灵类
    │  ├── libs
    │  │   ├── symbol.js                          // ES6 Symbol简易兼容
    │  │   └── weapp-adapter.js                   // 小游戏适配器
    │  ├── npc
    │  │   └── enemy.js                           // 初始化管道和控制
    │  |   └── pipe.js                            // 管道类
    │  ├── player
    │  │   └── bird.js                           // 小鸟类
    │  ├── runtime
    │  │   ├── background.js                      // 背景类
    │  │   ├── gameinfo.js                        // 用于展示分数和结算界面
    │  |   ├── floor.js                           // 地板类
    │  │   └── music.js                           // 全局音效管理器
    │  ├── databus.js                             // 管控游戏状态
    │  └── main.js                                // 游戏入口主函数
    ├── game.js                                   // 游戏入口
    ├── game.json
    ├── project.config.json
    

    项目结构就是在官方给的Demo上进行修改的,这里就不做具体的介绍。请看官方文档,下面主要介绍一下enemy.js的实现,其他类都比较简单。

    enemy.js实现
    import DataBus from '../databus'
    import Pipe from './pipe'
    import Music from '../runtime/music'
    
    const databus = new DataBus()
    
    const screenWidth = window.innerWidth
    const screenHeight = window.innerHeight
    
    const pipeH = databus.pipeInfo.height;
    const pipeW = databus.pipeInfo.width;
    
    const constant = pipeH + databus.gap;
    
    function rnd(start, end) {
      return Math.floor(Math.random() * (end - start) + start)
    }
    
    export default class Enemy {
    
      constructor() {
        this.createdRndPipe();
        this.music = new Music();
      }
    
      setBird(bird) {
        this.bird = bird;
      }
    
      renderPipe(ctx) {
        
        let pipeLen = databus.pipe.length;
    
        for (let i = 0; i < pipeLen; i++) {
    
          const currPipeX = databus.pipe[i].x
          const currPipeY = databus.pipe[i].y
          
          this.pipeNorth = new Pipe('images/pipeNorth.png', currPipeX, currPipeY, ctx);
          this.pipeNorth.drawToCanvas(ctx);
    
          this.pipeSouth = new Pipe('images/pipeSouth.png', currPipeX, currPipeY + constant, ctx);
          this.pipeSouth.drawToCanvas(ctx);
        
          databus.pipe[i].x -= 1;
    
          if (databus.pipe[i].x == 12) {
            this.createdRndPipe();
          }
          
          this.collisionDetection(databus.pipe[i]);
          
          this.scorPlay(databus.pipe[i]);
        }
      }
    
      /**
       * 生产一个随机的管道
      */
      createdRndPipe() {
        const rndX = rnd(pipeH * 0.5, pipeH * 0.9) - pipeH
        databus.pipe.push({
          x: screenWidth,
          y: rndX
        });
      }
      
      /**
       * 分数打印
       * pipe => 当前pipe[i]
      */
      scorPlay(pipe) {
        if (pipe.x === 5) {
          databus.score += 1;
          this.music.playScore();
        }
      }
    
      /**
       * 检测是否碰撞pipe
      */
      collisionDetection(pipe) {
        const bird = this.bird;
        const bX = bird.x;
        const bY = bird.y;
        const bW = bird.width;
        const bH = bird.height;
    
        const floorH = 118;
    
        if (bX + bW >= pipe.x && bX <= pipe.x + pipeW && (bY <= pipe.y + pipeH || bY + bH >= pipe.y + constant) ||
          bY + bH >= screenHeight - floorH
        ) {
          databus.gameOver = true;
          this.music.playGameOver();
        }
      }
    }
    
    

    enemy.js类主包含管道的移动、新管道的生成、鸟和管道的碰撞检测。

    renderPipe主要是用来渲染管道的,我们在初始化databus.pipe数据容器的时候,会预先插入一个管道信息。然后通过遍历databus.pipe来绘制管道。

    1. 移动: 通过给每个管道的 x 坐标 -1实现移动
    2. 生产新管道:当有管道快走出屏幕时,生产一个新的管道插入到databus.pipe里面。
    3. 碰撞检测:
      • bX + bW >= pipe.x && bX <= pipe.x + pipeW 判断鸟在如下图<--->的位置。
      • 在满足上一条的情况下,并且满足(bY <= pipe.y + pipeH || bY + bH >= pipe.y + constant)就可以判断鸟在(1)或(2)的位置,这种情况为游戏结束。
      • 还有一种结束的情况是bY + bH >= screenHeight - floorH 就是鸟落地的情况。
        WechatIMG15.jpg
    总结

    H5游戏应该说是我的初次实践,第一感觉游戏主要是在canvas上进行元素绘制,然后各种操作元素的X、Y坐标和检测他们坐标之间的关系,当然这只是对简单的游戏而言。表面看起来和其他项目有很大的不同,其实都在写JavaScript。

    相关文章

      网友评论

        本文标题:微信小游戏实践

        本文链接:https://www.haomeiwen.com/subject/aasvrftx.html