Case:cocos地图和网格初始化

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

非盈利博客,只是学习笔记,如有雷同,十分抱歉。

一、生成一个100*100的网格背景

其由10000个单位小方块组成。
在这里插入图片描述

代码分析

定义了一个名为 GridArea 的组件,用于在游戏的场景中动态创建一个网格。

import { _decorator, Component, Prefab, instantiate, Node, Vec3, warn } from 'cc';

const { ccclass, property } = _decorator;


@ccclass
export default class GridArea extends Component {
    @property
    rows: number = 100; // 网格行数

    @property
    cols: number = 100; // 网格列数

    @property(Prefab)
    gridCellPrefab: Prefab = null; // 网格单元的预制体

    onLoad() {
        this.createGrid();
    }

    createGrid() {
        if (!this.gridCellPrefab) {
            warn("请设置网格单元的预制体");
            return;
        }

        const cellWidth = 50; // 每个网格单元的宽度
        const cellHeight = 50; // 每个网格单元的高度

        for (let row = 0; row < this.rows; row++) {
            for (let col = 0; col < this.cols; col++) {
                const gridCell = instantiate(this.gridCellPrefab);
                
                // 设置单元格位置
                gridCell.setPosition(
                    col * cellWidth + cellWidth / 2,
                    row * cellHeight + cellHeight / 2,
                    0 // Z轴坐标设置为0
                );

                // 将网格单元添加为当前节点的子节点
                this.node.addChild(gridCell);
            }
        }
    }
}


导入必要的模块

import { _decorator, Component, Prefab, instantiate, Node, Vec3, warn } from 'cc';

从 cc 模块导入了一些必要的类和函数:

  • _decorator: 用于定义装饰器。
  • Component: 所有组件的基类,用户自定义组件需要继承此类。
  • Prefab: 预制体类(即可以实例化的对象)。
  • instantiate: 用于创建预制体实例的函数。
  • Node: 表示树形结构中的节点(即场景中的任意对象)。
  • Vec3: 表示三维向量(通常用于位置、旋转和缩放)。
  • warn: 用于打印警告信息的函数。

定义装饰器和类

const { ccclass, property } = _decorator;

@ccclass
export default class GridArea extends Component {

  • 使用 @ccclass 装饰器标记类,使其成为 Cocos Creator 中的一个组件。
  • GridArea 类继承自 Component,因此它具有所有组件的基本特性。

类定义

@ccclass
export default class GridArea extends Component {

GridArea 类继承自 Component,成为一个 Cocos Creator 中的组件。使用 @ccclass 装饰器标记这个类,使其能被 Cocos Creator 识别和使用。


属性定义

@property
rows: number = 100; // 网格行数

@property
cols: number = 100; // 网格列数

@property(Prefab)
gridCellPrefab: Prefab = null; // 网格单元的预制体

使用 @property 装饰器定义了三个属性:

  • rows: 网格的行数,默认值为 100。
  • cols: 网格的列数,默认值为 100。
  • gridCellPrefab: 网格单元的预制体类型,初始值为空。这意味着在编辑器中,可以将一个预制体拖放到这个属性上,以便在运行时进行实例化。

生命周期方法 onLoad()

onLoad() {
    this.createGrid();
}

onLoad 是 Cocos Creator 提供的生命周期方法之一,在组件加载后自动调用。在这里,它调用 createGrid 方法来创建网格。


创建网格的方法 createGrid()

createGrid() {
        if (!this.gridCellPrefab) {
            warn("请设置网格单元的预制体");
            return;
        }

        const cellWidth = 50; // 每个网格单元的宽度
        const cellHeight = 50; // 每个网格单元的高度

        for (let row = 0; row < this.rows; row++) {
            for (let col = 0; col < this.cols; col++) {
                const gridCell = instantiate(this.gridCellPrefab);
                
                // 设置单元格位置
                gridCell.setPosition(
                    col * cellWidth + cellWidth / 2,
                    row * cellHeight + cellHeight / 2,
                    0 // Z轴坐标设置为0
                );

                // 将网格单元添加为当前节点的子节点
                this.node.addChild(gridCell);
            }
        }
    }

检查 gridCellPrefab 是否被赋值
createGrid() {
    if (!this.gridCellPrefab) {
        warn("请设置网格单元的预制体");
        return;
    }

首先检查 gridCellPrefab 是否被赋值。如果没有,则通过 warn 函数打印警告信息,并退出该方法。

网格单元的尺寸设置
const cellWidth = 50; // 每个网格单元的宽度
const cellHeight = 50; // 每个网格单元的高度

定义每个网格单元的宽度和高度,分别为 50 个单位。

嵌套循环创建网格
for (let row = 0; row < this.rows; row++) {
    for (let col = 0; col < this.cols; col++) {
        const gridCell = instantiate(this.gridCellPrefab);

使用两个嵌套循环遍历行和列。对于每一行和每一列,使用 instantiate 函数创建一个新的网格单元实例。


设置单元格位置
gridCell.setPosition(
    col * cellWidth + cellWidth / 2,
    row * cellHeight + cellHeight / 2,
    0 // Z轴坐标设置为0
);

  • 计算每个网格单元的位置。通过将列索引乘以单元宽度,再加上一半的单元宽度,来水平居中单元格;垂直方向同理。
  • Z轴坐标设置为 0,因为这是一个二维平面上的网格。
添加子节点
this.node.addChild(gridCell);

将当前创建的网格单元添加为 GridArea 组件的子节点,这样它就会出现在当前节点(即 GridArea 组件所在的游戏对象)下。


二、名词解释

1.装饰器

装饰器是一种特殊的语法结构,主要用于修改或增强类、方法、属性或参数的行为。它们是一种设计模式,通常用于元编程,也就是在运行时对代码进行修改或扩展。装饰器最初是 JavaScript 的一项提案,在许多现代 JavaScript 框架和库(如 Angular、React 和 Cocos Creator)中得到广泛应用。

装饰器的基本概念

  • 函数: 装饰器实际上是一个函数,它接受某个对象作为参数,并返回一个新的对象或修改原有对象。
  • 用法: 装饰器通常附加在类或类成员的声明上,比如在类定义前面或者在方法和属性前面。
  • 功能: 装饰器可以用于各种目的,例如:
    • 添加元数据
    • 进行日志记录
    • 权限检查
    • 修改方法的实现
    • 实现依赖注入

三、在网格背景,随机生成其他图块

import { _decorator, Component, Prefab, instantiate, Node, Vec3, warn, randomRangeInt } from 'cc';

const { ccclass, property } = _decorator;

@ccclass
export default class GridArea extends Component {
    @property
    rows: number = 100; // 网格行数

    @property
    cols: number = 100; // 网格列数

    @property(Prefab)
    gridCellPrefab: Prefab = null; // 网格单元的预制体

    @property(Prefab)
    dirtPrefab: Prefab = null; // 土块的预制体

    private gridCells: Node[][] = []; // 用于保存所有的网格单元

    onLoad() {
        this.createGrid();
        this.randomizeDirtBlocks(10); // 随机设置10个土块
    }

    createGrid() {
        if (!this.gridCellPrefab) {
            warn("请设置网格单元的预制体");
            return;
        }

        const cellWidth = 10; // 每个网格单元的宽度
        const cellHeight = 10; // 每个网格单元的高度

        for (let row = 0; row < this.rows; row++) {
            this.gridCells[row] = [];
            for (let col = 0; col < this.cols; col++) {
                const gridCell = instantiate(this.gridCellPrefab);
                
                // 设置单元格位置
                gridCell.setPosition(
                    col * cellWidth + cellWidth / 2,
                    row * cellHeight + cellHeight / 2,
                    0 // Z轴坐标设置为0
                );

                // 将网格单元添加为当前节点的子节点
                this.node.addChild(gridCell);
                this.gridCells[row][col] = gridCell;
            }
        }
    }

    randomizeDirtBlocks(numDirtBlocks: number) {
        if (!this.dirtPrefab) {
            warn("请设置土块的预制体");
            return;
        }

        let placedBlocks = 0;
        const totalCells = this.rows * this.cols;
        const placedIndices = new Set<number>();

        while (placedBlocks < numDirtBlocks && placedIndices.size < totalCells) {
            const randomIndex = randomRangeInt(0, totalCells);
            if (!placedIndices.has(randomIndex)) {
                placedIndices.add(randomIndex);
                const row = Math.floor(randomIndex / this.cols);
                const col = randomIndex % this.cols;

                // 移除原有的网格单元
                const oldCell = this.gridCells[row][col];
                oldCell.destroy();

                // 创建并设置新的土块单元
                const dirtCell = instantiate(this.dirtPrefab);
                dirtCell.setPosition(oldCell.getPosition());
                this.node.addChild(dirtCell);
                this.gridCells[row][col] = dirtCell;

                placedBlocks++;
            }
        }
    }
}


分析

装饰器与属性定义

const { ccclass, property } = _decorator;

@ccclass
export default class GridArea extends Component {
    @property
    rows: number = 100; // 网格行数

    @property
    cols: number = 100; // 网格列数

    @property(Prefab)
    gridCellPrefab: Prefab = null; // 网格单元的预制体

    @property(Prefab)
    dirtPrefab: Prefab = null; // 土块的预制体

    private gridCells: Node[][] = []; // 用于保存所有的网格单元

使用装饰器 @ccclass 来定义一个新的组件类 GridArea
定义了一些属性:

  • rows: 网格的行数,默认值为 100。
  • cols: 网格的列数,默认值为 100。
  • gridCellPrefab: 网格单元的预制体,类型为 Prefab
  • dirtPrefab: 土块的预制体,类型为 Prefab
  • gridCells: 一个二维数组,用于存储每个网格单元的引用。

生命周期方法

onLoad() {
    this.createGrid();
    this.randomizeDirtBlocks(10); // 随机设置10个土块
}

  • onLoad: 当组件加载时被调用。这里调用了 createGrid() 和 randomizeDirtBlocks(10) 方法。
  • createGrid(): 创建网格单元。
  • randomizeDirtBlocks(10): 随机放置 10 个土块。

创建网格

createGrid() {
    if (!this.gridCellPrefab) {
        warn("请设置网格单元的预制体");
        return;
    }

    const cellWidth = 10; // 每个网格单元的宽度
    const cellHeight = 10; // 每个网格单元的高度

    for (let row = 0; row < this.rows; row++) {
        this.gridCells[row] = [];
        for (let col = 0; col < this.cols; col++) {
            const gridCell = instantiate(this.gridCellPrefab);
            
            // 设置单元格位置
            gridCell.setPosition(
                col * cellWidth + cellWidth / 2,
                row * cellHeight + cellHeight / 2,
                0 // Z轴坐标设置为0
            );

            // 将网格单元添加为当前节点的子节点
            this.node.addChild(gridCell);
            this.gridCells[row][col] = gridCell;
        }
    }
}

  • createGrid 方法负责初始化网格。
  • 首先检查 gridCellPrefab 是否存在,如果不存在则发出警告并退出。
  • 定义单元格的宽度和高度。
  • 使用双重循环遍历每一行和每一列,实例化网格单元,并设置其位置,然后将其作为子节点添加到当前节点中。

其中这段代码的意思是:

 for (let row = 0; row < this.rows; row++) {
        this.gridCells[row] = [];
        for (let col = 0; col < this.cols; col++) {
            const gridCell = instantiate(this.gridCellPrefab);
  • 当外层循环开始时,row 的值从 0 开始,每次迭代增加 1。
  • this.gridCells[row] = []; 这行代码为当前行(row)创建一个新的空数组。这意味着对于每个 row,您都将创建一个新的子数组,用于存储该行中的所有网格单元。
  • 之后,在内层循环中,会实例化网格单元并将它们存储到这个刚创建的子数组中:this.gridCells[row][col] = gridCell;

随机化土块

randomizeDirtBlocks(numDirtBlocks: number) {
        if (!this.dirtPrefab) {
            warn("请设置土块的预制体");
            return;
        }

        let placedBlocks = 0;
        const totalCells = this.rows * this.cols;
        const placedIndices = new Set<number>();

        while (placedBlocks < numDirtBlocks && placedIndices.size < totalCells) {
            const randomIndex = randomRangeInt(0, totalCells);
            if (!placedIndices.has(randomIndex)) {
                placedIndices.add(randomIndex);
                const row = Math.floor(randomIndex / this.cols);
                const col = randomIndex % this.cols;

                // 移除原有的网格单元
                const oldCell = this.gridCells[row][col];
                oldCell.destroy();

                // 创建并设置新的土块单元
                const dirtCell = instantiate(this.dirtPrefab);
                dirtCell.setPosition(oldCell.getPosition());
                this.node.addChild(dirtCell);
                this.gridCells[row][col] = dirtCell;

                placedBlocks++;
            }
        }
    }
检查土块预制体
if (!this.dirtPrefab) {
    warn("请设置土块的预制体");
    return;
}

首先,方法检查 dirtPrefab 是否存在。如果没有设置土块的预制体,则会发出警告并提前返回,以避免后续操作失败。

初始化变量
let placedBlocks = 0;
const totalCells = this.rows * this.cols;
const placedIndices = new Set<number>();

  • placedBlocks: 记录已放置的土块数量,初始值为 0。
  • totalCells: 计算网格中的总单元格数,即行数和列数的乘积。
  • placedIndices: 使用一个集合来存储已经放置土块的索引,确保每个索引只能放置一次土块。
随机放置土块
while (placedBlocks < numDirtBlocks && placedIndices.size < totalCells) {
    const randomIndex = randomRangeInt(0, totalCells);
    if (!placedIndices.has(randomIndex)) {
        placedIndices.add(randomIndex);
        const row = Math.floor(randomIndex / this.cols);
        const col = randomIndex % this.cols;

  • 使用 while 循环,继续执行直到达到要求放置的土块数量 (numDirtBlocks) 或者已经放置过所有可能的位置。
  • randomIndex = randomRangeInt(0, totalCells): 随机生成一个代表网格单元的索引。在范围[0, totalCells)之间产生随机整数。
  • if (!placedIndices.has(randomIndex)): 检查所选的随机索引是否已经使用过。如果没有,则继续执行以下代码:
    • 将当前的随机索引添加到 placedIndices 集合中。
    • 通过 Math.floor(randomIndex / this.cols) 计算出对应的行(row)。
    • 通过 randomIndex % this.cols 计算出对应的列(col)。

替换原有网格单元
const oldCell = this.gridCells[row][col];
oldCell.destroy();
  • 从 gridCells 数组中获取对应位置的原有网格单元(oldCell)。
  • 调用 oldCell.destroy() 方法移除原有的网格单元。这样可以清理出空间来放置新的土块
创建并放置土块
const dirtCell = instantiate(this.dirtPrefab);
dirtCell.setPosition(oldCell.getPosition());
this.node.addChild(dirtCell);
this.gridCells[row][col] = dirtCell;
  • 实例化一个土块的预制体(dirtCell)。
  • 使用 setPosition(oldCell.getPosition()) 设置新土块的位置,使其与被替换的网格单元位置相同。
  • 将新生成的土块作为子节点添加到当前节点中(this.node.addChild(dirtCell))。
  • 在 gridCells 数组的相应位置更新为新放置的土块(this.gridCells[row][col] = dirtCell)。
更新计数
placedBlocks++;

  • 增加已放置的土块计数器 placedBlocks 的值,以便在下一次循环中进行判断。

进阶:随机两个预制体

import { _decorator, Component, Prefab, instantiate, Node, Vec3, warn, randomRangeInt } from 'cc';

const { ccclass, property } = _decorator;

@ccclass
export default class GridArea extends Component {
    @property
    rows: number = 100; // 网格行数

    @property
    cols: number = 100; // 网格列数

    @property(Prefab)
    gridCellPrefab: Prefab = null; // 网格单元的预制体

    @property(Prefab)
    kuangPrefab: Prefab = null; // 矿的预制体、

    @property(Prefab)
    kengPrefab: Prefab = null; // 坑的预制体、

    @property(Prefab)
    mountainPrefab: Prefab = null; // 山的预制体、

    private gridCells: Node[][] = []; // 用于保存所有的网格单元

    onLoad() {
        this.createGrid();
        this.randomkuang(10); // 随机设置10个矿
        this.randomkeng(10); // 随机设置10个矿

    }

    createGrid() {
        if (!this.gridCellPrefab) {
            warn("请设置网格单元的预制体");
            return;
        }

        const cellWidth = 10; // 每个网格单元的宽度
        const cellHeight = 10; // 每个网格单元的高度

        for (let row = 0; row < this.rows; row++) {
            this.gridCells[row] = [];
            for (let col = 0; col < this.cols; col++) {
                const gridCell = instantiate(this.gridCellPrefab);
                
                // 设置单元格位置
                gridCell.setPosition(
                    col * cellWidth + cellWidth / 2,
                    row * cellHeight + cellHeight / 2,
                    0 // Z轴坐标设置为0
                );

                // 将网格单元添加为当前节点的子节点
                this.node.addChild(gridCell);
                this.gridCells[row][col] = gridCell;
            }
        }
    }

    randomkuang(numkuang: number) {
        if (!this.kuangPrefab) {
            warn("请设置矿的预制体");
            return;
        }

        let placedBlocks = 0;
        const totalCells = this.rows * this.cols;
        const placedIndices = new Set<number>();

        while (placedBlocks < numkuang && placedIndices.size < totalCells) {
            const randomIndex = randomRangeInt(0, totalCells);
            if (!placedIndices.has(randomIndex)) {
                placedIndices.add(randomIndex);
                const row = Math.floor(randomIndex / this.cols);
                const col = randomIndex % this.cols;

                // 移除原有的网格单元
                const oldCell = this.gridCells[row][col];
                oldCell.destroy();

                // 创建并设置新的土块单元
                const dirtCell = instantiate(this.kuangPrefab);
                dirtCell.setPosition(oldCell.getPosition());
                this.node.addChild(dirtCell);
                this.gridCells[row][col] = dirtCell;

                placedBlocks++;
            }
        }
    }

    randomkeng(numkeng: number) {
        if (!this.kengPrefab) {
            warn("请设置矿的预制体");
            return;
        }

        let placedBlocks = 0;
        const totalCells = this.rows * this.cols;
        const placedIndices = new Set<number>();

        while (placedBlocks < numkeng && placedIndices.size < totalCells) {
            const randomIndex = randomRangeInt(0, totalCells);
            if (!placedIndices.has(randomIndex)) {
                placedIndices.add(randomIndex);
                const row = Math.floor(randomIndex / this.cols);
                const col = randomIndex % this.cols;

                // 移除原有的网格单元
                const oldCell = this.gridCells[row][col];
                oldCell.destroy();

                // 创建并设置新的土块单元
                const dirtCell = instantiate(this.kengPrefab);
                dirtCell.setPosition(oldCell.getPosition());
                this.node.addChild(dirtCell);
                this.gridCells[row][col] = dirtCell;

                placedBlocks++;
            }
        }
    }
}


四、基础函数的详细解释

placedIndices.has(randomIndex)

作用: 检查集合中是否包含给定的索引
has() 方法用于检查 placedIndices 集合里是否已经存在 randomIndex。如果存在,返回 true;如果不存在,返回 false。

randomRangeInt

randomRangeInt 是一个用于生成随机整数的函数。它通常接受两个参数,表示生成随机整数的范围(最小值和最大值)。尽管具体实现可能因上下文而异,但使用此函数的目的都是为了在指定的范围内生成一个随机的整数。
EXA:
0 到 10 之间生成一个随机整数

const randomNum = randomRangeInt(0, 10);
console.log(randomNum); // 可能输出 0 到 9 之间的任意整数


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值