iT邦幫忙

2021 iThome 鐵人賽

DAY 22
0
Modern Web

你渴望連結嗎?將 Web 與硬體連上線吧!系列 第 22

D21 - 「不斷線的侏儸紀」:萃取 DNA

本系列文已改編成書「Arduino 自造趣:結合 JavaScript x Vue x Phaser 輕鬆打造個人遊戲機」,本書改用 Vue3 與 TypeScript 全面重構且加上更詳細的說明,

在此感謝 iT 邦幫忙、博碩文化與編輯小 p 的協助,歡迎大家前往購書,鱈魚在此感謝大家 (。・∀・)。

若想 DIY 卻不知道零件去哪裡買的讀者,可以參考此連結 。( •̀ ω •́ )✧


這個章節開始我們要重現 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


上一篇
D20 - 「吶,你想要成為什麼顏色?」:將色彩傳下去
下一篇
D22 - 「不斷線的侏儸紀」:很久很久以前的侏儸紀
系列文
你渴望連結嗎?將 Web 與硬體連上線吧!33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言