本系列文已改編成書「Arduino 自造趣:結合 JavaScript x Vue x Phaser 輕鬆打造個人遊戲機」,本書改用 Vue3 與 TypeScript 全面重構且加上更詳細的說明,
在此感謝 iT 邦幫忙、博碩文化與編輯小 p 的協助,歡迎大家前往購書,鱈魚在此感謝大家 (。・∀・)。
若想 DIY 卻不知道零件去哪裡買的讀者,可以參考此連結 。( •̀ ω •́ )✧
來建立我們的主角小恐龍吧。
建立小恐龍組件 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')
目前應該會長這樣。
點一下畫面,看看遊戲開始後小恐龍會不會開始跑步。
小恐龍成功開跑!
再來就是讓小恐龍跳躍和蹲下了。
跳躍動畫使用 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')
點擊看看小恐龍會不會跳躍。
成功起跳!
蹲下動作就簡單很多,單純就是狀態切換而已。
實作過程如下:
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')
嘗試看看是否左鍵跳躍,右鍵蹲下。
成功!恭喜復活恐龍惹!(´,,•ω•,,)
最後是最容易忘記也最重要的一步,就是銷毀計時器。利用 beforeDestroy()
呼叫 over()
達成效果。
src\components\window-app-google-dino\dino.vue <script>
export default {
name: 'Dino',
// ...
beforeDestroy() {
this.over();
},
// ...
};
以上程式碼已同步至 GitLab,大家可以前往下載: