提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
非盈利博客,只是学习笔记,如有雷同,十分抱歉。
一、生成一个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提供了大量能使我们快速便捷地处理数据的函数和方法。