D23 - 「不断线的侏罗纪」:有一只小恐龙在跑步

来建立我们的主角小恐龙吧。

建立组件

建立小恐龙组件 dino.vue

src\components\window-app-google-dino\dino.vue

<template lang="pug">
.dino
</template>

<style scoped lang="sass">
.dino
  position: absolute
  width: 80px
  bottom: 30px
  left: 30px
</style>

<script>
export default {
  name: 'Dino',
  components: {},
  props: {},
  data() {
    return {};
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {},
  beforeDestroy() {},
  methods: {},
};
</script>

game-scene.vue 引入 dino.vue

src\components\window-app-google-dino\game-scene.vue <script>

// ...

import { mapState } from 'vuex';

import Dino from './dino.vue';

export default {
  name: 'GameScene',
  components: {
    dino: Dino,
  },
  // ...
};

src\components\window-app-google-dino\game-scene.vue <template lang="pug">

.game-scene(@click='start')
  .ground
  dino(ref='dino')

  // ...

注入灵魂

再来帮小恐龙加入图片、动画等等效果,注入灵魂。

将准备好的图片放入 src\assets\google-dino 目录并新增以下变数。

src\components\window-app-google-dino\dino.vue <script>

/**
 * @typedef {Object} Status 人物状态
 * @property {Boolean} jumping 跳跃
 * @property {Boolean} squatting 蹲下
 */

import imgJump from '@/assets/google-dino/dino-jump.png';

export default {
  name: 'Dino',
  // ...
  data() {
    return {
      /** @type {Status} */
      status: {
        jumping: false,
        squatting: false,
      },

      /** 目前显示图片 */
      imgSrc: imgJump,

      /** 计时器,处理图片动画 */
      timer: null,
    };
  },
  // ...
};

methods 新增功能。

import imgRun01 from '@/assets/google-dino/dino-run-1.png';
import imgRun02 from '@/assets/google-dino/dino-run-2.png';
import imgJump from '@/assets/google-dino/dino-jump.png';
import imgDie from '@/assets/google-dino/dino-die.png';
import imgSquat01 from '@/assets/google-dino/dino-squat-1.png';
import imgSquat02 from '@/assets/google-dino/dino-squat-2.png';

export default {
  name: 'Dino',
  // ...
	methods: {
    /** 开始 */
    start() {
      this.status.jumping = false;
      this.status.squatting = false;

      this.timer = setInterval(() => {
        this.processSpriteImg();
      }, 150);
    },
    /** 结束 */
    over() {
      this.imgSrc = imgDie;
      clearInterval(this.timer);
    },

    /** 透过切换图片的方式动画 */
    processSpriteImg() {
      /** @type {Status} */
      const status = this.status;

      // 跑步
      if (this.imgSrc === imgRun01) {
        this.imgSrc = imgRun02;
      } else {
        this.imgSrc = imgRun01;
      }
    },
  },
  // ...
};

透过 props 取得游戏状态并侦测状态变化,执行对应动作。

src\components\window-app-google-dino\dino.vue <script>

// ...

import { GameStatus } from './game-scene.vue';

export default {
  name: 'Dino',
	// ...
	props: {
    gameStatus: {
      type: String,
      default: '',
    },
  },
  // ...
	watch: {
    gameStatus(status) {
      if (status === GameStatus.START) {
        this.start();
        return;
      }

      if (status === GameStatus.GAME_OVER) {
        this.over();
        return;
      }
    },
  },
  // ...
};

记得 game-scene.vue 模板中的 dino 也要加入参数。

src\components\window-app-google-dino\game-scene.vue <template lang="pug">

.game-scene(@click='start')
  .ground
  dino(ref='dino', :game-status='gameStatus')

	// ...

最後在 .dino 下方加个 img 显示小恐龙图片。

src\components\window-app-google-dino\dino.vue <template lang="pug">

.dino
  img(:src='imgSrc')

目前应该会长这样。

Untitled

点一下画面,看看游戏开始後小恐龙会不会开始跑步。

D23 - 小恐龙跑步.gif

小恐龙成功开跑!

更多动作

再来就是让小恐龙跳跃和蹲下了。

跳跃

跳跃动画使用 GSAP 实现。

GSAP 是一套专门处理动画与特效的 JS 套件,可以实现动画时间轴管理等等功能,功能非常强大。

概念为「透过 GSAP 控制跳跃高度数值,并将高度数值绑定至 CSS 样式,呈现 DOM 移动效果」。

实作过程如下:

  • data()

    • yOffset:目前跳跃高度。
    • gsapAni:储存 GSAP 动画变数。
  • methods

    • processSpriteImg():加入跳跃图片
    • initGsapAni():初始化 GSAP 物件
    • jump():开始跳跃。呼叫 GSAP 跳跃动画物件
  • computed

    • style:将变数转为 CSS 属性
  • created()

    呼叫 initGsapAni()

src\components\window-app-google-dino\dino.vue <script>

// ...

import { gsap } from 'gsap';

export default {
  name: 'Dino',
  // ...
  data() {
    return {
      // ...

      /** 跳跃量 */
      yOffset: 0,

			/** GSAP 动画 */
      gsapAni: {
        jump: null,
      },
    };
  },
	computed: {
    style() {
      return {
        transform: `translateY(-${this.yOffset}px)`,
      };
    },
  },
	created() {
    // 初始化 GSAP 动画物件
    this.initGsapAni();
  },
	// ...
	methods: {
    // ...

		/** 透过切换图片的方式动画 */
    processSpriteImg() {
      /** @type {Status} */
      const status = this.status;

			// 跳跃
      if (status.jumping) {
        this.imgSrc = imgJump;
        return;
      }

      // 跑步
      if (this.imgSrc === imgRun01) {
        this.imgSrc = imgRun02;
      } else {
        this.imgSrc = imgRun01;
      }
    },

    /** 初始化 GSAP 动画 */
    initGsapAni() {
      /** @type {Status} */
      const status = this.status;

      const jumpTimeline = gsap.timeline();

			// 动画持续时间
      const duration = 0.32;

      jumpTimeline
        .to(this, {
          duration,
          yOffset: 150,
          ease: 'power1.out',
          onStart() {
            status.jumping = true;
          },
        })
        .to(this, {
          duration,
          yOffset: 0,
          ease: 'power1.in',
          onComplete() {
            status.jumping = false;
          },
        })
        .pause();

      this.gsapAni.jump = jumpTimeline;
    },

    /** 跳跃 */
    jump() {
			if (this.status.jumping) return;

      this.gsapAni.jump.restart();
    },
  // ...
};

除了绑定 style 外,加入 @click,测试跳跃动画。

src\components\window-app-google-dino\dino.vue <template lang="pug">

.dino(:style='style', @click='jump')
  img(:src='imgSrc')

点击看看小恐龙会不会跳跃。

D23 - 小恐龙跳跃.gif

成功起跳!

蹲下

蹲下动作就简单很多,单纯就是状态切换而已。

实作过程如下:

  • methods
    • processSpriteImg():加入蹲下图片
    • setSquat():设定是否蹲下

src\components\window-app-google-dino\dino.vue <script>

// ...

export default {
  name: 'Dino',
	// ...
	methods: {
    // ...

		/** 透过切换图片的方式动画 */
    processSpriteImg() {
			/** @type {Status} */
      const status = this.status;

			// 跳跃
      if (status.jumping) {
        this.imgSrc = imgJump;
        return;
      }

			// 蹲下
      if (status.squatting) {
        if (this.imgSrc === imgSquat01) {
          this.imgSrc = imgSquat02;
        } else {
          this.imgSrc = imgSquat01;
        }
        return;
      }

      // 跑步
      if (this.imgSrc === imgRun01) {
        this.imgSrc = imgRun02;
      } else {
        this.imgSrc = imgRun01;
      }
    },

    // ...

		/** 设定是否蹲下 */
    setSquat(status = true) {
      this.status.squatting = status;
    },
};

这次使用右键测试「蹲下」动作,按着蹲下,放开回复动作。

src\components\window-app-google-dino\dino.vue <template lang="pug">

.dino(
  :style='style',
  @click='jump',
  @mousedown.right='setSquat(true)',
  @mouseup.right='setSquat(false)',
  @contextmenu.prevent
)
  img(:src='imgSrc')

尝试看看是否左键跳跃,右键蹲下。

D23 - 小恐龙蹲下.gif

成功!恭喜复活恐龙惹!(´,,•ω•,,)

最後是最容易忘记也最重要的一步,就是销毁计时器。利用 beforeDestroy() 呼叫 over() 达成效果。

src\components\window-app-google-dino\dino.vue <script>

export default {
  name: 'Dino',
  // ...
  beforeDestroy() {
    this.over();
  },
  // ...
};

总结

  • 完成「小恐龙」组件。
  • 完成小恐龙动作动画。
  • 成功让小恐龙跳跃、蹲下。

以上程序码已同步至 GitLab,大家可以前往下载:

GitLab - D23


<<:  Android Studio初学笔记-Day22-ToolBar

>>:  予焦啦!附录:旅途拾贝

[Day 26] BDD - 组合技

组合技 Drone + godog + Mattermost 当有需求要在k8s上透过drone定期...

【LeetCode】当初的 LeetCode 学习

有点受不了没什麽演算法底子还要掰出 Leetcode 文章QQ 今天来记录当初学习的过程和後来的想法...

Day22 类别与物件--魔术方法2 及 封装private

物件导向的封装特性 封装特性:在一个物件产生之後,物件的部分成员属性和成员方法在逻辑上是不允许在物件...

[Day 07] placeholder

写在前面 placeholder for test placeholder for test pla...

DAY24-资讯卡页面设计

前言: 昨天我们介绍了一个普通的资讯页面是如何完成的,今天我们要来介绍另一个很常用到的页面种类,资...