Cocos Creator 华容道

环境:cocos creator 2.0.10 + Mac环境 + TypeScript   (文末附源码链接)

本文提供了游戏玩法的逻辑,支持关卡配置(可以自由配置关卡)

先看一下效果:

 

首先,我们看一下我们要处理的问题:

1. 区域划分

2. 角色摆放(即:关卡元素摆放)

3. 如何移动 (滑动处理,能否移动)

4. 是否过关

把游戏里的点,有条不紊的划分出来,并一一击破,这样实现起来才会更加轻松自如。

 

代码并不复杂,应该很容易解读

Configs.ts  

eROW:5行

eCOL:4列

eGridSideLength:单位格子宽度为150

eDIR:移动方向

HEDRoles:角色配置信息 place:12 拆开来看,即横向占用1个格子,纵向占用2个格子

/**
 * 配置信息
 */

export var eROW = 5;
export var eCOL = 4;
export var eGridSideLength = 150;

export var eDIR = cc.Enum({
    UP: 1,
    DOWN: 2,
    LEFT: 3,
    RIGHT: 4,
});

export var HRDRoles = {
    "1": {
        "name": "曹操",
        "engName": "CaoCao",
        "place": 22,
        "spriteFrame": "caocao22"
    },
    "2": {
        "name": "关羽",
        "engName": "GuanYu",
        "place": 12,
        "spriteFrame": "guanyu12"
    },
    "3": {
        "name": "关羽",
        "engName": "GuanYu",
        "place": 21,
        "spriteFrame": "guanyu21"
    },
    "4": {
        "name": "张飞",
        "engName": "ZhangFei",
        "place": 12,
        "spriteFrame": "zhangfei12"
    },
    "5": {
        "name": "张飞",
        "engName": "ZhangFei",
        "place": 21,
        "spriteFrame": "zhangfei21"
    },
    "6": {
        "name": "黄忠",
        "engName": "HuangZhong",
        "place": 12,
        "spriteFrame": "huangzhong12"
    },
    "7": {
        "name": "黄忠",
        "engName": "HuangZhong",
        "place": 21,
        "spriteFrame": "zuangzhong21"
    },
    "8": {
        "name": "马超",
        "engName": "MaChao",
        "place": 12,
        "spriteFrame": "machao12"
    },
    "9": {
        "name": "马超",
        "engName": "MaChao",
        "place": 21,
        "spriteFrame": "machao21"
    },
    "10": {
        "name": "赵云",
        "engName": "ZhaoYun",
        "place": 12,
        "spriteFrame": "zhaoyun12"
    },
    "11": {
        "name": "赵云",
        "engName": "ZhaoYun",
        "place": 21,
        "spriteFrame": "zhaoyun21"
    },
    "12": {
        "name": "兵1",
        "engName": "soldier",
        "place": 11,
        "spriteFrame": "soldier11"
    },
    "13": {
        "name": "兵2",
        "engName": "soldier",
        "place": 11,
        "spriteFrame": "soldier11"
    },
    "14": {
        "name": "兵3",
        "engName": "soldier",
        "place": 11,
        "spriteFrame": "soldier11"
    },
    "15": {
        "name": "兵4",
        "engName": "soldier",
        "place": 11,
        "spriteFrame": "soldier11"
    }

};

Levels.ts

关卡配置信息,每4个元素占用1行,一共5行,共20个元素 (其中0表示格子未被占用)

export var HRDLevels = {
    "1": [2, 10, 0, 6, 2, 10, 0, 6, 8, 4, 1, 1, 8, 4, 1, 1, 12, 13, 14, 15],
};

HuaRongDao.ts

import { HRDRoles, eGridSideLength, eROW, eCOL, eDIR } from "./Configs";
import { HRDLevels } from "./Levels";

const { ccclass, property } = cc._decorator;
/**
 * 坐标索引,均以左上角为锚点
 * &----&----&----&-----
 * | 00 | 01 | 02 | 03 |
 * &----&----&----&-----
 * | 10 | 11 | 12 | 13 |
 * &----&----&----&-----
 * | 20 | 21 | 22 | 23 |
 * &----&----&----&-----
 * | 30 | 31 | 32 | 33 |
 * &----&----&----&-----
 * | 40 | 41 | 42 | 43 |
 * ---------------------
 */
@ccclass
export default class HuaRongDao extends cc.Component {

    @property(cc.Node)
    nodeMoveArea: cc.Node = null;

    @property(cc.Node)
    nodeCong: cc.Node = null;

    nodeRoleArr: Array<cc.Node> = [];

    // 左上角开始放置位置
    m_placeStartPos: cc.Vec2 = cc.v2(0, 0);

    placeArr: Array<any> = [];

    m_startPos: cc.Vec2 = null;
    m_endPos: cc.Vec2 = null;

    m_touchNode: cc.Node = null;

    onLoad() {
        this.addTouchEventListener();
        this._initLevel("1");
    }

    private addTouchEventListener() {
        this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
    }

    private onTouchStart(event) {
        this.m_startPos = event.touch.getLocation();
        // 找到touch的角色
        let worldPos = this.node.convertToWorldSpace(this.m_startPos);
        for (let i = 0; i < this.nodeRoleArr.length; i++) {
            let curNode = this.nodeRoleArr[i];
            if (curNode && curNode.isValid) {
                let nodePos = this.nodeMoveArea.convertToNodeSpaceAR(worldPos);
                let rect = cc.rect(curNode.getPosition().x, curNode.getPosition().y - curNode.getContentSize().height, curNode.getContentSize().width, curNode.getContentSize().height);
                let isInRect = rect.contains(nodePos);
                if (isInRect) {
                    this.m_touchNode = curNode;
                    let heroData = HRDRoles[this.m_touchNode.name];
                    cc.log("m_touchNode id = " + heroData.name);
                    break;
                }
            }
        }
    }

    private onTouchMove(event) {

    }

    private onTouchEnd(event) {
        this.m_endPos = event.touch.getLocation();
        let dis = this.m_startPos.sub(this.m_endPos).mag();

        if (dis >= 30 && this.m_touchNode) {
            cc.log("滑动了");
            this.moveDirection(this.m_startPos, this.m_endPos);
        }
    }

    private onTouchCancel(event) {
        this.m_endPos = event.touch.getLocation();
        let dis = this.m_startPos.sub(this.m_endPos).mag();

        if (dis >= 30 && this.m_touchNode) {
            cc.log("滑动了cancel");
            this.moveDirection(this.m_startPos, this.m_endPos);
        }
    }

    /**
     * 判断滑动方向
     * @param sPos 
     * @param ePos 
     */
    private moveDirection(sPos: cc.Vec2, ePos: cc.Vec2) {
        let deltaX = Math.abs(ePos.x - sPos.x);
        let deltaY = Math.abs(ePos.y - sPos.y);
        if (deltaX >= deltaY) {
            if (ePos.x > sPos.x) {
                cc.log("### right ###");
                this._moveRole(eDIR.RIGHT);
            } else {
                cc.log("### left ###");
                this._moveRole(eDIR.LEFT);
            }
        } else {
            if (ePos.y > sPos.y) {
                cc.log("### up ###");
                this._moveRole(eDIR.UP);
            } else {
                cc.log("### down ###");
                this._moveRole(eDIR.DOWN);
            }
        }
    }

    private _moveRole(dir: number) {
        if (!this.m_touchNode || !this.m_touchNode.isValid) {
            cc.error("[HuaRongDao] _moveRole m_touchNode error.");
            return;
        }
        switch (dir) {
            case eDIR.UP:
                this._moveUp();
                break;
            case eDIR.DOWN:
                this._moveDown();
                break;
            case eDIR.LEFT:
                this._moveLeft();
                break;
            case eDIR.RIGHT:
                this._moveRight();
                break;
        }
    }

    private _moveUp() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveUp row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveUp = true;
        if (row - 1 < 0) {
            canMoveUp = false;
        } else {
            for (let i = col; i < col + roleRow; i++) {
                if (this.placeArr[row - 1][i] != -1) {
                    cc.log("不能移动");
                    canMoveUp = false;
                    break;
                }
            }
        }
        if (canMoveUp) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x, this.m_touchNode.getPosition().y + eGridSideLength);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = col; i < col + roleRow; i++) {
                this.placeArr[row - 1][i] = 1;
                this.placeArr[row + roleCol - 1][i] = -1;
            }
            this._printDataArr();
        }
    }

    private _moveDown() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveDown row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveDown = true;
        if (row + 1 >= eROW) {
            canMoveDown = false;
        } else {
            for (let i = col; i < col + roleRow; i++) {
                if (this.placeArr[row + roleCol][i] != -1) {
                    cc.log("不能移动");
                    canMoveDown = false;
                    break;
                }
            }
        }
        if (canMoveDown) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x, this.m_touchNode.getPosition().y - eGridSideLength);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = col; i < col + roleRow; i++) {
                this.placeArr[row + roleCol][i] = 1;
                this.placeArr[row][i] = -1;
            }
            this._printDataArr();
        }
    }

    private _moveLeft() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveLeft row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveLeft = true;
        if (col - 1 < 0) {
            canMoveLeft = false;
        } else {
            for (let i = row; i < row + roleCol; i++) {
                if (this.placeArr[row + roleRow - 1][col - 1] != -1) {
                    cc.log("不能移动");
                    canMoveLeft = false;
                    break;
                }
            }
        }
        if (canMoveLeft) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x - eGridSideLength, this.m_touchNode.getPosition().y);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = row; i < row + roleCol; i++) {
                this.placeArr[i][col - 1] = 1;
                this.placeArr[i][col + roleRow - 1] = -1;
            }
            this._printDataArr();
        }
    }

    private _moveRight() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveRight row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveRight = true;
        if (col + 1 >= eCOL) {
            canMoveRight = false;
        } else {
            for (let i = row; i < row + roleRow; i++) {
                if (this.placeArr[i][col + 1] != -1) {
                    cc.log("不能移动");
                    canMoveRight = false;
                    break;
                }
            }
        }
        if (canMoveRight) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x + eGridSideLength, this.m_touchNode.getPosition().y);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = row; i < row + roleCol; i++) {
                this.placeArr[i][col + 1] = 1;
                this.placeArr[i][col - roleRow + 1] = -1;
            }
            this._printDataArr();
        }
    }

    /**
     * 判断游戏是否过关
     */
    private _checkVictory(): boolean {
        let pass = false;
        // let roleNode = this.nodeMoveArea.getChildByName("1");

        let roleNode = null;
        for (let i = 0; i < this.nodeRoleArr.length; i++) {
            let node = this.nodeRoleArr[i];
            if (node.name == "1") {
                roleNode = node;
            }
        }

        if (roleNode && roleNode.isValid) {
            let rowAndCol = this._posTranslateIndex(roleNode);
            if (rowAndCol.row === 3 && rowAndCol.col === 1) {
                pass = true;
            }
        }
        if (pass) {
            cc.log("恭喜过关");
            this.nodeCong.active = true;
            // 过关逻辑
        }
        return pass;


    }

    /**
     * 辅助打印数组信息
     */
    private _printDataArr() {
        for (let i = 0; i < this.placeArr.length; i++) {
            cc.log("[" + [this.placeArr[i][0]] + ", " + [this.placeArr[i][1]] + ", " + [this.placeArr[i][2]] + ", " + [this.placeArr[i][3]] + "]");
        }
    }

    /**
     * 通过position获取节点占用位置的索引
     * 注意:这里的位置有可能是带很多小数点的浮点数,所以使用Math.round
     * @param node 
     */
    private _posTranslateIndex(node: cc.Node) {
        let rowAndCol: any = {};
        for (let i = 0; i < eCOL; i++) {
            for (let j = 0; j < eROW; j++) {
                let xEquel = this.m_placeStartPos.x + i * eGridSideLength === Math.round(node.getPosition().x);
                let yEquel = this.m_placeStartPos.y - j * eGridSideLength === Math.round(node.getPosition().y);
                if (xEquel && yEquel) {
                    rowAndCol.row = j;
                    rowAndCol.col = i;
                    return rowAndCol;
                }
            }
        }
        cc.error("[HuaRongDao] _posTranslateIndex get wrong!!!");
        return null;
    }

    /**
     * 重置游戏数据
     */
    private _resetData() {
        this.m_placeStartPos = cc.v2(-this.nodeMoveArea.getContentSize().width / 2, this.nodeMoveArea.getContentSize().height / 2);
        this.nodeRoleArr = [];
        this.nodeMoveArea.removeAllChildren(true);

        this.placeArr = [];
        for (let i = 0; i < eROW; i++) {
            let arr: Array<number> = [];
            for (let j = 0; j < eCOL; j++) {
                arr.push(-1);
            }
            this.placeArr.push(arr);
        }
    }

    /**
     * 初始化关卡信息
     * @param lv 关卡等级
     */
    private _initLevel(lv: string) {
        this._resetData();
        let leveInfo = HRDLevels[lv];
        let index = 0;
        let roleConfig = null;
        for (let i = 0; i < eROW; i++) {
            for (let j = 0; j < eCOL; j++) {
                index = i * eCOL + j;
                let heroID = leveInfo[index];
                if (heroID === 0 || this.placeArr[i][j] === 1) {
                    continue;
                }

                roleConfig = HRDRoles[heroID];
                if (roleConfig) {
                    this._createSprite(heroID, cc.v2(this.m_placeStartPos.x + j * eGridSideLength, this.m_placeStartPos.y - i * eGridSideLength));
                    let place = roleConfig.place;
                    let front = Math.floor(place / 10);
                    let rear = place % 10;
                    for (let k = i; k < i + rear; k++) {
                        for (let m = j; m < j + front; m++) {
                            if (this.placeArr[k][m]) {
                                this.placeArr[k][m] = 1;
                            }
                        }
                    }
                }
            }
        }
    }

    private _createSprite(id: string, pos: cc.Vec2) {
        let roleData = HRDRoles[id];
        if (roleData) {
            let url = "huarongdao/" + roleData.spriteFrame;
            cc.loader.loadRes(url, cc.SpriteFrame, (err, spriteFrame) => {
                if (err) {
                    cc.error("[CCUtils] createSprite err = " + err);
                    return;
                } else {
                    let node = new cc.Node(id);
                    node.setAnchorPoint(cc.v2(0, 1));
                    let sprite = node.addComponent(cc.Sprite);
                    sprite.spriteFrame = spriteFrame;
                    node.setPosition(pos);

                    this.nodeMoveArea.addChild(node);
                    this.nodeRoleArr.push(node);
                }
            });
        }
    }

    public onBtnNextLevel(event: cc.Event, data: string) {
        if (event.type === cc.Node.EventType.TOUCH_END) {
            this._initLevel("2");
        }
    }

}

源码地址: https://gitee.com/jackxieff/Klotski.git

评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符 “速评一下”
©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页