溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

HTML+CSS+JavaScript怎么創(chuàng)建井字游戲

發(fā)布時(shí)間:2021-11-22 17:08:45 來源:億速云 閱讀:96 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“HTML+CSS+JavaScript怎么創(chuàng)建井字游戲”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

實(shí)現(xiàn) HTML

首先在 head 部分,我將包含我們稍后創(chuàng)建的 css 和 javascript 文件。我還添加了名為 Itim 的 Google 字體。

<link rel="stylesheet" href="style.css" rel="external nofollow" >
<link rel="preconnect" href="https://fonts.gstatic.com" rel="external nofollow" >
<link href="https://fonts.googleapis.com/css2?family=Itim&display=swap" rel="external nofollow"  rel="stylesheet">
<script src="index.js"></script>

HTML 的主體將相當(dāng)簡單。為了包裝所有東西,我將使用一個(gè)主標(biāo)簽,并對其應(yīng)用一個(gè)類background。在main包裝器內(nèi)部,我們將有五個(gè)部分。

第一部分將只包含我們的標(biāo)題h2。

第二部分將顯示當(dāng)前輪到誰。在顯示中,我們有一個(gè)包含X或O取決于當(dāng)前用戶的跨度。我們將類應(yīng)用于此跨度以對文本進(jìn)行著色。

第三部分是拿著游戲板的部分。它有一個(gè)container類,因此我們可以正確放置瓷磚。在本節(jié)中,我們有 9 個(gè) div,它們將充當(dāng)板內(nèi)的瓷磚。

第四部分將負(fù)責(zé)公布最終比賽結(jié)果。默認(rèn)情況下它是空的,我們將從 javascript 修改它的內(nèi)容。

最后一部分將保存我們的控件,其中包含一個(gè)重新開始按鈕。

<main class="background">
        <section class="title">
            <h2>井字游戲</h2>
        </section>
        <section class="display">
            玩家 <span class="display-player playerX">X</span> 的回合
        </section>
        <section class="container">
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
        </section>
        <section class="display announcer hide"></section>
        <section class="controls">
            <button id="reset">重新開始</button>
        </section>
    </main>

添加 CSS

我不會詳細(xì)介紹 CSS 的每一行,但你可以查看源碼中的完整代碼。

首先,我將創(chuàng)建style.css文件并刪除任何瀏覽器定義的邊距和填充,并為整個(gè)文檔設(shè)置我在 HTML 中包含的 Google 字體。

* {
    padding: 0;
    margin: 0;
    font-family: 'Itim', cursive;
}

我們必須添加的下一件重要事情是我們的板的樣式。我們將使用 CSS 網(wǎng)格來創(chuàng)建板。我們可以通過為列和行提供 3 倍 33% 的空間將容器一分為二。我們將通過設(shè)置最大寬度和將容器居中margin: 0 auto;

.container {
    margin: 0 auto;
    display: grid;
    grid-template-columns: 33% 33% 33%;
    grid-template-rows: 33% 33% 33%;
    max-width: 300px;
}

接下來,我們將添加板內(nèi)瓷磚的樣式。我們將應(yīng)用一個(gè)小的白色邊框,并將最小寬度和高度設(shè)置為 100 像素。我們將利用Flexbox的和設(shè)置的中心內(nèi)容justify-content align-items到center。我們會給它一個(gè)大字體大小并應(yīng)用,cursor: pointer這樣用戶就會知道這個(gè)字段是可點(diǎn)擊的。

.tile {
    border: 1px solid white;
    min-width: 100px;
    min-height: 100px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 50px;
    cursor: pointer;
}

我使用了兩種不同的顏色來更好地區(qū)分這兩個(gè)玩家。為此,我創(chuàng)建兩個(gè)實(shí)用程序類。玩家 X 的顏色為綠色,而玩家 O 的顏色為藍(lán)色。

.playerX {
    color: #09C372;
}

.playerO {
    color: #498AFB;
}

實(shí)現(xiàn) Javascript 部分

由于我們將 javascript 文件包含在<head>. 這是必需的,因?yàn)槲覀兊哪_本將在瀏覽器解析 HTML 正文之前加載。如果你不想將所有內(nèi)容都包含在此函數(shù)中,請隨意添加defer到腳本標(biāo)記中或?qū)⒛_本標(biāo)記移動到body.

window.addEventListener('DOMContentLoaded', () => {

});

首先,我們將保存對 DOM 節(jié)點(diǎn)的引用。我們將使用document.querySelectorAll(). 我們想要一個(gè)數(shù)組,但此函數(shù)返回一個(gè) NodeList,因此我們必須使用Array.from(). 我們還將獲取對播放器顯示、重置按鈕和播音員的引用。

const tiles = Array.from(document.querySelectorAll('.tile'));
const playerDisplay = document.querySelector('.display-player');
const resetButton = document.querySelector('#reset');
const announcer = document.querySelector('.announcer');

接下來,我們將添加控制游戲所需的全局變量。我們將用一個(gè)包含九個(gè)空字符串的數(shù)組來初始化一個(gè)板。這將保存板上每個(gè)圖塊的 X abd O 值。我們將有一個(gè)currentPlayer持有當(dāng)前回合活躍的玩家的標(biāo)志。該isGameActive變量將一直為真,直到有人獲勝或游戲以平局結(jié)束。在這些情況下,我們會將其設(shè)置為 false,以便剩余的圖塊在重置之前處于非活動狀態(tài)。我們有三個(gè)常數(shù)代表游戲結(jié)束狀態(tài)。我們使用這些常量來避免拼寫錯(cuò)誤。

let board = ['', '', '', '', '', '', '', '', ''];
let currentPlayer = 'X';
let isGameActive = true;

const PLAYERX_WON = 'PLAYERX_WON';
const PLAYERO_WON = 'PLAYERO_WON';
const TIE = 'TIE';

在下一步中,我們將在棋盤上存儲所有獲勝的位置。在每個(gè)子數(shù)組中,我們將存儲可以贏得比賽的三個(gè)位置的索引。所以這[0, 1, 2]將代表第一條水平線被玩家占據(jù)的情況。我們將使用這個(gè)數(shù)組來決定我們是否有贏家。

/*
   Indexes within the board
   [0] [1] [2]
   [3] [4] [5]
   [6] [7] [8]
*/

const winningConditions = [
   [0, 1, 2],
   [3, 4, 5],
   [6, 7, 8],
   [0, 3, 6],
   [1, 4, 7],
   [2, 5, 8],
   [0, 4, 8],
   [2, 4, 6]
];

現(xiàn)在我們將編寫一些實(shí)用函數(shù)。在isValidAction函數(shù)中,我們將決定用戶是否想要執(zhí)行有效的操作。如果 tile 的內(nèi)部文本是XorO我們返回 false 作為操作無效,否則 tile 為空所以操作有效。

const isValidAction = (tile) => {
    if (tile.innerText === 'X' || tile.innerText === 'O'){
        return false;
    }

    return true;
};

下一個(gè)效用函數(shù)將非常簡單。在這個(gè)函數(shù)中,我們將接收一個(gè)索引作為參數(shù),并將棋盤數(shù)組中的相應(yīng)元素設(shè)置為我們當(dāng)前玩家的符號。

const updateBoard =  (index) => {
   board[index] = currentPlayer;
}

我們將編寫一個(gè)小函數(shù)來處理玩家的變化。在這個(gè)函數(shù)中,我們將首先從playerDisplay. 字符串模板文字player${currentPlayer}將成為playerX或playerO取決于當(dāng)前玩家。接下來,我們將使用三元表達(dá)式來更改當(dāng)前玩家的值。如果是X,它將是O否則它將是X?,F(xiàn)在,我們改變了我們用戶的價(jià)值,我們需要更新innerText的playerDisplay,并應(yīng)用新的播放器類的。

const changePlayer = () => {
    playerDisplay.classList.remove(`player${currentPlayer}`);
    currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
    playerDisplay.innerText = currentPlayer;
    playerDisplay.classList.add(`player${currentPlayer}`);
}

現(xiàn)在我們將編寫宣布最終游戲結(jié)果的 announer 函數(shù)。它將接收結(jié)束游戲類型并innerText根據(jù)結(jié)果更新播音員 DOM 節(jié)點(diǎn)的 。在最后一行中,我們必須刪除隱藏類,因?yàn)椴ヒ魡T默認(rèn)是隱藏的,直到游戲結(jié)束。

const announce = (type) => {
    switch(type){
       case PLAYERO_WON:
            announcer.innerHTML = 'Player <span class="playerO">O</span> Won';
            break;
       case PLAYERX_WON:
            announcer.innerHTML = 'Player <span class="playerX">X</span> Won';
            break;
       case TIE:
            announcer.innerText = 'Tie';
        }
    announcer.classList.remove('hide');
};

接下來我們將編寫這個(gè)項(xiàng)目中最有趣的部分之一——結(jié)果評估。首先,我們將創(chuàng)建一個(gè) roundWon 變量并將其初始化為 false。然后我們將遍歷winConditions數(shù)組并檢查棋盤上的每個(gè)獲勝條件。例如,在第二次迭代中,我們將檢查這些值:board3、board4、board5。

我們還將進(jìn)行一些優(yōu)化,如果任何字段為空,我們將調(diào)用continue并跳到下一次迭代,因?yàn)槿绻@勝條件中有空圖塊,您將無法獲勝。如果所有字段都相等,那么我們就有一個(gè)贏家,因此我們將 roundWon 設(shè)置為 true 并中斷 for 循環(huán),因?yàn)槿魏芜M(jìn)一步的迭代都會浪費(fèi)計(jì)算。

在循環(huán)之后,我們將檢查roundWon變量的值,如果為真,我們將宣布獲勝者并將游戲設(shè)置為非活動狀態(tài)。如果我們沒有獲勝者,我們將檢查棋盤上是否有空牌,如果我們沒有獲勝者并且沒有空牌,我們將宣布平局。

function handleResultValidation() {
  let roundWon = false;
  for (let i = 0; i <= 7; i++) {
    const winCondition = winningConditions[i];
    const a = board[winCondition[0]];
    const b = board[winCondition[1]];
    const c = board[winCondition[2]];
    if (a === "" || b === "" || c === "") {
      continue;
    }
    if (a === b && b === c) {
      roundWon = true;
      break;
    }
  }

  if (roundWon) {
    announce(currentPlayer === "X" ? PLAYERX_WON : PLAYERO_WON);
    isGameActive = false;
    return;
  }

  if (!board.includes("")) announce(TIE);
}

接下來我們將處理用戶的操作。此函數(shù)將接收一個(gè) tile 和一個(gè)索引作為參數(shù)。當(dāng)用戶單擊一個(gè)圖塊時(shí),將調(diào)用此函數(shù)。首先我們需要檢查它是否是一個(gè)有效的動作,我們還將檢查游戲當(dāng)前是否處于活動狀態(tài)。如果兩者都為真,我們innerText用當(dāng)前玩家的符號更新瓷磚的 ,添加相應(yīng)的類并更新板陣列?,F(xiàn)在一切都更新了,我們必須檢查游戲是否已經(jīng)結(jié)束,所以我們調(diào)用handleResultValidation(). 最后,我們必須調(diào)用該changePlayer方法將輪次傳遞給另一個(gè)玩家。

const userAction = (tile, index) => {
  if (isValidAction(tile) && isGameActive) {
    tile.innerText = currentPlayer;
    tile.classList.add(`player${currentPlayer}`);
    updateBoard(index);
    handleResultValidation();
    changePlayer();
  }
};

為了讓游戲正常運(yùn)行,我們必須向磁貼添加事件偵聽器。我們可以通過循環(huán)遍歷圖塊數(shù)組并為每個(gè)圖塊添加一個(gè)事件偵聽器來做到這一點(diǎn)。(為了獲得更好的性能,我們只能向容器添加一個(gè)事件偵聽器并使用事件冒泡來捕獲父級上的磁貼點(diǎn)擊,但我認(rèn)為對于初學(xué)者來說這更容易理解。)

tiles.forEach( (tile, index) => {
    tile.addEventListener('click', () => userAction(tile, index));
});

我們只錯(cuò)過了一項(xiàng)功能:重置游戲。為此,我們將編寫一個(gè)resetBoard函數(shù)。在此函數(shù)中,我們將棋盤設(shè)置X為由九個(gè)空字符串組成,將游戲設(shè)置為活動狀態(tài),移除播音員并將玩家更改回(根據(jù)定義X始終開始)。

我們必須做的最后一件事是遍歷圖塊并將innerText 設(shè)置回空字符串,并從圖塊中刪除任何特定于玩家的類。

const resetBoard = () => {
    board = ['', '', '', '', '', '', '', '', ''];
    isGameActive = true;
    announcer.classList.add('hide');

    if (currentPlayer === 'O') {
        changePlayer();
    }

    tiles.forEach(tile => {
        tile.innerText = '';
        tile.classList.remove('playerX');
        tile.classList.remove('playerO');
    });
}

現(xiàn)在我們只需要將此函數(shù)注冊為重置按鈕的點(diǎn)擊事件處理程序。

resetButton.addEventListener('click', resetBoard);

“HTML+CSS+JavaScript怎么創(chuàng)建井字游戲”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI