研究Transition的文件後發現跟我想像的動畫變換不同,官方用法<Transition></Transition>
包裹內的新舊元件其中一個在動畫過程會先被移除掉或新增,但我先前設計好的CSS會是兩個元素都存在只是一個會被轉到CSS效果轉到背後,因此我的水平翻轉動畫需要兩個元素都存在HTML上。
為了在時間內完成,我打消原本水平翻轉的作法,我改採Transition
結合v-if
的方式去顯示卡牌正反兩面,
發現用漸進式出現消失也是不錯的效果,以下是樣板的改變:
// Card.vue
<template>
<div class="card " @click="emit('poker-flip', value)">
<Transition name="card-flip">
<div v-if="isOpen" class="card-front" :class="numberClass">{{ content }}</div>
<div v-else class="card-back"></div>
</Transition>
</div>
</template>
參考Vue官方的範例,
在style添加以下後綴是-enter-active
/leave-active
/-enter-from
/-leave-to
的class,是為了讓Transition知道動畫要如何改變。
// Card.vue
<style scoped>
.card-flip-enter-active,
.card-flip-leave-active {
transition: all 0.5s ease-out;
}
.card-flip-enter-from,
.card-flip-leave-to {
opacity: 0;
}
{/* 略 */}
utils/poker-helper.js
shuffle
,洗牌採用的演算法參考看別人文章實作 Fisher-Yates 演算法,雖然洗牌用其他方法也可以,但看參考的文章說這個時間複雜度最低。function shuffle(deck) {
let length = deck.length;
for (let i = 0; i < length; i++) {
let rand_to_swap = Math.floor(Math.random()*(length-i));
let tmp = deck[length-1-i];
deck[length-1-i] = deck[rand_to_swap];
deck[rand_to_swap] = tmp;
}
return deck;
}
geneateShuffleDeck
,這邊的isDone
是為了儲存比對成功,isDone
為true時卡片會變成顯示不可點擊的小綠卡。function geneateShuffleDeck() {
let deck = [];
for (let i = 0; i < 52; i++) {
deck.push({
value: i,
isOpen: false,
isDone: false
});
}
return shuffle(deck);
}
簡單就是52張牌洗亂擺在桌上,翻出兩張牌打開有相同的就等於連上,
因為我記憶力沒多好,所以遊戲規則調整成一次最多可以翻六張,超過張數的話牌就會蓋起來!
雖然樣式很醜,但也做了記錄了分數
、當前經過時間
和遊戲重置
的功能。
因為有越來越多變數用ref存著,在<script setup>
中每次對ref
的變數取值/設值都要加 .value 越來越冗長,後面想到可以用reactive
宣告一個遊戲狀態存多個屬性欄位,尤其是陣列的部分
// GameBoard.vue
const boardCards = ref(geneateShuffleDeck());
const gameScore = ref(0);
const game = reactive({
timer: 0, // 當前經過時間
timerInterval: null, // 儲存執行 setInterval()回傳的intevealId,重置會需要用到
deckCards: [], // 將目前打開的牌放到裡面,方便之後比對是否有數字相同的卡
})
另外遊戲判定成功,我是使用Watcher去看有沒有分數(gameScore)達到182的,才去跳出結束訊息,
但看網路上watch好像都是用在接收API結果觸發時居多。
// GameBoard.vue
watch(gameScore, (newScore, oldScore) => {
if (newScore >= 182) {
alert(`遊戲結束,花費時間: ${timerFormat.value} 總分數: ${newScore}!!!`);
resetGame();
}
});
實作完後覺得最複雜的可能就是點卡牌後觸發的翻轉功能,判定成功與否真的蠻麻煩,
傳值/取值也是如果可以有個簡單的中央儲存控管就好了。
最後成功實作出來也玩了幾回,至少真的像在玩一個遊戲的感覺,雖然最多可以點開六張是比較寬鬆。
參考
明日預計會做紙牌接龍會用到的牌堆
設計,感謝觀看!