EVA.js学习笔记(六)实践fappy-bird游戏(下)

421 阅读4分钟

EVA.js学习笔记(六)实践fappy-bird游戏(下)

# EVA.js学习笔记(四)实践fappy-bird游戏(上)

# EVA.js学习笔记(五)实践fappy-bird游戏(中)

# VA.js学习笔记(六)实践fappy-bird游戏(下)

游戏的基本流程创建完成后,就可以开始增加游戏逻辑,添加管道来让小鸟躲避,躲避成功就获取得分,整个游戏就完成了

所以我们首先来创建管道

一、创建单组管道

\

 createBar(distance, x, y, cWidth, cHeigt) {
      const bar = new GameObject("bar", {
        size: { width: cWidth, height: cHeigt },
        origin: { x: 0.5, y: 0.5 },
        position: {
          x: x,
          y: y,
        },

        anchor: {
          x: 0,
          y: 0,
        },
      });
      bar.addComponent(
        new Sprite({
          resource: "bar",
          spriteName: distance,
        })
      );

      let physics = bar.addComponent(
        new Physics({
          type: PhysicsType.RECTANGLE,
          bodyOptions: {
            isStatic: true, // Whether the object is still, any force acting on the object in a static state will not produce any effect
            restitution: 0,
            frictionAir: 0,
            friction: 0,
            frictionStatic: 0,
            force: {
              x: 0,
              y: 0,
            },
            stopRotation: true, // default false, usually do not need to be set
          },
        })
      );
      bar.addComponent(new Move());//添加移动功能,具体使用往下看
      bar.addComponent(new Next());//添加创建新管道功能。具体使用往下看
      bar.addComponent(
        new Render({
          alpha: 1,
          zIndex: 8,
        })
      );


      this.game.scene.addChild(bar);
      return { bar, physics };
    },

创建管道有几个需要注意的点:

1、创建一组管道,分为上管道和下管道,所以一组就是2个管道,以下的方法通过传参数来创建2个管道,所以需要调用2次来创建上下2个管道

写一个createBars方法

createBars() {
      let allHeight = (this.sceneHeight * 3) / 4;
      let barWidth = this.barWidthDefault;
      let x = this.sceneWidth - barWidth * -0.5;
      let topHeight = 802;
      let space = 250;
      let hard = 100; //起伏高度
      let mixHeight = 40;
      let bottomHeight = Math.random() * hard + space + mixHeight;

      const top = this.createBar("bar_r.png", x, 0, barWidth, topHeight);
      const bottom = this.createBar(
        "bar.png",
        x,
        (this.sceneHeight * 3) / 4 - bottomHeight / 2,
        barWidth,
        bottomHeight
      );

      return { top, bottom };
    },

2、管道需要添加物理属性,当鸟撞上的时候就可以通过鸟的监听来执行操作。

3、管理里面添加的new Move和new Next是采用了eva.js里的脚本组件功能,其中的update方法就是每帧执行的方法,在game对象中,game.ticker.add方法也是每一帧执行方法,但是官方建议在Component中的update方法实增加每帧执行的方法,也可以使用add 方法,该方法将会在所有System的lateUpdate执行后执行

二、移动

因为管道使用了物理属性,所以无法通过EVA自带的过渡动画来移动,所以需要通过物理属性里的Matter.Body.translate来进行移动

首先创建文件Move.js

import { Game, Component, GameObject } from '@eva/eva.js'
import { Physics } from '@eva/plugin-matterjs'
import Matter from 'matter-js'
export default class Move extends Component {
  gameObject
  static componentName = 'move'
  constructor() {
    super()
  }
  update() {
    const physics = this.gameObject.getComponent(Physics)
    if (window.game && physics.body) {
      if (window.game.playing) {
        let pushVec = Matter.Vector.create(-5, 0)//向左位移5
        Matter.Body.translate(physics.body, pushVec)
      }
    }
  }
}

引入后就能够使用

  bar.addComponent(new Move());

来添加移动效果了。

三、创建多组管道

思路:

判断管道的位置,当管道移动到500的时候,就创建一个组新管道,当管道溢出屏幕后,就把自己删除

每一个管道只负责创建下一个管道,然后溢出屏幕后就被删除

首先创建Next.js

需要判断下,游戏在开始的时候,才执行操作

import { Game, Component, GameObject } from "@eva/eva.js";
import { Physics } from "@eva/plugin-matterjs";
import Matter from "matter-js";

export default class Next extends Component {
  gameObject;
  isAdd;
  static componentName = "next";

  constructor() {
    super();
  }

  update() {
    const physics = this.gameObject.getComponent(Physics);
    if (window.game.playing) {
    
      if (physics.body) {
        let x = physics.body.position.x;//获取管道的位置
        let isTop = physics.body.position.y == 0 ? true : false;
        //溢出屏幕
        if (x == -80) {
          this.gameObject.getComponent(Physics).removeAllListeners();

          window.game.scene.removeChild(this.gameObject);

          this.gameObject.destroy();
        }
      
        this.isAdd = false; //防止重复添加
        if (!this.isAdd && x == 500) {
          this.isAdd = true;
          //新建一组管道
          //只判断下面的管道,否则会重复创建,因为该方法在上下管道都有,所以是执行2次的
          if (isTop) {
            window.game.emit("createBar", "down");
          }
        }
      }
    }
  }

}

createBar的监听

 this.game.on("createBar", (e) => {
   this.createBars();
 });

\

四、创建得分

首先通过eva.js中的Text来创建得分显示

 createScore() {
      const text = new GameObject("score", {
        position: {
          x: 40,
          y: 80,
        },
        origin: {
          x: 0,
          y: 0,
        },
        anchor: {
          x: 0,
          y: 0,
        },
      });

      text.addComponent(
        new Text({
          text: "得分:0",
          style: {
            fontFamily: "Arial",
            fontSize: 36,
            fontStyle: "italic",
            fontWeight: "bold",
            fill: "#fff",
            stroke: "#000",
            strokeThickness: 5,
            dropShadow: true,
            dropShadowColor: "#000000",
            dropShadowBlur: 4,
            dropShadowAngle: Math.PI / 6,
            dropShadowDistance: 6,
            wordWrap: true,
            wordWrapWidth: 400,
            breakWords: true,
          },
        })
      );

      this.game.scene.addChild(text);
    },

然后判断当小鸟通过了管道后增加得分

思路:

要判断小鸟通过管道得分,但是实际小鸟的X坐标不会变,变的是管道的 X坐标,可以通过管道的X位置小于小鸟的X位置,从而判断出小鸟通过了管道,所以可以在之前的Next.js中添加

....
  update() {
    const physics = this.gameObject.getComponent(Physics);
    if (window.game.playing) {
  		  ...
        //60是小鸟的位置,
        if (x == 60) {
          //只判断下面的管道

          if (isTop) {
            window.game.emit("getScore");
          }
        }
       ...
    }
  }
  lateUpdate() {
    if (window.game.playing) {
      // console.log("得分lateUpdatelateUpdatelateUpdate");
    }
  }
}

getScore的监听方法

  this.game.on("getScore", () => {
        this.score++;

        this.updateScode("score", this.score);
      });

updateScode方法,先找到name叫score这个game对象,然后更改text的显示值

 updateScode(name, value) {
      const score = this.game.scene.gameObjects.find((item) => {
        return item.name == name;
      });

      const text = score.getComponent(Text);

      text.text = "得分:" + value;
    },

五、完成游戏

到此为止游戏也差不多完成了,总的来说要完成一个简单的互动小游戏是非常方便的,官方也有很多参考的案例,这个demo做完后差不多也对常用的组件熟悉了,算刚好入门,等有时间会尝试做一些其他的游戏。