D21 - 「不断线的侏罗纪」:萃取 DNA

这个章节开始我们要重现 Chrome 浏览器离线时出现的小游戏「Dinosaur Game」,首先来好好规划一下游戏的蓝图。

视窗规划

  • 视窗主体

    负责提供脚位资料、设定栏位。

  • 游戏场景

    包含所有游戏角色等等。

D21 - 规划小恐龙游戏场景.png

游戏规划

D21 - 规划小恐龙游戏场景.png

场景包含:

  • 分数

    随时间自动增加,每 0.1 秒增加 1 分。

  • 云朵

    随机生成,向左移动,营造恐龙向右跑的感觉。

  • 提示文字

    根据目前游戏状态,显示对应文字,提示玩家该如何动作。

  • 仙人掌

    随机生成仙人掌,样式随机,向左移动。

  • 小恐龙

    原地向上跳跃,有跑步、跳跃、蹲下、死亡样式。

    使用两个按钮控制「跳跃」与「蹲下」。

游戏逻辑为:

  • 游戏状态分为「待机」、「开始」、「结束」。
  • 「仙人掌」与「恐龙」需要进行碰撞侦测。
  • 一旦「恐龙」发生碰撞,游戏状态变为结束,画面冻结,结束游戏。
  • 「云朵」与「仙人掌」会随着分数的提高而增加速度,但不会超过最大速度。

建立「视窗主体」

建立 window-app-google-dino 资料夹管理相关组件并建立 window-app-google-dino.vue 视窗组件。

内容概念与「调色盘」相同。

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

/**
 * @typedef {import('@/script/modules/port-transceiver').default} PortTransceiver
 *
 * @typedef {import('@/types/type').PinInfo} PinInfo
 * @typedef {import('@/types/type').PinCapability} PinCapability
 */

import { mapState } from 'vuex';

import mixinWindow from '@/mixins/mixin-window';

import BaseWindow from '@/components/base-window.vue';
import BaseSelectPin from '@/components/base-select-pin.vue';

import { PinMode } from '@/script/utils/firmata.utils';
const { INPUT_PULLUP } = PinMode;

export default {
  name: 'WindowAppGoogleDino',
  components: {
    'base-window': BaseWindow,
    'base-select-pin': BaseSelectPin,
  },
  mixins: [mixinWindow],
  props: {},
  data() {
    return {
      jumpPin: null,
      squatPin: null,
    };
  },
  computed: {
    ...mapState({
      boardPins: (state) => state.board.info.pins,
    }),

    /** 支援功能的脚位 */
    supportPins() {
      /** @type {PinInfo[]} */
      const boardPins = this.boardPins;

      return boardPins.filter((pin) =>
        pin.capabilities.some((capability) => INPUT_PULLUP === capability.mode)
      );
    },

    /** 设定是否完成 */
    isSettingOk() {
      return this.jumpPin && this.squatPin;
    },
  },
  watch: {
    jumpPin(newVal, oldVal) {
      this.handlePinSelect(newVal, oldVal);
    },
    squatPin(newVal, oldVal) {
      this.handlePinSelect(newVal, oldVal);
    },
  },
  created() {},
  mounted() {},
  methods: {
    /** 处理脚位选择事件,回报 Vuex 新增、移除占用脚位
     * @param {PinInfo} newVal
     * @param {PinInfo} oldVal
     */
    handlePinSelect(newVal, oldVal) {
      if (newVal) {
        this.$store.commit('window/addOccupiedPin', {
          id: this.id,
          pin: newVal,
        });
      }

      if (oldVal) {
        this.$store.commit('window/deleteOccupiedPin', {
          id: this.id,
          pin: oldVal,
        });
      }
    },
    /** 处理错误讯息 */
    handleErr(msg) {
      this.$q.notify({
        type: 'negative',
        message: msg,
      });
    },
  },
};

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

base-window.window-app-google-dino(
  header-icon='r_videogame_asset',
  body-class='c-col h-400px',
  title='跑跑小恐龙'
)
  .h-full.overflow-hidden
    // 游戏场景(还没建立)

    // 设定栏位
    transition(name='fade-up')
      .setting-form(v-if='!isSettingOk')
        .form-section
          .form-item.mb-20px
            q-icon.mr-10px(name='r_gamepad', size='20px')
            .text-18px.font-700
              | 设定控制器

          .form-item
            .text-16px.w-100px
              | 跳跃
            base-select-pin.w-full(
              v-model='jumpPin',
              :pins='supportPins',
              color='light-green-4',
              placeholder='点击选择',
              @err='handleErr'
            )

          .form-item
            .text-16px.w-100px
              | 蹲下
            base-select-pin.w-full(
              v-model='squatPin',
              :pins='supportPins',
              color='light-green-4',
              placeholder='点击选择',
              @err='handleErr'
            )

src\components\window-app-google-dino\window-app-google-dino.vue <style scoped lang="sass">

@import '@/styles/quasar.variables.sass'

.window-app-google-dino
  width: 700px

.setting-form
  position: absolute
  top: 0%
  left: 0px
  width: 100%
  height: 100%
  padding: 20px
  background: rgba(white, 0.9)
  backdrop-filter: blur(4px)
  display: flex
  justify-content: center
  .form-section
    padding: 20px
    width: 50%
    border-radius: $border-radius-m
    box-shadow: $focus-shadow

  .form-item
    display: flex
    align-items: center
    margin-bottom: 20px

接着回到 app.vue,将右键选单内加入『新增「跑跑小恐龙」』选项,并引入组件。

src\app.vue <template lang="pug">

.screen(@click='handleClick')
  // ...

  // 右键选单
  q-menu(context-menu, content-class='border-radius-s')
    q-list.min-w-260px
      q-item(@click='addWindow("window-digital-io")', clickable, v-close-popup)
        q-item-section
          | 新增「数位 I/O 视窗」
			q-item(@click='addWindow("window-analog-input")', clickable, v-close-popup)
        q-item-section
          | 新增「类比输入视窗」
			q-item(@click='addWindow("window-pwm-output")', clickable, v-close-popup)
        q-item-section
          | 新增「PWM 输出视窗」
			q-separator

      q-item(
        @click='addWindow("window-app-rgb-led-palette")',
        clickable,
        v-close-popup
      )
        q-item-section
          | 新增「RGB LED 调色盘」
			q-item(
        @click='addWindow("window-app-google-dino")',
        clickable,
        v-close-popup
      )
        q-item-section
          | 新增「跑跑小恐龙」

src\app.vue <script>

// ...

import WindowDigitalIo from '@/components/window-digital-io.vue';
import WindowAnalogInput from '@/components/window-analog-input.vue';
import WindowPwmOutput from '@/components/window-pwm-output.vue';

import WindowAppRgbLedPalette from '@/components/window-app-rgb-led-palette/window-app-rgb-led-palette.vue';
import WindowAppGoogleDino from '@/components/window-app-google-dino/window-app-google-dino.vue';

export default {
  name: 'App',
  components: {
    'dialog-system-setting': DialogSystemSetting,
    
    'window-digital-io': WindowDigitalIo,
    'window-analog-input': WindowAnalogInput,
    'window-pwm-output': WindowPwmOutput,

    'window-app-rgb-led-palette': WindowAppRgbLedPalette,
    'window-app-google-dino': WindowAppGoogleDino,
  },
  // ...
};

D21 - 跑跑小恐龙视窗主体建立完成.gif

视窗基本功能建立完成!

硬体实作

准备的设备内容同「D11 数位功能」:

  • 三用电表 * 1

  • 面包板 * 1

  • 按钮 * 2

    2021-09-12 17.44.27-1.jpg

检查硬体

标准作业流程。

按钮

利用三用电表确认按钮是否能够正常通导。

D11 - 确认按钮正常.png

连接电路

以下为参考接线方式,可以不用完全相同,只要效果相同即可。

使用 Uno 板子上的 5V 为 +、GND 为 -。

为了让电路简单,这里我们一律都使用「上拉输入」。

D21 - 控制按钮电路 (1).png

下一章节要来实际建立游戏场景!

总结

  • 完成游戏规划
  • 建立「跑跑小恐龙」视窗
  • 完成控制器电路

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

GitLab - D21


<<:  乙太网路光纤通道标准(FCoE)

>>:  【Day 23】Pointer 指标

我想成为架构师-计划蓝图

继上次废话之後,此次话不多说!正入主题!! 此次我给自己安排计画能将会一笔一笔列出,也就是我未来将循...

Day22 探讨Templates

经过这几天的介绍,相信大家也越来越了解它里面包含的功能了吧! 多了解一些东西,对之後的开发一定会越来...

【第31天】番外篇-Windows + YOLOV4 本地端训练

摘要 前言 工具 流程 前言 【第3天】资料前处理-YOLOv4与自动框选中文字曾提及,Window...

[Day_10]资料储存容器(3) - 字典(dict)

字典(dict) 今天要来跟大家介绍字典(dict), 字典储存的资料为「键(key)」与「值(va...

Unity与Photon的新手相遇旅途 | Day17-击杀数计算

今天的内容为计算击杀怪物数量。 ...