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

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

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

目标:用eva.js在vue工程中实现fappy-bird游戏

完整的项目地址: demo

搭建vue框架,我使用的是vue cli3。先初始化好框架部分。删除不要的vue演示代码,定义自己的页面。

vue create evademo

然后安装eva.js

npm install @eva/eva.js

1、添加资源

首先将使用的资源图片统一放到一个js文件中,方便加载,新建一个resource.js文件,在里面定义资源对象。

一共使用了6个资源,其中2个静态图片(背景和地面),1个精灵图动画(小鸟扇翅膀),3个精灵图(开始界面菜单,结束界面菜单,上下管道)

资源图片放在了项目evademo/public/static 下面,(放在其他地方eva.js的resource读取不出来,有能力的小伙伴可以自己尝试来补充下)。

import { RESOURCE_TYPE } from "@eva/eva.js";
export default [
    name: "bg",
    type: RESOURCE_TYPE.IMAGE,
    src: {
      image: {
        type: "png",
        url: "./../../public/bg.png",
    preload: true,
    name: "ground",
    type: RESOURCE_TYPE.IMAGE,
    src: {
      image: {
        type: "png",
        url: "@/../static/ground.png",
    preload: true,
    name: "ready",
    type: RESOURCE_TYPE.SPRITE,
    src: {
      image: {
        type: "png",
        url: "@/../static/ready/ready.png",
      json: {
        type: "json",
        url: "@/../static/ready/ready.json",
    preload: true,
    name: "bird",
    type: RESOURCE_TYPE.SPRITE_ANIMATION,
    src: {
      image: {
        type: "png",
        url: "@/../static/bird/bird.png",
      json: {
        type: "json",
        url: "@/../static/bird/bird.json",
    preload: true,
    name: 'over',
    type: RESOURCE_TYPE.SPRITE,
    src: {
      image: {
        type: 'png',
          '@/../static/over/over.png',
      json: {
        type: 'json',
          '@/../static/over/over.json',
    preload: true,
    name: 'bar',
    type: RESOURCE_TYPE.SPRITE,
    src: {
      image: {
        type: 'png',
          '@/../static/bar/bar.png',
      json: {
        type: 'json',
          '@/../static/bar/bar.json',
    preload: true,

2、创建游戏对象

创建一个vue文件index.vue, 在其中创建canvas标签,导入相应的包,导入之前创建的资源js文件,添加资源,准备工作就完成了。

注意:在这里我们需要对之后会用到的一些组件安装、导入、并且在systems里设置new XXXX();如果不设置,在后面的addComponent中就不会有任何效果。如果发现添加了组件没有生效,记得检查是否在systems中配置了。

<template>
    <canvas id="canvas"></canvas>
  </div>
</template>
<script>
import { resource, Game, GameObject, RESOURCE_TYPE } from "@eva/eva.js";
import { Render, RenderSystem } from "@eva/plugin-renderer-render";
import { Event, EventSystem, HIT_AREA_TYPE } from "@eva/plugin-renderer-event";
import { Text, TextSystem } from "@eva/plugin-renderer-text";
import sources from "./birdResource";
import { Sprite, SpriteSystem } from "@eva/plugin-renderer-sprite";
import {
  SpriteAnimation,
  SpriteAnimationSystem,
} from "@eva/plugin-renderer-sprite-animation";
SpriteAnimation;
import { Transition, TransitionSystem } from "@eva/plugin-transition";
import {
  TilingSprite,
  TilingSpriteSystem,
} from "@eva/plugin-renderer-tiling-sprite";
import { PhysicsSystem, Physics, PhysicsType } from "@eva/plugin-matterjs";
import { Img, ImgSystem } from "@eva/plugin-renderer-img";
export default {
  mounted() {
    this.show();
   methods: {
    show() {
      resource.addResource(sources);
      this.game = new Game({
        frameRate: 61, // 兼容Eva自身bug, 帧率必须大于60
        autoStart: true, // 可选
        systems: [
          new RendererSystem({
            canvas: document.querySelector("#canvas"),
            width: this.sceneWidth,
            height: this.sceneHeight,
            resolution: window.devicePixelRatio / 2,
          new TilingSpriteSystem(),
          new TransitionSystem(),
          new SpriteAnimationSystem(),
          new RenderSystem(),
          new EventSystem({
            // moveWhenInside: true // 代表只有在元素内部才会执行move事件,默认为false
          new ImgSystem(),
          new TextSystem(),
          new SpriteSystem(),
          new PhysicsSystem({
            resolution: window.devicePixelRatio / 2,
            // isTest: true, // Whether to enable debugging mode
            // element: document.querySelector(".debugger"), 
            world: {
              gravity: {
                y: 5, // gravity
</script>
<style>
#canvas {
  width: 100%;
  height: auto;
</style>

背景分为2个部分,一个部分背景,一部分是地面,用于判断小鸟落地。

1、添加背景

首先定义屏幕的宽度的长度

 data() {
    return {
      sceneWidth: 750,
      sceneHeight: (window.innerHeight / window.innerWidth) * 750,
    	game:''// 整个游戏的对象

创建的方法我们都放在creatBg()方法里

createBg() { // 创建 game object const bg = new GameObject("image", { size: { width: this.sceneWidth, height: this.sceneHeight }, origin: { x: 0, y: 0 }, position: { x: 0, y: 0, anchor: { x: 0, y: 0, // 为 game object 添加 Image Component bg.addComponent( new Img({ resource: "bg", this.game.scene.addChild(bg); bg.addComponent( new Render({ zIndex: 1, //将背景图放在底层

这样背景就会显示在我们的界面中了

2、添加地面

地面是一个png图片,如果直接添加的话对于之后的移动效果不太好实现,所以采用精灵平铺的方式,这样就可以做出一个无限长的地板图片,可以一直移动。通过地面的anchor、origin、scale属性将图置于背景图片的底部,这里的地板图片不是添加到game上,而是作为bg的addChild添加到了bg对象中

  const ground = new GameObject("ground", {
        size: { width: this.sceneWidth, height: this.sceneHeight / 4 },
        position: { x: 0, y: 0 },
        anchor: {
          x: 0,
          y: 1,//将地面至于背景底部
        origin: {
          x: 0.5,
          y: 0.5,
        scale: { x: 2, y: 2 }, // 缩放比例
  const groundTilingSprite = new TilingSprite({
        resource: "ground",
        tileScale: { x: 1, y: 1 },
        tilePosition: { x: 0, y: 0 },
 ground.addComponent(groundTilingSprite);
//添加为地板添加物理属性,使小鸟可以落到地板上
 ground.addComponent(
        new Physics({
          type: PhysicsType.RECTANGLE,
          bodyOptions: {
            isStatic: true,
 bg.addChild(ground);//将地板添加在背景里

3、地面动起来

思路:通过改变Transform 属性,在每一帧调用一次position.x的位置改变

在Game对象中,有一个ticker.add方法可以执行每一帧调用一次的方法。

this.game.ticker.add(() => {
    ground.tilePosition.x -= 1;

创建准备开始游戏界面

在我们的ready标题界面中,有2个元素(红色小鸟是后面添加,暂时当看不见),一个是绿色标题,一个是红色带点击部分的图片,2个图片放在了一个精灵图上

思路:创建一个总的readyBox的gameObject,然后分别添加2个元素进来

1、创建readyBox

 const readyBox = new GameObject("readyBox", {
  	 size: { width: 320, height: 80 },
     position: {
     		x: 128,
 		 		y: this.sceneHeight / 4,

这里的x,y,宽度和高度是根据自己的需要计算出来的,主要是为了让第一个标题居中和定位他的离顶部的距离

2、添加标题和添加tap图片

添加标题的时候也是添加一个新的gameObject对象,在对象中添加Sprite组件,将我们的图片显示出来

    const readyTitle = new GameObject("readyTitle", {
        size: { width: 512, height: 144 },
        position: {
          x: 0,
          y: 0,
      readyTitle.addComponent(
        new Sprite({
          resource: "ready",
          spriteName: "ready_title.png",
      const readyTap = new GameObject("readyTitle", {
        size: { width: 294, height: 273 },
        position: {
          x: 120,
          y: 188,
      readyTap.addComponent(
        new Sprite({
          resource: "ready",
          spriteName: "ready_tap.png",
 readyBox.addChild(readyTitle);
 readyBox.addChild(readyTap);
 this.game.scene.addChild(readyBox);

添加完成以后,还需要添加2个事件,就是隐藏和显示这个readyBox的事件。通过过渡动画来改变对象的透明度alpha来实现。

//如果需要在其他方法中调用,记得要把animation对象抛出来再调用
const animation = readyBox.addComponent(new Transition());
      animation.group = {
        hidden: [
            name: "alpha",
            component: render,
            values: [
                time: 0,
                value: 1,
                tween: "linear",
                time: 20,
                value: 0,
                tween: "linear",
        show: [
            name: "alpha",
            component: render,
            values: [
                time: 0,
                value: 0,
                tween: "linear",
                time: 20,
                value: 1,
                tween: "linear",

通过调用创建的对象里的animation对象来触发显示隐藏

如果需要在其他方法中调用,记得要把animation对象抛出来再调用

 animation.play("show", 1);//1代表执行1次
 animation.play("hidden", 1);

3、添加点击开始事件

思路:通过交互事件实现,在我们需要点击的gameObject上添加Event对象,通过监听和触发emit来操作我们的raedyBox,由于我们只需要点击readyTap对象,所以事件只添加在这个对象上然后通过一个emit方法将操作抛出去,方便我们后续操作。之后在game对象的监听中调用。

const evt = readyTap.addComponent(
        new Event({
          type: HIT_AREA_TYPE.Rect,
  evt.on("tap", () => {
   //点击后调用
    this.game.emit("on-game-ready");
//我们在之前的show()方法中监听抛出的来的方法
this.game.on("on-game-ready", (e) => {
  //点击开始后你想做什么操作

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

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

分类:
前端
  •