iT邦幫忙

2023 iThome 鐵人賽

DAY 20
0
SideProject30

毫無自信的開發Web遊戲接龍-成為創造龍的英雄之路!系列 第 20

Day20 實作結算牌堆元件(四) 實作移入7牌堆的拖曳&遊戲重置

  • 分享至 

  • xImage
  •  

前言

今天會先實作結算牌堆的牌要可以拖曳至7牌堆
另外因為每次要重新開始都要切換頁面或按F5重新整理也會實作一個重置遊戲的按鈕

拖曳結算牌堆的牌 至 7牌堆

原本以為會花點時間想怎麼做,但實際上思考、實作都沒花多少時間就完成。

因為結算牌堆拖曳的牌一次只會拖曳一張,且拖曳到7牌堆的過程判斷基本上抄之前7牌堆自己的拖曳判斷方法就差不多完成,只多了一個先判斷拖曳的目標牌堆是否為七牌堆,甚至不用像其他牌堆拖曳:move還要額外去寫『拖曳成功後要觸發修改陣列』的函數changeOption.vlaue

以下是對應結算牌堆<FinishedArea >內元件的屬性:move實作程式碼:

// DragDemo.vue
/** 結算牌堆移動 */
function finishedCardMove(evt) {
    const to = getDomName(evt.to);
    const { futureIndex, element } = evt.draggedContext;

    let result = validNames.includes(to);
    // 只能移動至目標牌堆的最後一張牌
    result = result && futureIndex == cardStacks[to].length;

    // 檢查疊牌順序、花色是否正確
    result = result && checkNextOk(cardStacks[to], element);

    return result;
}

調整樣板<FinishedArea >的屬性:moveCard="finishedCardMove"即可套用上方的函數。

<!-- DragDemo.vue -->
<div class="text">結算牌堆</div>
<FinishedArea :fourCards="cardStacks" :moveCard="finishedCardMove" @doms="setFourCardDoms"
    :change="cardChange" />

實作重置遊戲的按鈕

因為遊戲初始化就是寫在onMounted但重設的部分不夠完整,至少並沒有考慮到結算牌堆的部分,舊版初始化程式碼如下:

onMounted(() => {
    const data = geneateShuffleDeck(52);
    const everyIndex = [0, 1, 3, 6, 10, 15, 21, 28];
    validNames.forEach((name, idx) => {
        cardStacks[name] = data.slice(everyIndex[idx], everyIndex[idx + 1]);
    });
    cardStacks.delaerStacks = data.slice(28).map(card => ({ ...card, isOpen: true }));
});

所以乾脆將初始化遊戲寫成函數resetGame(),這樣點擊重置按鈕、渲染元件onMounted時都可以呼叫同個函數。

// DragDemo.vue
onMounted(() => {
    resetGame();
});

意外發現發牌區<DealerArea>開牌到第幾張的狀態是包在元件內不利於初始化,決定先將狀態提升父元件的程式碼中DragDemo.vue,將開牌到第幾張的索引改用props方式傳入通知元件<DealerArea>要更新索引。

// DragDemo.vue
<script setup>
let dealer = reactive({ index: 0 });
</script>
<template>
    <div class="text">發牌區</div>
    <DealerArea :dealer="dealer" :deck="cardStacks.delaerStacks" :moveCard="dealerMove" />
</template>

為了讓<DealerArea>取得發牌索引的變化,在definProps新增屬性dealer對應一個reactive物件,當物件dealer參考變動時則發牌區的索引index會被設值 【變動後dealer的index】,參考下方程式碼:

// DealerArea.vue
const props = defineProps(
    {
        dealer: {
            type: Object,
            default: reactive({ index: 0 })
        },
        // ...略
    }
)
const index = ref(0);
watch(() => props.dealer, (newDealer) => {
    index.value = newDealer.index;
});

發牌區的開牌索引是const index = ref(0);宣告維持不變,讓<DealerArea>原本的index等操作程式碼不用調整。

回到遊戲重置的部分關於函數resetGame的實作,只需要比原本的onMount重設多上重設開牌索引重設結算牌堆的資料,可以注意到變數dealer直接被賦予新物件{ index : 0 }這樣才可以刺激子元件<DealerArea>watch觀測到變化進而調整元件內部的開牌索引

// DragDemo.vue
function resetGame() {
    const data = geneateShuffleDeck(52); // 洗亂的52張牌
    const everyIndex = [0, 1, 3, 6, 10, 15, 21, 28]// 7牌堆每個牌堆的起始index
    validNames.forEach((name, idx) => {
        cardStacks[name] = data.slice(everyIndex[idx], everyIndex[idx + 1]);
    });
    // 發牌區
    cardStacks.delaerStacks = data.slice(28).map(card => ({ ...card, isOpen: true }));
    // 結算牌堆區
    FOUR_SUITS.forEach(name => {
        cardStacks[name] = [];
    });
    dealer = { index: 0 };
}

小結

今天原本只要完善結算牌堆拖曳,但有些時間就補上遊戲重置的機制。

明日預計讓接龍顯示分數遊玩時間

程式碼: https://github.com/kabuto412rock/ithelp-pokergame/tree/day20
Yes


上一篇
Day 19 實作結算牌堆元件(三)整合至接龍頁面
下一篇
Day21 顯示接龍分數、遊戲時間
系列文
毫無自信的開發Web遊戲接龍-成為創造龍的英雄之路!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言