iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0
SideProject30

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

Day14 接龍發牌區功能實作(一)發牌循環

  • 分享至 

  • xImage
  •  

為了實現接龍發牌區功能,必須先思考如何讓撲克牌循環利用,這部分程式碼我是先拆一個頁面來練習實作,避免單一頁面的程式碼邏輯太過混亂。

發牌區的樣板

今日實作的目標會是一個左邊移牌區右邊發牌堆結合在一起的,
點擊發牌堆會將牌發到移牌區顯示,移牌區最多同時顯示三張牌。
發牌區樣板圖-實作的方向

實作的樣板程式碼

// DealerAreaView.vue
<GameBoard>
    <div class="text">發牌區</div>
    <div style="display: grid; grid-template-columns: 1.5fr 1fr; gap:3rem; width: fit-content;">
        <!-- 移牌區 - 左邊水平疊牌最多三張 -->
        <div style="display: grid; grid-template-columns: repeat(3, 3rem);">
            <div v-for="card in canTakeCards" :key="card.value">
                <Card :value="card.value" :isOpen="true" />
            </div>
        </div>
        <!-- 發牌堆 -->
        <div class="card-box">
            <div class="card" style="visibility: hidden;">
                <div style="visibility: visible; width: 100%;height: 100%; ">
                    <Transition name="slide-left">
                        <div v-if="deckState == 'empty'">無牌可用</div>
                        <div v-else-if="deckState == 'full'" class="card" @click="clickCard">重新循環</div>
                        <div v-else-if="deckState == 'normal'" @click="clickCard" class="card-back"></div>
                    </Transition>
                </div>
            </div>
        </div>
    </div>
</GameBoard>

可以注意到發牌堆使用<Transition>包裹,裡面的元件使用v-ifv-else-if去判斷三種情況顯示元件,
這邊使用到的deckState是一個計算結果。

在說明deckState之前,先講一下此範例使用到的變數indexdeck

const index = ref(0);
const deck = ref(geneateDeck(14, true));

deck就是包含著發牌堆+移牌區的卡牌陣列,日後會改用屬性props傳進元件,
但因為今天在練習實作就先自己產生。

index則是對應發到第幾張牌的指標(Pointer),採用指標的原因是可以不用將把發牌堆移牌區分成兩個陣列儲存,當指標index為0時代表移牌區沒有牌,index為1時則代表已發到第1張牌,以此類推。

回到變數deckState就是用指標位置和牌堆數量計算出來發牌堆會有3種顯示狀態:

  1. 發牌堆移牌區都沒牌時,顯示無牌可用 (empty)
  2. 發牌堆已發完牌但移牌區仍有牌,則顯示重新循環 (full)
  3. 發牌堆還有牌可以發,顯示撲克卡背 (normal)
const deckState = computed(() => {
    if (index.value === 0 && deck.value.length == 0) return 'empty';
    if (index.value === deck.value.length) return 'full';
    return 'normal';
});

移牌區顯示的撲克陣列canTakeCards也是用indexdeck計算出來的最多回傳3個元素的陣列,
因為Array.slice只會回傳複製陣列,所以不會影響deck陣列本身。

/** 玩家可拿取的牌 */
const canTakeCards = computed(() => {
    let startIndex = index.value < 3 ? 0 : index.value - 3;
    return deck.value.slice(startIndex, index.value);
});

點擊發牌堆觸發的函數也只是改變指標index往前移動,間接影響上面使用computed計算出來的結果。

function clickCard() {
    index.value++;
    if (index.value > deck.value.length) {
        index.value = 0;
    }
}

小結

發牌區內部的部分使用陣列指標的方式去判斷,可以減少對陣列本身的pushpop等異動原堆疊資料的行為。

目前移牌區沒有使用到<draggable>包裹,實際上移牌區的牌應該要可被拖曳至中心的集牌區進行移動,但中心的集牌區的牌不能被拖回發牌區的移牌區,這部分明天才會做但還是先提一下。

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

Yes


上一篇
Day 13 牌尾自動翻牌、限制疊牌順序
下一篇
Day15 接龍發牌區功能實作(二)拖曳功能及CSS發牌動畫
系列文
毫無自信的開發Web遊戲接龍-成為創造龍的英雄之路!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言