65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 jQuery 的两人井字游戏 2D 游戏

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (17投票s)

2014年9月2日

CPOL

5分钟阅读

viewsIcon

44501

downloadIcon

1104

使用 jQuery 的两人井字游戏 2D 游戏。

Sample Image - maximum width is 600 pixels

引言

井字棋是一款非常简单的纸笔游戏。在这个例子中,我展示了如何使用 jQuery 在 HTML 上构建一个 2D 井字棋游戏。

背景

井字棋是关于 O 和 X 的。游戏规则非常简单。在一个 3x3 的网格上,玩家必须水平/垂直/对角线连接 3 个连续的 O 或 X。我设计了一个非常简单的界面,并使用 jQuery 来实现游戏玩法。在下一节中,我将解释代码。

Using the Code

在这里,我将解释代码块。

<!DOCTYPE html>
<html>
<head>
    <title>TicTacToe</title>
    <link rel="stylesheet" type="text/css" href="css/reset.css">
    <link rel="stylesheet" type="text/css" href="css/main.css">
</head>
<body>

<div id="game-wrap">
    
    <div class="row">
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
    </div>

    <div class="row">
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
    </div>

    <div class="row">
        <div class="col"></div>
        <div class="col"></div>
        <div class="col"></div>
    </div>

</div>

<div id="panel">
    <input type="text" id="player-1-inp" placeholder="Enter player 1">
    <input type="text" id="player-2-inp" placeholder="Enter player 2">
    <button id="playButton">Play!</button>
    <h1 id="board"></h1>
</div>

<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>

在这里,我使用简单的 HTML div 创建了一个 3x3 的网格。我使用了三个行 div,并在每个行 div 中使用了三个列 div。我将行和列的名称保持相同,因为我计划稍后将此结构用作 2D 网格。在网格下方,我放置了一个面板 div,玩家可以在其中设置他们的名字、开始游戏并查看游戏状态消息。

body{
background: #323232;
}

#game-wrap{
    width: 450px;
    height: 455px;
    margin: 0 auto;
    background: gray;
    margin-top: 50px;
    border-left: 5px solid gray;
    border-top-right-radius: 20px;
    border-top-left-radius: 20px;
}

.row{
    width: 100%;
    height: 150px;
}
.col{
    width: 32%;
    height: 145.5px;
    border: 3px solid white;
    float: left;
    text-align: center;
    font-size: 150px;
    font-family: helvetica;
    color: white;
    cursor: pointer;
}
.matched{
    color: maroon;
}
.player-1-color{
    color: maroon;
}
.col:nth-child(1){
    border-left: none;
}
.col:nth-child(3){
    border-right: none;
}

.row:nth-child(1) .col{
    border-top: none;
    margin-top: 3px;
}
.row:nth-child(3) .col{
    border-bottom: none;
    margin-bottom: 3px;
}
#panel{
    width: 435px;
    padding: 10px;
    margin: 0 auto;
    background: brown;
    border-bottom-right-radius: 20px;
    border-bottom-left-radius: 20px;
}
#board{
    font-size: 30px;
    font-family: helvetica;
    color: whitesmoke;
    margin-top: 10px;
}

这是游戏的 CSS 设计。代码不言自明。我假设使用 jQuery 的人都了解 CSS。

jQuery 部分

在这一部分,我将分别编写多个代码块,并单独解释它们。但它们都来自同一个 .js 文件。起初,我们需要创建一些函数并进行一些初始化,然后才能进入主要的游戏玩法。

var player1Name="" , player2Name="", turn = "";
var grid =  [[0,0,0],[0,0,0],[0,0,0]];
var hasWinner = 0, moveCount=0;

function boardMsg(x){
    return $("#board").text(x);
}

在这里,我们为玩家姓名、跟踪游戏回合、一个 3x3 数组来映射玩家的移动、用于查找获胜者的标志变量、用于计算总移动次数的标志变量(最大 moveCount 将是 9)以及最后用于在面板上写入的函数创建了一些新变量。

function setTurn(){
    var r = Math.floor((Math.random() * 2) + 1);
    hasWinner=0;
    if(r==1){
        turn = player1Name;
        boardMsg(player1Name+"'s turn now!");
    }
    else{
        turn = player2Name;
        boardMsg(player2Name+"'s turn now!");
    }
}

然后,我们编写一个函数来随机设置玩家的回合。因为我们不想每次都让某个玩家先走。使用随机数,我们设置了回合,并将获胜者标志设置为 0 ,因为游戏刚刚开始。

function init(){
        turn = "";
        grid =  [[0,0,0],[0,0,0],[0,0,0]];
        boardMsg("");
        $(".col").map(function() {
            $(this).text("");
        }).get();
        hasWinner = 0;
        moveCount=0;
}

现在,我们需要编写一个初始化函数,如下所示,因为如果游戏已经玩了一次或多次,每次玩家重玩时,都需要清除旧值,例如回合、网格数组、面板消息、网格的 O/X 以及标志。

$("#playButton").click(function (){

    if(hasWinner==1){
        init();
    }

    player1Name = $("#player-1-inp").val();
    player2Name = $("#player-2-inp").val();

    if(player1Name=="" || player2Name==""){
        alert("Please set player all the names.");
        return;
    }

    setTurn();
});

这个函数是播放按钮的点击事件,用于从输入标签获取玩家的值。如果之前有获胜者,则表示此点击是用于“再玩一次”按钮。因此,我们重新初始化必要的值。然后,我们将检查玩家是否设置了他们的名字。最后,我们设置回合。

$(".col").click(function (){

    if(player1Name=="" || player2Name==""){
        alert("Please set player all the names.");
        return;
    }

    var row = $(this).parent().index();
    var col = $(this).index();

    if(grid[row][col]!==0){
        alert("This position is taken. Please try other position.");
        return;
    }
    if(hasWinner==1){
        alert("Please click play again");
        return;
    }

    if(turn==player1Name){
        moveCount++;
        $(this).text("O");
        grid[row][col] = 1;
        var ifWon = winnerCheck(1,player1Name);
        if(!ifWon){
            if(moveCount>=9){
                boardMsg("Match Drawn!");
                moveCount=0;
                $("#playButton").text("Play again");
                hasWinner=1;
                return;
            }else{
                turn = player2Name;
                boardMsg(player2Name+"'s turn now!");
            }
            return;    
        }
        else{
            return;
        }        
    }
    else if(turn==player2Name){
        moveCount++;
        $(this).text("X");
        grid[row][col] = 2;
        var ifWon = winnerCheck(2,player2Name);
        if(!ifWon){
            if(moveCount>=9){
                boardMsg("Match Drawn!");
                moveCount=0;
                $("#playButton").text("Play again");
                hasWinner=1;
                return;
            }else{
                turn = player1Name;
                boardMsg(player1Name+"'s turn now!");
            }
            return;    
        }
        else{
            return;
        }        
    }
});

这是网格单元的点击事件。在这里,我们在每个 .col 类上使用 jQuery 类选择器点击函数。如果玩家点击任何 .col div,我们将有条件地检查当前是谁在玩。第一个条件是针对 player1。然后,我们使用 jQuery 的 index()parent() 获取网格单元的行-列位置。如果该位置已被占用,我们将继续进行。或者,我们将检查回合以确定哪个玩家正在玩。检查完回合后,我们将增加移动计数,因为这是一次成功的移动。然后,我们将 1 放入网格的 [row][col] 位置,而玩家刚刚点击了实际网格的 [row][col] 位置。我们将 1 和玩家姓名传递给即将到来的获胜者检查函数。如果玩家没有获胜,我们将检查是否已用尽移动次数且游戏是否已平局。如果是平局,我们将向面板发送消息并更改标志值。在这里,尽管游戏是平局,但我将 1 设置为 hasWinner 标志,因为在 setTurn 函数中,如果需要创建新游戏,我们需要传递 init() 的条件。然后,如果不是平局,我们将回合交给第二个玩家,并向面板发送消息。并且在平局的条件下,如果玩家获胜,则什么都不会发生,只会停止函数。因此,请仔细检查我为两个玩家写了两个 if 条件。在这些条件内部,除了某些值之外,一切都相同,例如当条件是为玩家 1 时,我们将 1 放入网格,将 1 和玩家 1 的姓名传递给获胜者检查函数,并将回合交给玩家 2。对于玩家 2,所有这些事情都将相反。

function winnerCheck(n,playerName){
    if(

        (grid[0][0]==n && grid[0][1]==n && grid[0][2]==n) ||
        (grid[1][0]==n && grid[1][1]==n && grid[1][2]==n) ||
        (grid[2][0]==n && grid[2][1]==n && grid[2][2]==n) ||

        (grid[0][0]==n && grid[1][0]==n && grid[2][0]==n) ||
        (grid[0][1]==n && grid[1][1]==n && grid[2][1]==n) ||
        (grid[0][2]==n && grid[1][2]==n && grid[2][2]==n) ||

        (grid[0][0]==n && grid[1][1]==n && grid[2][2]==n)||
        (grid[0][2]==n && grid[1][1]==n && grid[2][0]==n)


        ){
        boardMsg(playerName+" won the game!");
        hasWinner = 1;
        moveCount=0;
        $("#playButton").text("Play again");
        return true;
    }
    return false;
}

最后一个函数是检查获胜者。在这个函数中,我们传递了一个数字和玩家姓名作为参数。然后我们检查网格上水平/垂直/对角线是否有三个连续的 n。如果其中任何一个条件匹配,则该玩家赢得了比赛。因此,当我们将 1 和玩家 1 的姓名传递给函数时,它将检查玩家 1 是否赢得了比赛,而当我们传递 2 和玩家 2 的姓名时,它将检查玩家 2 是否赢得了比赛。然后我们向面板发送消息并更新标志。因为 UI 现在应该停止游戏。然后,我们将按钮的文本更改为“再玩一次”。最后,我们返回 true。如果所有 8 个条件都为 false,我们则返回 false。根据返回值,网格单元的点击函数将按我之前解释的那样工作。

jsfiddle 上玩这个游戏。

© . All rights reserved.