《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑
棋类游戏中的棋子摆放逻辑
其实要点就一句话:我们看到的不应是棋盘,而是坐标。
现在通过下面的五子棋(或围棋)实例来看下如何理解这句话。
运行效果如下:
Cocos Creator版本:2.2.2
后台回复"棋",获取该项目完整文件。
创建节点
1. bg为Sprite类型节点,作为场景背景。
2. board bg也是Sprite类型节点,作为棋盘背景。
3. board虽然为空节点,但是非常关键,因为棋子都是添加到这个节点上的。它的大小应等于棋盘上可落子区域大小:
为方便开发,我们可以将该节点的锚点设置为(0, 0),那么对棋子来说左下角就是坐标原点了。
4. dot预制也会添加到board节点上。棋盘上有多少个点,就会有多少个预制。每个预制都会进行触摸监听,玩家点击到哪个dot,那么我们就在相应的dot位置上放一个棋子。
5. piece预制用来当做棋子。
代码编写
首先我们新建一个Board.js脚本,添加属性并编写onLoad方法内容:
// Board.js
properties: {
piecePrefab: cc.Prefab, // 棋子预制
touchDotPrefab: cc.Prefab // 触摸点预制
},
// LIFE-CYCLE CALLBACKS:
onLoad () {
cc.debug.setDisplayStats(false);
const hLines = 15; // 水平线数量
const vLines = 15; // 垂直线数量
this.blockWidth = (this.node.width / (vLines-1)).toFixed(2); // 每块区域的宽度
this.blockHeight = (this.node.height / (hLines-1)).toFixed(2); // 每块区域的高度
this.boardPosArray = []; // 棋盘上所有点的坐标
this.getBoardPos(hLines, vLines);
this.currentPlayer = 'BLACK'; // 当前着步方
this.initTouchDots(); // 添加所有触摸点
},
1. hLines和vLines常量用来保存棋盘上的水平线和垂直线数量,五子棋(围棋)的棋盘是一个正方形,所以横竖线数量相等,都为15。
2. 既然已经知道了可落子区域的总大小和横竖线数量,那么我们就可以求出每块小区域的大小了。
3. boardPosArray数组用来存储棋盘上各个点的坐标。而获取各个点的坐标就在getBoardPos方法中:
// Board.js
getBoardPos(hLines, vLines) {
for (let i=0; i<hLines; i++) {
for (let j=0; j<vLines; j++) {
let x = j*this.blockWidth;
let y = i*this.blockHeight;
this.boardPosArray.push([x, y, '0']);
}
}
},
boardPosArray数组的每个元素包含一个x坐标,一个y坐标以及用来判断当前位置是否存在棋子的标识,初始化时都是'0'。
4. currentPlayer变量用来存储当前的着步方。
5. initTouches用来添加触摸点,方法编写如下:
// Board.js
initTouchDots() {
for (let i=0; i<this.boardPosArray.length; i++) {
let touchDot = cc.instantiate(this.touchDotPrefab);
touchDot.opacity = 0;
this.node.addChild(touchDot);
touchDot.getComponent('TouchDot').initBoard(this);
touchDot.setPosition(this.boardPosArray[i][0], this.boardPosArray[i][1])
}
},
触摸点是不能被看到的,所以透明度需要设为0。笔者这里给大家看下没有设置为透明时的样子:
该预制上挂着的TouchDot.js脚本编写如下:
// TouchDot.js
cc.Class({
extends: cc.Component,
properties: {
},
// LIFE-CYCLE CALLBACKS:
onLoad () {
this.node.on('touchstart', this.onTouchStart, this);
},
initBoard(board) {
this.board = board;
},
onTouchStart() {
this.board.putPiece(this.node.x, this.node.y);
}
});
initBoard方法用于获取Board.js脚本实例。在onTouchStart方法中我们调用Board.js中的putPiece方法直接将棋子放置到该触摸点的位置。
putPiece方法编写如下:
// Board.js
putPiece(x, y) {
// 放置棋子,并更新着步方xx
let is_ok = this.check(x.toFixed(2), y.toFixed(2));
if (!is_ok)
return;
let piece = cc.instantiate(this.piecePrefab);
this.node.addChild(piece);
piece.getComponent('Piece').setPic(this.currentPlayer);
piece.width = this.blockWidth*0.9;
piece.height = this.blockHeight*0.9;
piece.setPosition(x, y)
if (this.currentPlayer == 'BLACK') {
this.currentPlayer = 'WHITE';
}
else {
this.currentPlayer = 'BLACK';
}
},
在该方法中,我们首先要调用check方法判断当前位置是否已经有棋子了,如果没有那么就在该位置上放一个棋子,放置完毕则更改着步方。
check方法编写如下:
// Board.js
check(x, y) {
// 查看当前位置是否可以着步
for (let i=0; i<this.boardPosArray.length; i++) {
if (x==this.boardPosArray[i][0] && y==this.boardPosArray[i][1]){
if (this.boardPosArray[i][2]=='0') {
// 可以放置,并更新数组
this.boardPosArray[i][2] = '1';
return true;
}
else {
// 已有棋子,不可放置
return false;
}
}
}
}
其实就是循环boardPosArray数组,判断该位置上是'0'还是'1',如果是前者,那么表明可以放置。
注:笔者这里的判断只是给大家进行简单进行演示,并不一定符合下棋规则。比如围棋中的某个空位落子后会直接没"气"(也就是说该空位已经被围死了),那么也不能在这个空位上落子对吧。
棋子预制上挂着的Piece.js脚本编写如下:
// Piece.js
cc.Class({
extends: cc.Component,
properties: {
blackPic: cc.SpriteFrame,
whitePic: cc.SpriteFrame
},
// LIFE-CYCLE CALLBACKS:
onLoad () {},
setPic(currentPlayer) {
if (currentPlayer=='BLACK') {
this.node.getComponent(cc.Sprite).spriteFrame = this.blackPic;
}
else if (currentPlayer=='WHITE') {
this.node.getComponent(cc.Sprite).spriteFrame = this.whitePic;
}
}
});
blackPic和whitePic就是黑白棋子图片,而setPic方法会根据当前的着步方来设置相应的棋子图片。
好,那本节教程就到这,希望大家有所收获~
P.S. 虽然笔者这里用的是五子棋(或围棋)这个例子,但是开发逻辑同样适用于其他棋类,比如象棋。
上一篇: js 实现ai五子棋人机大战
下一篇: 北航机试13年02题:简单八皇后