使用Pixi.js实现《围追堵截》桌游(四)
前言
在前面的文章中我们已经实现了包括游戏对象绘制,管理类实现以及游戏的基本交互。本篇文章中我们将实现游戏的回合相关逻辑,这也是整体游戏实现的最后部分。
游戏内回合的分析与实现
游戏的回合切换逻辑
游戏回合的变化,本质上就是对棋盘操作能力的交换。
我们在玩棋牌类游戏时,往往只有在本人的回合才能进行出牌/移动棋子等交互动作,这是每一个参与游戏的人都需要遵守游戏规则(否则容易被踢下桌)。
在我们的游戏中为了让大家都可以遵守游戏规则,我们需要根据游戏进程限制玩家的操作能力以及 UI 交互来确保游戏的回合可以正常持续下去。
对玩家而言当前回合的操作分为两种:操作棋子进行移动和选择挡板进行阻挡。通过限制这两项能力来区分出当前是谁的回合,当然,也要将回合的变化通过发送事件通知 UI 从而体现在用户界面上。
下面我们来看下游戏回合切换的实现:
/**
* Game 类
* /
// 切换回合
nextTurn() {
// 切换当前玩家
this.currentPlayer = this.currentPlayer === this.player1 ? this.player2 : this.player1;
// 通知 UI 回合切换
this.emit('turn-update', {
current: this.currentPlayer,
player1: this.player1,
player2: this.player2,
});
// 每回合开始时,将操作模式设置为移动棋子
this.changeCurrentTurnMode(RoleMoveModeEnum.Move);
}
// 改变本回合操作模式 移动/阻挡
changeCurrentTurnMode(mode) {
if (mode === RoleMoveModeEnum.Block) {
this.toggleGapInteractive(true);
this.toggleRectInteractive(false);
} else {
this.toggleGapInteractive(false);
this.toggleRectInteractive(true);
}
}
// 开启/关闭所有的 Gap 绘制对象的交互事件
toggleGapInteractive(isOpen) {
// 获取棋盘上的所有绘制对象
const allEnitity = this.boardEntity.getAllChildEnitity();
if (isOpen) {
allEnitity.forEach(row => {
row.forEach(entity => {
if (entity instanceof GapEntity) {
// doOpenInteractive 方法会过滤掉无方向的 Gap
entity.doOpenInteractive();
}
});
});
} else {
allEnitity.forEach(row => {
row.forEach(entity => {
if (entity instanceof GapEntity) {
entity.doCloseInteractive();
}
});
});
}
}
// 开启/关闭 Rect 的交互事件
toggleRectInteractive() {
if (isOpen) {
const gridColor = this.currentPlayer.getGridColor();
// 获取玩家当前可移动的所有 Rect,在上篇文章中我们在玩家的 nextTurn 方法中计算过该属性的值
const currentValidRects = this.currentPlayer.getValidRects();
currentValidRects.forEach(item => {
const ele = this.boardEntity.getElementByPos(item.x, item.y);
if (ele instanceof RectEntity) {
// 这里将开启了交互的 Rect 暂存起来
this._cacheVaildRect.push(ele);
// 开启 Rect 的交互并给予一个颜色,使用当前玩家的颜色用来进一步区分当前可移动的棋子是哪个
ele.doOpenInteractive(gridColor);
}
});
} else {
this.currentPlayer.toggleSelected(false);
if (this._cacheVaildRect.length) {
// 这里将暂存中开启交互的 Rect 交互全部关闭
this._cacheVaildRect.forEach(ele => {
ele.doCloseInteractive();
});
this._cacheVaildRect = [];
}
}
}
至此,我们已经完成了整个游戏的 90% 的逻辑,还有一些 UI 交互的细节由于不是实现的重点内容不再进行赘述。
本游戏内还实现了辅助线功能,它的目的是用来绘制基于 A* 计算的当前玩家到达所有终点的路径,从而辅助玩家进行决策,感兴趣的同学可以去项目内看看具体的实现过程 /src/game-core/entity/assist-line.js
结语
恭喜你已经一步步完成了《围追堵截》这款桌游的 web 版实现!!!希望在这个过程中你能够有所收益。 同时如果有任何问题也可以在评论区留言,我都会一一回复。
下面是一些本项目可以继续改造练手的地方:
- 将比较粗糙的计算逻辑进一步优化性能。
- 加入一些音效,或者优化用户界面适配移动端。
- 尝试更换一个 2D/3D 引擎来重新实现整个游戏。
- 将此单机游戏改造成服务端参与,从而进行网络对战。
再见 👋