欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑

程序员文章站 2022-05-25 13:56:39
...

棋类游戏中的棋子摆放逻辑

创建节点

代码编写


其实要点就一句话:我们看到的不应是棋盘,而是坐标。

现在通过下面的五子棋(或围棋)实例来看下如何理解这句话。

 

运行效果如下:

《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑

 

Cocos Creator版本:2.2.2

后台回复"",获取该项目完整文件。

《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑

 

创建节点

《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑

1. bg为Sprite类型节点,作为场景背景。

2. board bg也是Sprite类型节点,作为棋盘背景。

3. board虽然为空节点,但是非常关键,因为棋子都是添加到这个节点上的。它的大小应等于棋盘上可落子区域大小:

《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑

为方便开发,我们可以将该节点的锚点设置为(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。笔者这里给大家看下没有设置为透明时的样子:

《Cocos Creator游戏实战》棋类游戏中的棋子摆放逻辑

 

该预制上挂着的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. 虽然笔者这里用的是五子棋(或围棋)这个例子,但是开发逻辑同样适用于其他棋类,比如象棋。