iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Modern Web

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

D27 - 「來互相傷害啊!」:運籌帷幄

  • 分享至 

  • xImage
  •  

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

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

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


來規劃遊戲藍圖吧。

視窗規劃

基本上和小恐龍單元一樣。

  • 視窗主體

    負責提供腳位資料、設定欄位。

  • 遊戲場景

    包含所有遊戲角色等等。

不過設定欄位要怎麼設計呢?要先了解搖桿的訊號組成才行,就讓我們留到下一章再來研究。

遊戲規劃

依照場景進行規劃。

歡迎場景

D26 - 規劃遊戲場景:歡迎場景.png

  • 主角

    使用搖桿可以控制人物移動,可用於讓玩家確認控制器是否正常。

  • 提示文字

    告知玩家按下搖桿按鈕即可開始。

主場景

進行遊戲的主要場景,中央河流分隔,人物不可跨越。

D26 - 規劃遊戲場景:主場景.png

  • 主角
    • 透過搖桿控制人物移動,按下按鈕發射武器
    • 按下按鈕發射武器,並播放發射動畫
    • 血量顯示在左上角,預設 5 點
    • 被敵人武器擊中時,播放被擊中動畫並減少生命值
    • 生命值歸零時,觸發死亡事件
  • 主角武器
    • 會與敵人發生碰撞
    • 向下飛行、隨機旋轉
    • 最多只能存在 1 個武器,不能連續發射
  • 敵人
    • 上下隨機移動,左右則追著主角移動
    • 隨機發射武器並播放發射動畫
    • 血量顯示在左上角,預設 10 點
    • 被主角武器擊中時,播放被擊中動畫並減少生命值
    • 生命值歸零時,觸發死亡事件
  • 敵人武器
    • 會與主角發生碰撞
    • 向上飛行、隨機旋轉
    • 最多只能存在 5 個武器,不能連續發射

結束場景

表示遊戲結束。

D26 - 規劃遊戲場景:結束場景.png

  • 主角

    依照勝敗顯示不同人物圖片。

  • 提示文字

    依照勝敗顯示不同文字並提示按下搖桿按鈕即可重新開始。

建立「視窗主體」

建立 window-app-cat-vs-dog 資料夾管理相關組件並建立 window-app-cat-vs-dog.vue 視窗組件。

概念與「跑跑小恐龍」相同。

src\components\window-app-cat-vs-dog\window-app-cat-vs-dog.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';

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

    /** 設定欄位是否完成 */
    isSettingOk() {
      return false;
    },
  },
  watch: {},
  created() {},
  mounted() {},
  methods: {
    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-cat-vs-dog\window-app-cat-vs-dog.vue <template lang="pug">

base-window.window-app-cat-vs-dog(
  :pos='pos',
  header-icon='r_videogame_asset',
  body-class='c-col',
  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
              | 設定控制器

src\components\window-app-cat-vs-dog\window-app-cat-vs-dog.vue <style scoped lang="sass">

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

.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
  align-items: center
  .form-section
    padding: 20px
    width: 80%
    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
          | 新增「跑跑小恐龍」
			q-item(
        @click='addWindow("window-app-cat-vs-dog")',
        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';
import WindowAppCarVsDog from '@/components/window-app-cat-vs-dog/window-app-cat-vs-dog.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,
		'window-app-cat-vs-dog': WindowAppCarVsDog,
  },
  // ...
};

D27 - 建立貓狗大戰視窗.gif

成功建立戰場!

總結

  • 完成遊戲規劃
  • 建立「貓狗大戰」視窗

以上程式碼已同步至 GitLab,大家可以前往下載:

GitLab - D27


上一篇
D26 - 「來互相傷害啊!」:站在 Phaser 的肩膀上
下一篇
D28 - 「來互相傷害啊!」:粗乃玩搖桿!
系列文
你渴望連結嗎?將 Web 與硬體連上線吧!33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言