本系列文已改編成書「Arduino 自造趣:結合 JavaScript x Vue x Phaser 輕鬆打造個人遊戲機」,本書改用 Vue3 與 TypeScript 全面重構且加上更詳細的說明,
在此感謝 iT 邦幫忙、博碩文化與編輯小 p 的協助,歡迎大家前往購書,鱈魚在此感謝大家 (。・∀・)。
若想 DIY 卻不知道零件去哪裡買的讀者,可以參考此連結 。( •̀ ω •́ )✧
這個章節開始我們要重現 Chrome 瀏覽器離線時出現的小遊戲「Dinosaur Game」,首先來好好規劃一下遊戲的藍圖。
視窗主體
負責提供腳位資料、設定欄位。
遊戲場景
包含所有遊戲角色等等。
場景包含:
分數
隨時間自動增加,每 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,
},
// ...
};
視窗基本功能建立完成!
準備的設備內容同「D11 數位功能」:
三用電表 * 1
麵包板 * 1
按鈕 * 2
標準作業流程。
利用三用電表確認按鈕是否能夠正常通導。
以下為參考接線方式,可以不用完全相同,只要效果相同即可。
使用 Uno 板子上的 5V 為 +、GND 為 -。
為了讓電路簡單,這裡我們一律都使用「上拉輸入」。
下一章節要來實際建立遊戲場景!
以上程式碼已同步至 GitLab,大家可以前往下載: