BoardGame.io 五子棋(一)

本文介绍了使用BoardGame.io结合React制作五子棋游戏的方法。先准备项目并添加依赖,接着定义游戏、客户端,改善游戏逻辑,包括着法验证、回合管理和胜利条件判断。之后制作棋盘,添加AI功能,最后用wgo.js美化棋盘,还可进一步完善游戏。

太长不看:直接点击这里查看代码

BoardGame.io 是一个专门为回合制游戏打造的游戏引擎。无需一行网络或存储相关的代码,只需要编写简单函数描述游戏动作如何影响游戏状态,即可自动帮你生成一个支持多人在线的完整游戏。它支持回合制游戏的方方面面,比如状态管理、多人在线、AI、游戏进程或回合管理、游戏大厅等诸多功能。今天我们就用它结合 React 制作一个五子棋游戏。

准备

首先,我们准备一个 React 项目,并添加 boadgame.io 依赖。

npx create-react-app gomoku
cd gomoku
npm install boardgame.io

定义游戏

接下来,我们要定义游戏。定义游戏相当于告诉 boardgame.io 游戏是怎么玩的。由于引擎会管理好当前玩家、游戏是否结束等这些状态,对于五子棋游戏来说,只剩下局面信息需要定义了。通过创建一个满足特定接口的对象,即可定义一个游戏。这些接口当中,setup 函数是起点,它负责创建游戏状态 G。而 moves 则定义了此游戏中有多少种可以执行的动作。

动作实际是一个函数,它接收当前状态 G 作为参数,并对它进行修改,使它成为新的状态。动作函数还接收另外一个参数 ctx, 它包含当前玩家、当前回合等这些信息,由 boardgame.io 管理,无法修改。除 Gctx 外,其它参数你可自由定义,它们将被视为执行该动作的额外参数。

五子棋游戏中,我们只有一个动作,就是落子。且把它命名为 putStone,它需要一个 ID 参数告诉它该在哪里下子。

创建 src/Game.js 文件,并添加以下内容:

export const Gomoku = {
   
   
    setup: () => ({
   
    stones: Array(15*15).fill(0) }),

    moves: {
   
   
        putStone: (G, ctx, id) => {
   
   
          G.stones[id] = [1,-1][ctx.currentPlayer];
        },
    },
};

定义客户端

客户端相当于一个可以玩游戏,只不过只能通过 API 玩。将 src/App.js 内容替换为以下内容:

import {
   
    Client } from 'boardgame.io/react';
import {
   
    Gomoku } from './Game';

const App = Client({
   
    game: Gomoku});

export default App;

若此时运行 npm start ,会看到一个 UI,这是 boardgame.io 渲染的 Debug 面板。当前状态下,使用这个 UI 下虽然也可以进行游戏,但玩起来相当费劲,就不介绍了。

Debug 面板在生产环境构建时 (NODE_ENV='production')会被自动去除,也可以在 Client 的配置中添加 debug: false 关闭。

改善游戏逻辑

着法验证

目前为止,若玩家对已经落子的位置调用 putStone , 则那个位置的棋子会被覆盖。这挺扯的,需要防止。

要让 boardgame.io 就能知道此着法是无效的,需返回一个从 boardgame.io 中引入的特别常量:

import {
   
    INVALID_MOVE } from 'boardgame.io/core';

现在,我们在 putStone 中验证着法并返回 INVALID_MOVE:

putStone: (G, ctx, id) => {
   
   
    if (G.stones[id] !== 0) {
   
   
        return INVALID_MOVE;
    }
    G.stones[id] = [1,-1][ctx.currentPlayer];
}

回合管理

不同的游戏,玩家在一回合可以进行的动作数量可能不同,结束回合的条件也不同。有的游戏一回合可以进行多个动作,有的一回合一个动作。五子棋就是一回合一个动作的游戏。在 Debug 面板中,我们可以点击 endTurn 手动结束回合。其实,客户端代码也可以执行完动作后自动结束回合。

在 boardgame.io 中有多种方法管理回合,使用 moveLimit 就是其中之一。下面我们就使用这种方法让引擎自动帮我们结束当前回合:

export const Gomoku = {
   
   
    setup: () => {
   
    /* ... */ },
    
	turn: {
   
   
	    moveLimit: 1,
	},
	
	moves: {
   
    /* ... */ },
};

胜利条件

我们的五子棋游戏定义得差不多了,只差最后一环:胜利局面判断。

首先,我们先加几个函数:

/**
 * 检查一条线上某一方是否成 5
 * @param {number[]} stones
 * @param {number} clr
 * @param {number} start
 * @param {number} end
 * @param {number} stride
 */
function checkWinnerByLine(stones, clr, start, end, stride) {
   
   
    let cnt = 0;
    for (; cnt < 5 && start !== end; start += stride) {
   
   
        if (stones[start] === clr) cnt++;
        else cnt = 0;
    }
    return cnt >= 5;
}

/**
 * 检查某位玩家是否获胜
 * @param {number[]} stones
 * @param {number} clr
 */
function isVictory(stones, clr) {
   
   
    const boardSize = 15;
    let x = 0,
        y = 0;
    let start = 0,
        end = 0,
        stride = 1;

    // horizontal
    stride = <
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值