mirror of
https://github.com/Gongxh0901/kunpolibrary
synced 2025-10-09 16:45:45 +00:00
模块拆分
This commit is contained in:
102
docs/Asset.md
102
docs/Asset.md
@@ -1,102 +0,0 @@
|
||||
## 资源加载
|
||||
> !!! 注意:资源加载多次和一次效果一样
|
||||
|
||||
### 特点
|
||||
* 可通过路径或者uuid获取资源
|
||||
|
||||
* 只适合手动管理资源,单无论加载多少次,卸载一次后删除
|
||||
|
||||
* 可根据 `new kunpo.AssetLoader("batchName")` 传入的 `batchName`批量卸载资源
|
||||
|
||||
> 比如进入战斗时,创建了多个new kunpo.AssetLoader("batchName") 来加载资源,传入的batchName相同
|
||||
>
|
||||
> 等退出战斗后,可以通过 AssetPool.releaseBatchAssets("batchName") 一键释放所有等于batchName的资源
|
||||
|
||||
### 使用
|
||||
```typescript
|
||||
let paths: kunpo.IAssetConfig[] = [
|
||||
{ path: "ui/manual", type: cc.Asset },
|
||||
{ path: "prefab", type: cc.Prefab },
|
||||
{ path: "icon", type: cc.SpriteFrame },
|
||||
{ path: "texture/6101/spriteFrame", type: cc.SpriteFrame, isFile: true },
|
||||
{ path: "pet", type: cc.SpriteFrame, bundle: "bundle_res" },
|
||||
];
|
||||
let loader = new kunpo.AssetLoader("batchName");
|
||||
loader.start({
|
||||
configs: paths,
|
||||
complete: () => {
|
||||
console.log("加载完成");
|
||||
},
|
||||
fail: (msg: string, err: Error) => {
|
||||
console.log("加载失败", msg, err);
|
||||
},
|
||||
progress: (percent: number) => {
|
||||
console.log("加载进度", percent);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 接口
|
||||
#### *资源加载器*
|
||||
|
||||
```typescript
|
||||
interface IAssetConfig {
|
||||
/** 资源类型 */
|
||||
type: typeof Asset;
|
||||
/** 资源路径 */
|
||||
path: string;
|
||||
/** 是否是单个文件 默认是文件夹 */
|
||||
isFile?: boolean;
|
||||
/** 资源包名 默认 resources */
|
||||
bundle?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始加载资源
|
||||
* @param {IAssetConfig[]} res.configs 资源配置
|
||||
* @param {number} res.parallel 并行加载数量 默认 10
|
||||
* @param {number} res.retry 失败重试次数 默认 3
|
||||
* @param {Function} res.complete 加载完成回调
|
||||
* @param {Function} res.progress 加载进度回调
|
||||
* @param {Function} res.fail 加载失败回调
|
||||
*/
|
||||
public start(res: { configs: IAssetConfig[], parallel?: number, retry?: number, complete: () => void, fail: (msg: string, err: Error) => void, progress?: (percent: number) => void }): void
|
||||
|
||||
/** 重试 重新加载失败的资源 */
|
||||
public retry(): void
|
||||
```
|
||||
|
||||
#### *资源池*
|
||||
|
||||
```typescript
|
||||
/** 资源是否已加载 */
|
||||
public static has(path: string, bundlename: string = "resources"): boolean
|
||||
|
||||
/** 获取资源 */
|
||||
public static get<T extends Asset>(path: string, bundlename: string = "resources"): T
|
||||
|
||||
/** 按 uuid 判断资源是否已加载 */
|
||||
public static hasUUID(uuid: string): boolean
|
||||
|
||||
/** 按 uuid 获取资源 */
|
||||
public static getByUUID<T extends Asset>(uuid: string): T
|
||||
|
||||
/** 按资源路径释放资源 */
|
||||
public static releasePath(path: string, bundlename: string = "resources"): void
|
||||
|
||||
/** 按 bundle 和 文件夹释放资源 */
|
||||
public static releaseDir(dir: string, bundlename: string = "resources", asset: typeof Asset): Promise<boolean>
|
||||
|
||||
/** 按 uuid 释放资源 */
|
||||
public static releaseUUID(uuid: string): void
|
||||
|
||||
/** 释放所有加载的资源 */
|
||||
public static releaseAll(): void
|
||||
|
||||
/**
|
||||
* 按资源加载批次释放资源
|
||||
* @param batchName 资源加载批次名 对应 AssetLoader 实例化时传入的 name
|
||||
*/
|
||||
public static releaseBatchAssets(batchName: string): void;
|
||||
```
|
||||
|
@@ -1,141 +0,0 @@
|
||||
## 行为树
|
||||
|
||||
> 行为树是一种强大的 AI 决策系统,用于实现复杂的游戏 AI 行为。
|
||||
|
||||
#### 基本概念
|
||||
|
||||
1. 节点状态
|
||||
```typescript
|
||||
enum Status {
|
||||
SUCCESS, // 成功
|
||||
FAILURE, // 失败
|
||||
RUNNING // 运行中
|
||||
}
|
||||
```
|
||||
|
||||
2. 节点类型
|
||||
- **动作节点 (Action)**:执行具体行为的叶子节点
|
||||
- **组合节点 (Composite)**:控制子节点执行顺序的节点
|
||||
- **条件节点 (Condition)**:判断条件的节点
|
||||
- **装饰节点 (Decorator)**:修饰其他节点行为的节点
|
||||
|
||||
#### 使用示例
|
||||
|
||||
```typescript
|
||||
import {
|
||||
BehaviorTree,
|
||||
Sequence,
|
||||
Selector,
|
||||
Parallel,
|
||||
Success,
|
||||
Failure,
|
||||
WaitTime,
|
||||
Agent,
|
||||
Blackboard
|
||||
} from 'kunpocc';
|
||||
|
||||
// 1. 创建行为树
|
||||
const tree = new BehaviorTree(
|
||||
new Sequence( // 顺序节点:按顺序执行所有子节点
|
||||
new WaitTime(2), // 等待2秒
|
||||
new Selector( // 选择节点:选择一个可执行的子节点
|
||||
new Success(() => {
|
||||
console.log("执行成功动作");
|
||||
}),
|
||||
new Failure(() => {
|
||||
console.log("执行失败动作");
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// 2. 创建代理和黑板
|
||||
const agent = new Agent(); // AI代理
|
||||
const blackboard = new Blackboard(); // 共享数据黑板
|
||||
|
||||
// 3. 执行行为树
|
||||
tree.tick(agent, blackboard);
|
||||
```
|
||||
|
||||
#### 常用节点
|
||||
|
||||
1. 组合节点
|
||||
|
||||
```typescript
|
||||
// 顺序节点:按顺序执行所有子节点,直到遇到失败或运行中的节点
|
||||
new Sequence(childNode1, childNode2, childNode3);
|
||||
|
||||
// 选择节点:选择第一个成功或运行中的子节点
|
||||
new Selector(childNode1, childNode2, childNode3);
|
||||
|
||||
// 并行节点:同时执行所有子节点
|
||||
new Parallel(childNode1, childNode2, childNode3);
|
||||
|
||||
// 记忆顺序节点:记住上次执行的位置
|
||||
new MemSequence(childNode1, childNode2, childNode3);
|
||||
|
||||
// 记忆选择节点:记住上次执行的位置
|
||||
new MemSelector(childNode1, childNode2, childNode3);
|
||||
|
||||
// 随机选择节点:随机选择一个子节点执行
|
||||
new RandomSelector(childNode1, childNode2, childNode3);
|
||||
```
|
||||
|
||||
2. 动作节点
|
||||
|
||||
```typescript
|
||||
// 成功节点
|
||||
new Success(() => {
|
||||
// 执行动作
|
||||
});
|
||||
|
||||
// 失败节点
|
||||
new Failure(() => {
|
||||
// 执行动作
|
||||
});
|
||||
|
||||
// 运行中节点
|
||||
new Running(() => {
|
||||
// 持续执行的动作
|
||||
});
|
||||
|
||||
// 等待节点
|
||||
new WaitTime(2); // 等待2秒
|
||||
new WaitTicks(5); // 等待5个tick
|
||||
```
|
||||
|
||||
3. 使用黑板共享数据
|
||||
|
||||
```typescript
|
||||
// 在节点中使用黑板
|
||||
class CustomAction extends Action {
|
||||
tick(ticker: Ticker): Status {
|
||||
// 获取数据
|
||||
const data = ticker.blackboard.get("key");
|
||||
|
||||
// 设置数据
|
||||
ticker.blackboard.set("key", "value");
|
||||
|
||||
return Status.SUCCESS;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 注意事项
|
||||
|
||||
1. 节点状态说明:
|
||||
- `SUCCESS`:节点执行成功
|
||||
- `FAILURE`:节点执行失败
|
||||
- `RUNNING`:节点正在执行中
|
||||
2. 组合节点特性:
|
||||
- `Sequence`:所有子节点返回 SUCCESS 才返回 SUCCESS
|
||||
- `Selector`:任一子节点返回 SUCCESS 就返回 SUCCESS
|
||||
- `Parallel`:并行执行所有子节点
|
||||
- `MemSequence/MemSelector`:会记住上次执行位置
|
||||
3. 性能优化:
|
||||
- 使用黑板共享数据,避免重复计算
|
||||
- 合理使用记忆节点,减少重复执行
|
||||
- 控制行为树的深度,避免过于复杂
|
||||
|
||||
|
524
docs/EC.md
524
docs/EC.md
@@ -1,524 +0,0 @@
|
||||
## 实体组件模块
|
||||
> 实体组件系统是一种用于游戏开发的架构模式,它将游戏对象(实体)的数据(组件)和行为分离。
|
||||
|
||||
### 特点
|
||||
* 不同实体上的组件更新顺序管理(`只根据注册的组件更新顺序更新,跟实体无关`)
|
||||
* 灵活的EC装饰器 (配合插件 `kunpo-ec` 使用,配置实体组件信息,一键导出)
|
||||
* 支持多世界(多战斗场景,互不影响)
|
||||
* 区分数据组件和逻辑组件,只更新逻辑组件
|
||||
|
||||
### 插件链接
|
||||
|
||||
* **kunpo-ec**: [https://store.cocos.com/app/detail/7311](https://store.cocos.com/app/detail/7311)
|
||||
|
||||
### 使用
|
||||
|
||||
#### *creator插件`kunpo-ec`*
|
||||
> `kunpo-cc`可以方便创建、配置、导出实体,操作界面如下图:
|
||||
|
||||

|
||||
|
||||
#### *使用*
|
||||
|
||||
1. 组件类型声明
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* @Author: gongxh
|
||||
* @Date: 2025-01-23
|
||||
* @Description: 组件枚举
|
||||
*/
|
||||
|
||||
import { cc } from "../header";
|
||||
|
||||
/** 数据组件类型 */
|
||||
enum DataComponentType {
|
||||
Health,
|
||||
Transform,
|
||||
RootNode,
|
||||
LimitMove,
|
||||
/** 渲染组件 (多个) */
|
||||
Render,
|
||||
}
|
||||
|
||||
/** 逻辑组件类型 (组件更新数据从上到下) */
|
||||
export enum SystemComponentType {
|
||||
Move = 100000,
|
||||
ScreenRebound,
|
||||
|
||||
/** 位置更新系统 */
|
||||
PositionUpdateSystem = 120000,
|
||||
}
|
||||
|
||||
export const ComponentType = {
|
||||
...DataComponentType,
|
||||
...SystemComponentType
|
||||
};
|
||||
export type ComponentType = DataComponentType | SystemComponentType;
|
||||
|
||||
/** 自定义组件更新顺序列表 */
|
||||
export const componentUpdateOrderList = cc.Enum.getList(cc.Enum(SystemComponentType)).map(item => item.value).sort((a, b) => a - b);
|
||||
```
|
||||
|
||||
2. 编写组件脚本
|
||||
|
||||
```typescript
|
||||
import { AnimationClip, Asset, AudioClip, Color, Enum, JsonAsset, ParticleAsset, Prefab, Size, Skeleton, SpriteFrame, Vec2, Vec3 } from "cc";
|
||||
import { _ecdecorator, Component } from "kunpocc";
|
||||
import { ComponentType } from "../../ComponentTypes";
|
||||
const { ecclass, ecprop } = _ecdecorator;
|
||||
|
||||
enum HealthType {
|
||||
HP = 1,
|
||||
Max = 2,
|
||||
Current = 3
|
||||
}
|
||||
|
||||
// 注册组件 (必须)
|
||||
@ecclass("Health", ComponentType.Health, { describe: "血量组件" })
|
||||
export class Health extends Component {
|
||||
// 注册组件属性 (可选: 使用kunpo-ec插件则必须注册)
|
||||
@ecprop({ type: "entity", defaultValue: "", displayName: "实体", tips: "实体" })
|
||||
private testentity: string = "";
|
||||
|
||||
@ecprop({ type: "array", format: "entity", displayName: "实体数组", tips: "实体数组" })
|
||||
private testentityarray: string[] = [];
|
||||
|
||||
@ecprop({ type: 'int', defaultValue: 0, displayName: "血量", tips: "当前血量提示" })
|
||||
private hp: number = 0;
|
||||
|
||||
@ecprop({ type: 'float', defaultValue: 0, displayName: "最大血量", tips: "最大血量提示" })
|
||||
private maxHp: number = 0;
|
||||
|
||||
@ecprop({ type: 'string', defaultValue: "", displayName: "字符串", tips: "字符串提示" })
|
||||
private string: string = "";
|
||||
|
||||
@ecprop({ type: 'boolean', defaultValue: false, displayName: "布尔值", tips: "布尔值提示" })
|
||||
private bool: boolean = true;
|
||||
|
||||
@ecprop({ type: "enum", format: Enum(HealthType), defaultValue: HealthType.Current, displayName: "枚举", tips: "枚举提示" })
|
||||
private hpeunm: HealthType = HealthType.Current;
|
||||
|
||||
@ecprop({ type: "spriteframe", displayName: "精灵帧" })
|
||||
private spriteFrame: SpriteFrame;
|
||||
|
||||
@ecprop({ type: "asset", displayName: "资源" })
|
||||
private asset: Asset;
|
||||
|
||||
@ecprop({ type: "prefab", displayName: "预制体" })
|
||||
private prefab: Prefab;
|
||||
|
||||
@ecprop({ type: "skeleton", displayName: "骨骼动画" })
|
||||
private skeleton: Skeleton;
|
||||
|
||||
@ecprop({ type: "particle", displayName: "粒子" })
|
||||
private particle: ParticleAsset;
|
||||
|
||||
@ecprop({ type: "animation", displayName: "动画" })
|
||||
private animation: AnimationClip;
|
||||
|
||||
@ecprop({ type: "audio", displayName: "音频" })
|
||||
private audio: AudioClip;
|
||||
|
||||
@ecprop({ type: "jsonAsset", displayName: "json资源" })
|
||||
private jsonAsset: JsonAsset;
|
||||
|
||||
@ecprop({
|
||||
type: "object", format: {
|
||||
hp1: {
|
||||
type: "object",
|
||||
format: {
|
||||
hp: "int",
|
||||
max: "int"
|
||||
}
|
||||
},
|
||||
hp2: {
|
||||
type: "object",
|
||||
format: {
|
||||
hp: "int",
|
||||
max: "int"
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
private obj: { hp1: { hp: number, max: number }, hp2: { hp: number, max: number } };
|
||||
|
||||
@ecprop({
|
||||
type: "array", format: "int",
|
||||
})
|
||||
private arr: number[];
|
||||
|
||||
@ecprop({
|
||||
type: "array", format: { type: "object", format: { hp: "int", max: "int" } }
|
||||
})
|
||||
private arrobj: { hp: number, max: number }[];
|
||||
|
||||
@ecprop({ type: "vec2", displayName: "向量2" })
|
||||
private vec2: Vec2;
|
||||
|
||||
@ecprop({ type: "vec3", displayName: "向量3" })
|
||||
private vec3: Vec3;
|
||||
|
||||
@ecprop({ type: "color", defaultValue: Color.RED, displayName: "颜色" })
|
||||
private color: Color;
|
||||
|
||||
@ecprop({ type: "size", displayName: "尺寸" })
|
||||
private size: Size;
|
||||
|
||||
protected onAdd(): void {
|
||||
// 设置组件是否更新,只有需要更新的组件才设置
|
||||
this.needUpdate = true;
|
||||
}
|
||||
|
||||
protected onEnter(): void {
|
||||
// 可在此获取同实体上的其他组件
|
||||
let transform = this.getComponent(ComponentType.Transform);
|
||||
/** 获取单例组件 */
|
||||
let signleton = this.entity.entityManager.getSingleton(ComponentType.XXXX);
|
||||
}
|
||||
|
||||
protected onRemove(): void {
|
||||
// 清理组件数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. 创建ec世界,并设置更新
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* @Author: Gongxh
|
||||
* @Date: 2025-01-16
|
||||
* @Description: 战斗界面
|
||||
*/
|
||||
|
||||
import { ECManager } from "kunpocc";
|
||||
import { componentUpdateOrderList } from "../../ec/ComponentTypes";
|
||||
import { cc, fgui, kunpo } from "../../header";
|
||||
const { uiclass, uiprop, uiclick } = kunpo._uidecorator;
|
||||
|
||||
@uiclass("Window", "Game", "GameWindow")
|
||||
export class GameWindow extends kunpo.Window {
|
||||
@uiprop container: fgui.GComponent;
|
||||
public onInit() {
|
||||
console.log("GameWindow onInit");
|
||||
this.adapterType = kunpo.AdapterType.Full;
|
||||
this.type = kunpo.WindowType.CloseAll;
|
||||
this.bgAlpha = 0;
|
||||
}
|
||||
|
||||
protected onShow() {
|
||||
console.log("GameWindow onShow");
|
||||
/** 创建一个ec世界的节点 */
|
||||
let node = new cc.Node();
|
||||
this.container.node.addChild(node);
|
||||
|
||||
/**
|
||||
* 创建一个ec世界
|
||||
* 参数1: 世界名称
|
||||
* 参数2: 世界节点
|
||||
* 参数3: 组件更新顺序列表
|
||||
* 参数4: 实体池的最大缓存数量,多余的不会被缓存,根据需要调整
|
||||
* 参数5: 预创建的实体数量,根据需要调整
|
||||
*/
|
||||
kunpo.log("需要更新的组件", componentUpdateOrderList);
|
||||
ECManager.createECWorld("world", node, componentUpdateOrderList, 100, 10);
|
||||
}
|
||||
|
||||
protected onClose() {
|
||||
/** 退出游戏时 销毁ec世界 */
|
||||
ECManager.destroyECWorld("world");
|
||||
}
|
||||
|
||||
@uiclick
|
||||
private onBack(): void {
|
||||
kunpo.WindowManager.showWindow("HomeWindow");
|
||||
}
|
||||
|
||||
@uiclick
|
||||
private onCreateEntity(): void {
|
||||
/** 创建一个实体 */
|
||||
ECManager.createEntity("world", "entity1");
|
||||
}
|
||||
|
||||
protected onUpdate(dt: number): void {
|
||||
/** 更新ec世界 */
|
||||
ECManager.getECWorld("world").update(dt);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 重点接口
|
||||
|
||||
注:详细说明查看声明文件 `kunpocc.d.ts`
|
||||
|
||||
1. 总管理器 `ECManager`
|
||||
|
||||
```typescript
|
||||
/**注册所有组件 如果GameEntry因分包导致,组件的代码注册晚于CocosEntry的onInit函数, 则需要在合适的时机手动调用此方法*/
|
||||
public static registerComponents(): void
|
||||
|
||||
/**
|
||||
* 创建EC世界 创建EC世界前必须先注册组件
|
||||
* @param {string} worldName 名称
|
||||
* @param {Node} node 世界节点
|
||||
* @param {number[]} componentUpdateOrderList 组件更新顺序列表 (只传需要更新的组件列表)
|
||||
* @param {number} [maxCapacityInPool=128] 实体池最大容量,多余的实体不会缓存
|
||||
* @param {number} [preloadEntityCount=32] 预加载Entity数量
|
||||
*/
|
||||
public static createECWorld(worldName: string, node: Node, componentUpdateOrderList: number[], maxCapacityInPool = 128, preloadEntityCount = 32): EntityManager
|
||||
|
||||
/** 获取EC世界 */
|
||||
public static getECWorld(worldName: string): EntityManager
|
||||
|
||||
/** 获取EC世界节点 */
|
||||
public static getECWorldNode(worldName: string): Node
|
||||
|
||||
/** 销毁EC世界 */
|
||||
public static destroyECWorld(worldName: string): void
|
||||
|
||||
/**
|
||||
* 注册配置表中的实体信息
|
||||
* 如果在GameEntry中配置了ecConfig,则此方法会自动调用
|
||||
* @param config 实体配置信息,格式为 {实体名: {组件名: 组件数据}}
|
||||
*/
|
||||
public static registerEntityConfig(config: { [entityName: string]: IEntityConfig }): void
|
||||
|
||||
/**
|
||||
* 添加实体信息 (如果已经存在, 则数据组合)
|
||||
* 如果存在编辑器编辑不了的数据 用来给编辑器导出的实体信息 添加扩展数据
|
||||
* @param name 实体名
|
||||
* @param info 实体信息
|
||||
*/
|
||||
public static addEntityInfo(name: string, info: IEntityConfig): void
|
||||
|
||||
/** 获取实体配置信息 */
|
||||
public static getEntityInfo(name: string): Record<string, any>
|
||||
|
||||
/**
|
||||
* 创建实体
|
||||
* @param worldName 实体管理器名称
|
||||
* @param name 实体名字
|
||||
* @returns {kunpo.Entity} 实体
|
||||
*/
|
||||
public static createEntity(worldName: string, name: string): Entity
|
||||
|
||||
/**
|
||||
* 销毁实体
|
||||
* @param worldName 世界名称
|
||||
* @param entity 实体
|
||||
*/
|
||||
public static destroyEntity(worldName: string, entity: Entity): void
|
||||
|
||||
/**
|
||||
* 通过实体ID销毁实体
|
||||
* @param worldName 世界名称
|
||||
* @param entityId 实体ID
|
||||
*/
|
||||
public static destroyEntityById(worldName: string, entityId: number): void
|
||||
```
|
||||
|
||||
2. 实体管理器 (创建的world)`EntityManager `
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* 通过实体ID获取实体
|
||||
* @param {EntityId} entityId 实体Id
|
||||
* @returns {(Entity | null)} 实体
|
||||
*/
|
||||
public getEntity(entityId: EntityId): Entity | null
|
||||
|
||||
/**
|
||||
* 获取指定标签的实体
|
||||
* @param {number} tag 标签
|
||||
* @returns {Entity[]} 返回的实体池
|
||||
*/
|
||||
public getEntitiesByTag(tag: number): Entity[]
|
||||
|
||||
/**
|
||||
* 根据实体ID判断实体是否存在
|
||||
* @param {EntityId} entityId 实体Id
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public exists(entityId: EntityId): boolean
|
||||
|
||||
/** 添加单例组件 */
|
||||
public addSingleton(component: Component): void
|
||||
|
||||
/** 获取单例组件 */
|
||||
public getSingleton<T extends Component>(componentType: number): T
|
||||
|
||||
/** 删除单例组件 */
|
||||
public removeSingleton(componentType: number): void
|
||||
|
||||
/** 是否存在对应的单例组件 */
|
||||
public hasSingleton(componentType: number): boolean
|
||||
|
||||
/** 激活单例组件 */
|
||||
public activeSingleton(): void
|
||||
|
||||
|
||||
/** 更新 需要外部调用 */
|
||||
public update(dt: number): void
|
||||
```
|
||||
|
||||
3. 实体 `Entity`
|
||||
|
||||
```typescript
|
||||
/** 实体名称 */
|
||||
public name: string;
|
||||
|
||||
/** 实体ID */
|
||||
public id: EntityId;
|
||||
|
||||
/** 实体标识 */
|
||||
public tags: Set<number>;
|
||||
|
||||
/** 实体状态 */
|
||||
public states: Map<number, number>;
|
||||
|
||||
/** 是否被激活 (添加到实体管理器时激活) */
|
||||
public active: boolean = false;
|
||||
|
||||
/** 所属实体管理器 (实体创建后直接赋值) */
|
||||
public entityManager: EntityManager;
|
||||
|
||||
/** 所有组件 */
|
||||
public readonly components: Map<number, Component> = new Map();
|
||||
|
||||
/** 添加标签 标签除了表示Entity,还可以通过EntityManager获取指定标签的Entity */
|
||||
public addTag(...tag: number[]): void
|
||||
|
||||
/** 删除标签 */
|
||||
public removeTag(tag: number): void
|
||||
|
||||
/** 是否包含标签 */
|
||||
public hasTag(...tag: number[]): boolean
|
||||
|
||||
/** 获取组件 */
|
||||
public getComponent<T extends Component>(componentType: number): T
|
||||
|
||||
/** 添加组件 */
|
||||
public addComponent(component: Component): void
|
||||
|
||||
/** 删除组件 */
|
||||
public removeComponent(componentType: number): void
|
||||
|
||||
/** 删除所有组件 */
|
||||
public removeAllComponents(): void
|
||||
|
||||
/**
|
||||
* 是否包含组件
|
||||
* @param {number} componentType 组件类型
|
||||
*/
|
||||
public hasComponent(componentType: number): boolean
|
||||
|
||||
/** 销毁自己 */
|
||||
public destroy(): void {
|
||||
this.entityManager.destroyEntityById(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加监听
|
||||
* @param eventName 监听的消息名
|
||||
* @param callback 回调
|
||||
* @param entityId 实体ID
|
||||
* @param once 是否单次监听
|
||||
*/
|
||||
public addEvent(eventName: string, callback: (...args: any[]) => void, once: boolean = false): void
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param eventName 消息名
|
||||
* @param entityId 实体ID
|
||||
* @param args 发送参数
|
||||
*/
|
||||
public sendListener(eventName: string, ...args: any[]): void
|
||||
|
||||
/** 删除监听 */
|
||||
public removeListener(eventName: string, callback?: (...args: any[]) => void): void
|
||||
|
||||
/**
|
||||
* 添加状态
|
||||
* 状态采用计数方式,对状态处理时需要保证addState和removeState成对存在
|
||||
* @param {number} state 状态类型
|
||||
*/
|
||||
public addState(state: number): void
|
||||
|
||||
/**
|
||||
* 删除状态
|
||||
* @param {number} state 状态类型
|
||||
* @returns {boolean} 如果计数为0或状态不存在,则返回true
|
||||
*/
|
||||
public removeState(state: number): boolean
|
||||
|
||||
/** 是否包含指定状态 */
|
||||
public hasState(state: number): boolean
|
||||
|
||||
/** 清除状态 */
|
||||
public clearState(state: number): void
|
||||
|
||||
/** 清除所有状态 */
|
||||
public clearAllStates(): void
|
||||
```
|
||||
|
||||
|
||||
|
||||
4. 组件 `Component`
|
||||
|
||||
```typescript
|
||||
/** 组件名 */
|
||||
public name: string;
|
||||
|
||||
/** 组件类型 */
|
||||
public type: number;
|
||||
|
||||
/** 是否需要更新 */
|
||||
public needUpdate: boolean;
|
||||
|
||||
/** 所属实体 */
|
||||
public entity: Entity;
|
||||
|
||||
/** 所属组件管理器 */
|
||||
public componentManager: ComponentManager;
|
||||
|
||||
/**
|
||||
* 获取同实体上的组件
|
||||
* @param {number} componentType 组件类型
|
||||
*/
|
||||
public getComponent<T extends Component>(componentType: number): T
|
||||
|
||||
/** 删除自己 */
|
||||
public destroySelf(): void
|
||||
|
||||
/**
|
||||
* 生命周期函数
|
||||
* 被添加到实体 对应onDestroy
|
||||
*/
|
||||
protected onAdd(): void
|
||||
|
||||
/**
|
||||
* 生命周期函数
|
||||
* 组件被销毁 对应onAdd
|
||||
*/
|
||||
protected onDestroy(): void
|
||||
|
||||
/**
|
||||
* 生命周期函数
|
||||
* 可在此方法获取实体其他组件
|
||||
*/
|
||||
protected abstract onEnter(): void;
|
||||
|
||||
/**
|
||||
* 生命周期函数
|
||||
* 从实体中删除前执行的函数 在此函数中清理初始化的数据
|
||||
*/
|
||||
protected abstract onRemove(): void;
|
||||
|
||||
/**
|
||||
* 更新函数
|
||||
*/
|
||||
protected onUpdate(dt: number): void
|
||||
```
|
||||
|
||||
|
132
docs/QuadTree.md
132
docs/QuadTree.md
@@ -1,132 +0,0 @@
|
||||
## 四叉树
|
||||
> 四叉树是一种通过空间划分来进行高效碰撞查询的数据结构。
|
||||
|
||||
#### 基本概念
|
||||
|
||||
1. 形状类型
|
||||
|
||||
```typescript
|
||||
import { QuadTree, Box, Circle, Polygon } from 'kunpocc';
|
||||
|
||||
// 1. 矩形
|
||||
const box = new Box(x, y, width, height, tag);
|
||||
|
||||
// 2. 圆形
|
||||
const circle = new Circle(x, y, radius, tag);
|
||||
|
||||
// 3. 多边形
|
||||
const points = [v2(x1, y1), v2(x2, y2), v2(x3, y3)];
|
||||
const polygon = new Polygon(points, tag);
|
||||
```
|
||||
|
||||
2. 配置参数
|
||||
|
||||
```typescript
|
||||
// 四叉树配置
|
||||
const QTConfig = {
|
||||
MAX_SHAPES: 12, // 每个节点最大形状数量
|
||||
MAX_LEVELS: 5, // 最大深度
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### 使用示例
|
||||
|
||||
1. 创建和初始化
|
||||
|
||||
```typescript
|
||||
import { QuadTree, Box, rect } from 'kunpocc';
|
||||
|
||||
// 创建四叉树(参数:区域范围,层级,绘制组件)
|
||||
const bounds = rect(0, 0, 800, 600); // x, y, width, height
|
||||
const quadTree = new QuadTree(bounds);
|
||||
|
||||
// 添加形状
|
||||
const player = new Box(100, 100, 50, 50, 1); // 玩家碰撞体,tag=1
|
||||
const enemy = new Circle(200, 200, 25, 2); // 敌人碰撞体,tag=2
|
||||
quadTree.insert(player);
|
||||
quadTree.insert(enemy);
|
||||
```
|
||||
|
||||
2. 碰撞检测
|
||||
|
||||
```typescript
|
||||
// 检测指定形状与特定标签的碰撞
|
||||
const collisions = quadTree.collide(player, 2); // 检测玩家与 tag=2 的形状碰撞
|
||||
if (collisions.length > 0) {
|
||||
console.log('发生碰撞!');
|
||||
for (const target of collisions) {
|
||||
// 处理碰撞逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. 动态更新
|
||||
|
||||
```typescript
|
||||
// 在游戏循环中更新四叉树
|
||||
function update() {
|
||||
// 更新形状位置
|
||||
player.position = v2(newX, newY);
|
||||
enemy.position = v2(newX, newY);
|
||||
|
||||
// 更新四叉树
|
||||
quadTree.update();
|
||||
|
||||
// 检测碰撞
|
||||
const collisions = quadTree.collide(player, 2);
|
||||
}
|
||||
```
|
||||
|
||||
4. 清理
|
||||
|
||||
```typescript
|
||||
// 清理四叉树
|
||||
quadTree.clear();
|
||||
```
|
||||
|
||||
|
||||
#### 形状操作
|
||||
|
||||
1. 位置和缩放
|
||||
|
||||
```typescript
|
||||
// 设置位置
|
||||
shape.position = v2(x, y);
|
||||
|
||||
// 设置缩放
|
||||
shape.scale = 1.5;
|
||||
|
||||
// 获取包围盒
|
||||
const boundingBox = shape.getBoundingBox();
|
||||
```
|
||||
|
||||
2. 特定形状操作
|
||||
|
||||
```typescript
|
||||
// 矩形重置
|
||||
box.resetPoints(x, y, width, height);
|
||||
|
||||
// 圆形半径
|
||||
circle.radius = newRadius;
|
||||
|
||||
// 多边形顶点
|
||||
polygon.points = newPoints;
|
||||
```
|
||||
|
||||
|
||||
#### 性能优化建议
|
||||
|
||||
1. 合理设置配置参数:
|
||||
- `MAX_SHAPES`:较小的值会导致更频繁的分裂,较大的值会降低查询效率
|
||||
- `MAX_LEVELS`:控制树的最大深度,防止过度分割
|
||||
|
||||
2. 碰撞检测优化:
|
||||
- 使用合适的标签系统,只检测需要的碰撞
|
||||
- 根据游戏需求选择合适的形状(圆形计算最快)
|
||||
- 避免使用过于复杂的多边形
|
||||
|
||||
3. 更新策略:
|
||||
- 仅在必要时更新四叉树
|
||||
- 对于静态物体,可以使用单独的四叉树
|
||||
- 动态物体频繁更新时,考虑使用更大的边界范围
|
Reference in New Issue
Block a user