mirror of
https://github.com/Gongxh0901/kunpolibrary
synced 2025-04-23 20:08:41 +00:00
1633 lines
43 KiB
Markdown
1633 lines
43 KiB
Markdown
# KunpoLib
|
||
|
||
基于 Cocos Creator 3.0+ 的一套游戏框架,提供了一系列实用模块,帮助开发者快速构建高质量的游戏项目。
|
||
|
||
项目持续优化中,敬请期待~~
|
||
|
||
## 目录
|
||
- [模块](#模块)
|
||
- [安装kunpocc](#安装kunpocc)
|
||
- [项目基础配置](#项目基础配置)
|
||
- [使用方法](#使用方法)
|
||
- [一、UI 系统](#一ui-系统)
|
||
- [UI 装饰器使用](#ui-装饰器使用)
|
||
- [创建窗口](#创建窗口)
|
||
- [二、实体组件系统(EC)](#二实体组件系统ec)
|
||
- [creator插件`kunpo-ec`](#creator插件kunpo-ec)
|
||
- [重点接口说明](#重点接口说明)
|
||
- [使用](#使用)
|
||
- [三、网络模块](#三-网络模块)
|
||
- [HTTP 请求](#http-请求)
|
||
- [请求方法](#请求方法)
|
||
- [参数说明](#参数说明)
|
||
- [响应处理](#响应处理)
|
||
- [四、四叉树碰撞检测](#四四叉树碰撞检测)
|
||
- [基本概念](#基本概念)
|
||
- [使用示例](#使用示例)
|
||
- [形状操作](#形状操作)
|
||
- [性能优化建议](#性能优化建议)
|
||
- [五、行为树系统](#五行为树系统)
|
||
- [行为树基本概念](#行为树基本概念)
|
||
- [行为树使用示例](#行为树使用示例)
|
||
- [常用节点](#常用节点)
|
||
- [注意事项](#注意事项)
|
||
- [六、资源加载工具](#六资源加载工具)
|
||
- [资源加载器](#资源加载器)
|
||
- [资源池](#资源池)
|
||
- [七、条件显示节点](#七条件显示节点用来处理游戏中的提示红点信息)
|
||
- [定义条件](#定义条件)
|
||
- [节点关联条件](#节点关联条件)
|
||
- [八、全局事件系统](#八-全局事件系统)
|
||
- [九、全局计时器](#九全局计时器)
|
||
- [十、平台相关](#十平台相关)
|
||
- [平台类型](#平台类型)
|
||
- [平台判断](#平台判断)
|
||
- [使用示例](#使用示例-2)
|
||
- [十一、屏幕](#十一屏幕)
|
||
- [十二、工具类](#十二工具类)
|
||
- [数学工具 (MathTool)](#数学工具-mathtool)
|
||
- [MD5 加密](#md5-加密)
|
||
|
||
## 模块
|
||
|
||
- **UI 系统 (基于 FairyGUI)**
|
||
|
||
* 灵活的 UI 装饰器(配合插件 `kunpo-fgui` 使用,一键导出界面配置,省时省力省代码)
|
||
|
||
* 控制窗口之间的相互关系(eg: 打开界面时,是隐藏/关闭前一个界面,还是隐藏/关闭所有界面)
|
||
|
||
* 多窗口组管理
|
||
|
||
* 顶部显示金币钻石的资源栏(header),一次实现,多界面复用,
|
||
|
||
* 支持不同界面使用不同 header
|
||
|
||
- **EC 框架**
|
||
|
||
* 不同实体上的组件更新顺序管理(`只根据注册的组件更新顺序更新,跟实体无关`)
|
||
|
||
- 灵活的EC装饰器 (配合插件 `kunpo-ec` 使用,配置实体组件信息,一键导出)
|
||
- 支持多世界(多战斗场景,互不影响)
|
||
- 区分数据组件和逻辑组件,只更新逻辑组件
|
||
|
||
- **网络模块 (Http)**
|
||
- HTTP 请求管理
|
||
- 完整的请求响应接口
|
||
|
||
- **四叉树(碰撞查询)**
|
||
|
||
* 矩形碰撞
|
||
* 圆形碰撞
|
||
* 多边形碰撞
|
||
|
||
- **行为树系统**
|
||
- 用来实现复杂的怪物行为
|
||
|
||
- **资源管理**
|
||
* 资源加载后放入资源池
|
||
* 资源池 可通过路径或者uuid获取资源
|
||
* 只适合手动管理资源,单无论加载多少次,卸载一次后删除
|
||
|
||
- **条件显示节点系统 (用来处理游戏中的提示红点信息)**
|
||
|
||
* 主要是解耦用,条件单独实现,节点关联单条件或者多个条件
|
||
|
||
- **全局事件系统 `GlobalEvent`**
|
||
|
||
- **全局计时器 `GlobalTimer`**
|
||
|
||
- **平台相关 `Platform`**
|
||
|
||
- **屏幕尺寸 `Screen`**
|
||
|
||
- **数据结构**
|
||
|
||
- 二叉堆(`BinaryHeap` 最大、最小堆)
|
||
- 单向(`LinkedList`)、双向链表 (`DoublyLinkedList`)
|
||
- 栈(`Stack`)
|
||
|
||
- **适配相关 `Adapter` (不需要关心) **
|
||
|
||
## 安装kunpocc
|
||
|
||
```bash
|
||
npm install kunpocc
|
||
```
|
||
|
||
## 项目基础配置
|
||
|
||
1. 新建项目,创建首场景文件
|
||
|
||
2. 编写入口脚本
|
||
|
||
```typescript
|
||
import { _decorator } from "cc";
|
||
/** 引入kunpocc入口 */
|
||
import { CocosEntry, log } from "kunpocc";
|
||
|
||
const { ccclass, property, menu } = _decorator;
|
||
@ccclass("GameEntry")
|
||
@menu("kunpo/GameEntry")
|
||
export class GameEntry extends CocosEntry {
|
||
@property(cc.Node)
|
||
private root: cc.Node = null;
|
||
onInit(): void {
|
||
log("GameEntry onInit");
|
||
}
|
||
}
|
||
```
|
||
|
||
3. 创建入口节点`GameEntry`,创建UI模块节点 `UI` 、UI容器节点`window`, 并关联对应的脚本
|
||
|
||

|
||
|
||
4. 配置完毕
|
||
|
||
|
||
|
||
## 使用方法
|
||
|
||
### 一、UI 系统
|
||
|
||
> 注:UI制作需要使用 FairyGUI,[FairyGUI官方文档](https://www.fairygui.com/docs/editor)
|
||
|
||
> 
|
||
|
||
#### *UI 装饰器使用*
|
||
|
||
> 注:只有使用了装饰器的内容才能在 `kunpo-fgui` 插件中识别,`kunpo-fgui`插件操作界面如下图
|
||
|
||
> 
|
||
|
||
|
||
|
||
1. 窗口装饰器
|
||
|
||
```typescript
|
||
import { Window, _uidecorator } from 'kunpocc';
|
||
const { uiclass, uiprop, uiclick } = _uidecorator;
|
||
|
||
/**
|
||
* 窗口装饰器
|
||
* @param 参数1: 窗口容器节点名字
|
||
* @param 参数2: FairyGUI中的UI包名
|
||
* @param 参数3: FairyGUI中的组件名 必须和 class 类同名 这里是 MyWindow
|
||
*/
|
||
@uiclass("Window", "UI包名", "MyWindow")
|
||
export class MyWindow extends Window {
|
||
// ... 窗口实现
|
||
}
|
||
```
|
||
|
||
2. 窗口 Header 装饰器
|
||
|
||
```typescript
|
||
import { WindowHeader, _uidecorator } from 'kunpocc';
|
||
const { uiheader } = _uidecorator;
|
||
|
||
/**
|
||
* 窗口顶部资源栏装饰器
|
||
* @param 参数1: FairyGUI中的UI包名
|
||
* @param 参数2: FairyGUI中的组件名 必须和 class 类同名 这里是 MyWindowHeader
|
||
*/
|
||
@uiheader("UI包名", "WindowHeader")
|
||
export class MyWindowHeader extends WindowHeader {
|
||
// ... Header 实现
|
||
}
|
||
```
|
||
|
||
3. UI组件装饰器
|
||
|
||
```typescript
|
||
import { _uidecorator } from 'kunpocc';
|
||
const { uicom, uiprop, uiclick } = _uidecorator;
|
||
|
||
/**
|
||
* UI组件类装饰器
|
||
* @param 参数1: FairyGUI中的UI包名
|
||
* @param 参数2: FairyGUI中的组件名 必须和 class 类同名 这里是 MyComponent
|
||
*/
|
||
@uicom("Home", "MyComponent")
|
||
export class MyComponent {
|
||
// ... 组件实现
|
||
}
|
||
```
|
||
|
||
4. UI属性装饰器
|
||
|
||
```typescript
|
||
import { Window, _uidecorator } from 'kunpocc';
|
||
const { uiclass, uiprop, uiclick } = _uidecorator;
|
||
|
||
@uiclass("Window", "Home", "MyWindow")
|
||
export class MyWindow extends Window {
|
||
// FairyGUI 组件属性装饰器
|
||
@uiprop private btnConfirm: GButton; // 按钮组件
|
||
@uiprop private txtTitle: GTextField; // 文本组件
|
||
@uiprop private listItems: GList; // 列表组件
|
||
}
|
||
```
|
||
|
||
5. 点击事件装饰器
|
||
|
||
```typescript
|
||
import { Window, _uidecorator } from 'kunpocc';
|
||
const { uiclass, uiprop, uiclick } = _uidecorator;
|
||
|
||
@uiclass("Window", "Home", "MyWindow")
|
||
export class MyWindow extends Window {
|
||
// 点击事件装饰器
|
||
@uiclick
|
||
private onTouchEvent(event: cc.Event): void {
|
||
console.log('确认按钮被点击');
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
#### *创建窗口*
|
||
|
||
1. 创建窗口类
|
||
|
||
```typescript
|
||
/**
|
||
* 窗口名必须和FairyGUI中的组件同名
|
||
*/
|
||
import { Window, _uidecorator } from 'kunpocc';
|
||
const { uiclass, uiprop, uiclick } = _uidecorator;
|
||
|
||
@uiclass("Window", "UI包名", "MyWindow")
|
||
export class MyWindow extends Window {
|
||
protected onInit(): void {
|
||
// 初始化窗口
|
||
}
|
||
|
||
protected onShow(userdata?: any): void {
|
||
// 窗口显示时的逻辑
|
||
}
|
||
|
||
protected onClose(): void {
|
||
// 窗口关闭时的逻辑
|
||
}
|
||
}
|
||
```
|
||
|
||
2. 窗口管理
|
||
|
||
* 重要:显示窗口前必须确保窗口资源已加载 !!!
|
||
|
||
```typescript
|
||
// 显示窗口
|
||
WindowManager.showWindow("MyWindow", { /* 用户数据 */ });
|
||
|
||
// 关闭窗口
|
||
WindowManager.closeWindow("MyWindow");
|
||
|
||
// 获取窗口实例
|
||
const window = WindowManager.getWindow<MyWindow>("MyWindow");
|
||
|
||
// 获取当前最顶层窗口
|
||
const topWindow = WindowManager.getTopWindow();
|
||
|
||
// 检查窗口是否存在
|
||
const exists = WindowManager.hasWindow("MyWindow");
|
||
```
|
||
|
||
3. 窗口生命周期
|
||
- `onInit`: 窗口初始化时调用
|
||
- `onShow`: 窗口显示时调用
|
||
- `onClose`: 窗口关闭时调用
|
||
- `onHide`: 窗口隐藏时调用
|
||
- `onShowFromHide`: 窗口从隐藏状态恢复时调用
|
||
- `onCover`: 窗口被覆盖时调用
|
||
- `onRecover`: 窗口恢复时调用
|
||
- `onEmptyAreaClick`: 点击窗口空白区域时调用
|
||
|
||
|
||
|
||
### 二、实体组件系统(EC)
|
||
|
||
* 不使用creator官方的挂载脚本的方式,有以下几个原因
|
||
> 1. node挂脚本的方式效率低
|
||
> 1. 支持多世界,方便管理
|
||
> 3. 通过装饰器注册属性给creator插件 kunpo-ec 使用
|
||
> 4. 组件分数据组件和逻辑组件,只更新逻辑组件
|
||
|
||
* 实体组件系统是一种用于游戏开发的架构模式,它将游戏对象(实体)的数据(组件)和行为分离。
|
||
|
||
#### *creator插件`kunpo-ec`*
|
||
|
||
> `kunpo-cc`可以方便创建、配置、导出实体,操作界面如下图:
|
||
|
||

|
||
|
||
|
||
|
||
#### *重点接口说明*
|
||
|
||
注:详细说明查看声明文件 `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
|
||
```
|
||
|
||
|
||
|
||
#### *使用*
|
||
|
||
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. 编写组件脚本
|
||
|
||
* 在组件的 onAdd 方法中,设置组件是否更新,只有需要更新的组件才需要设置
|
||
|
||
```typescript
|
||
protected onAdd(): void {
|
||
this.needUpdate = true;
|
||
}
|
||
```
|
||
|
||
|
||
|
||
组件完整示例内容如下:
|
||
|
||
```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);
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
|
||
### 三、 网络模块
|
||
|
||
#### *HTTP 请求*
|
||
|
||
```typescript
|
||
import { HttpManager, IHttpEvent, HttpResponseType } from 'kunpocc';
|
||
|
||
// 1. 使用回调方式处理响应
|
||
const event: IHttpEvent = {
|
||
name: "login",
|
||
onComplete: (response) => {
|
||
console.log('请求成功:', response.data);
|
||
},
|
||
onError: (response) => {
|
||
console.log('请求失败:', response.error);
|
||
}
|
||
};
|
||
|
||
// POST 请求
|
||
HttpManager.post(
|
||
"https://api.example.com/login",
|
||
{ username: "test", password: "123456" },
|
||
"json", // 响应类型:'json' | 'text' | 'arraybuffer'
|
||
event,
|
||
["Content-Type", "application/json"], // 请求头
|
||
5 // 超时时间(秒)
|
||
);
|
||
|
||
// GET 请求
|
||
HttpManager.get(
|
||
"https://api.example.com/users",
|
||
{ id: 1 },
|
||
"json",
|
||
event
|
||
);
|
||
|
||
// 2. 使用全局事件方式处理响应
|
||
GlobalEvent.add(HttpManager.HttpEvent, (result, response) => {
|
||
if (result === "succeed") {
|
||
console.log('请求成功:', response.data);
|
||
} else {
|
||
console.log('请求失败:', response.error);
|
||
}
|
||
}, this);
|
||
|
||
// 发送请求(不传入 event 参数)
|
||
HttpManager.post("https://api.example.com/data", { /* data */ });
|
||
```
|
||
|
||
#### *请求方法*
|
||
- `post(url, data, responseType?, event?, headers?, timeout?)`
|
||
- `get(url, data, responseType?, event?, headers?, timeout?)`
|
||
- `put(url, data, responseType?, event?, headers?, timeout?)`
|
||
- `head(url, data, responseType?, event?, headers?, timeout?)`
|
||
|
||
#### *参数说明*
|
||
- `url`: 请求地址
|
||
- `data`: 请求数据
|
||
- `responseType`: 响应类型(可选,默认 'json')
|
||
- `'json'`: JSON 格式
|
||
- `'text'`: 文本格式
|
||
- `'arraybuffer'`: 二进制数据
|
||
- `event`: 请求事件回调(可选)
|
||
- `headers`: 请求头(可选)
|
||
- `timeout`: 超时时间,单位秒(可选,0表示不超时)
|
||
|
||
#### *响应处理*
|
||
1. 回调方式(通过 IHttpEvent):
|
||
```typescript
|
||
const event: IHttpEvent = {
|
||
name: "自定义名称",
|
||
data?: "自定义数据", // 可选
|
||
onComplete: (response) => {
|
||
// 成功回调
|
||
},
|
||
onError: (response) => {
|
||
// 失败回调
|
||
}
|
||
};
|
||
```
|
||
|
||
2. 全局事件方式:
|
||
```typescript
|
||
GlobalEvent.add(HttpManager.HttpEvent, (result, response) => {
|
||
// result: "succeed" | "fail"
|
||
// response: IHttpResponse
|
||
}, this);
|
||
```
|
||
|
||
|
||
|
||
### 四、四叉树碰撞检测
|
||
|
||
> 四叉树是一种用于高效进行空间划分和碰撞检测的数据结构。
|
||
|
||
#### *基本概念*
|
||
|
||
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. 更新策略:
|
||
- 仅在必要时更新四叉树
|
||
- 对于静态物体,可以使用单独的四叉树
|
||
- 动态物体频繁更新时,考虑使用更大的边界范围
|
||
|
||
|
||
### 五、行为树系统
|
||
|
||
> 行为树是一个强大的 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. 性能优化:
|
||
- 使用黑板共享数据,避免重复计算
|
||
- 合理使用记忆节点,减少重复执行
|
||
- 控制行为树的深度,避免过于复杂
|
||
|
||
|
||
|
||
### 六、资源加载工具
|
||
|
||
#### *资源加载器*
|
||
|
||
> 注意:资源就算加载多次和一次效果一样
|
||
|
||
```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 async releaseDir(dir: string, bundlename: string = "resources", asset: typeof Asset): Promise<void>
|
||
|
||
/** 按 uuid 释放资源 */
|
||
public static releaseUUID(uuid: string): void
|
||
|
||
/** 释放所有加载的资源 */
|
||
public static releaseAll(): void
|
||
```
|
||
|
||
|
||
|
||
### 七、条件显示节点(用来处理游戏中的提示红点信息)
|
||
|
||
#### *定义条件*
|
||
|
||
```typescript
|
||
// 定义条件类型枚举
|
||
enum ConditionType {
|
||
condition1,
|
||
condition2,
|
||
condition3,
|
||
}
|
||
|
||
// 定义条件
|
||
@conditionClass(ConditionType.condition1)
|
||
export class Condition1 extends kunpo.ConditionBase {
|
||
protected onInit(): void {
|
||
// 监听条件发生变化, 则调用一次 this.tryUpdate();
|
||
kunpo.GlobalEvent.add("condition1", () => {
|
||
this.tryUpdate();
|
||
}, this);
|
||
}
|
||
|
||
protected evaluate(): boolean {
|
||
//TODO:: 根据条件数据,返回true or false
|
||
return true;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### *节点关联条件*
|
||
|
||
```typescript
|
||
/** 任意一个满足 显示节点 */
|
||
new kunpo.ConditionAnyNode(fgui.GObject, ConditionType.condition1, ConditionType.condition2);
|
||
|
||
/** 所有条件都满足 显示节点 */
|
||
new kunpo.ConditionAllNode(fgui.GObject, ConditionType.Condition1, ConditionType.Condition2, ConditionType.Condition3);
|
||
```
|
||
|
||
|
||
|
||
### 八、 全局事件系统
|
||
|
||
```typescript
|
||
import { GlobalEvent } from 'kunpocc';
|
||
|
||
// 添加事件监听
|
||
GlobalEvent.add('eventName', (arg1, arg2) => {
|
||
console.log('事件触发:', arg1, arg2);
|
||
}, this);
|
||
|
||
// 添加一次性事件监听
|
||
GlobalEvent.addOnce('oneTimeEvent', (data) => {
|
||
console.log('一次性事件触发:', data);
|
||
}, this);
|
||
|
||
// 发送事件
|
||
GlobalEvent.send('eventName', 'arg1', 'arg2');
|
||
|
||
// 发送事件到指定目标
|
||
GlobalEvent.sendToTarget('eventName', target, 'arg1', 'arg2');
|
||
|
||
// 移除事件监听
|
||
GlobalEvent.remove('eventName', callback, this);
|
||
|
||
// 移除指定目标的所有事件监听
|
||
GlobalEvent.removeByTarget(this);
|
||
|
||
// 移除指定事件名和目标的事件监听
|
||
GlobalEvent.removeByNameAndTarget('eventName', this);
|
||
```
|
||
|
||
|
||
|
||
### 九、全局计时器
|
||
|
||
```typescript
|
||
import { GlobalTimer } from 'kunpocc';
|
||
|
||
// 启动一次性定时器(2秒后执行)
|
||
const timerId1 = GlobalTimer.startTimer(() => {
|
||
console.log('2秒后执行一次');
|
||
}, 2);
|
||
|
||
// 启动循环定时器(每3秒执行一次,执行5次)
|
||
const timerId2 = GlobalTimer.startTimer(() => {
|
||
console.log('每3秒执行一次,总共执行5次');
|
||
}, 3, 5);
|
||
|
||
// 启动无限循环定时器(每1秒执行一次)
|
||
const timerId3 = GlobalTimer.startTimer(() => {
|
||
console.log('每1秒执行一次,无限循环');
|
||
}, 1, -1);
|
||
|
||
// 停止定时器
|
||
GlobalTimer.stopTimer(timerId1);
|
||
GlobalTimer.stopTimer(timerId2);
|
||
GlobalTimer.stopTimer(timerId3);
|
||
```
|
||
|
||
注意事项:
|
||
- 定时器的时间间隔单位为秒
|
||
- loop 参数说明:
|
||
- 0:执行一次
|
||
- 正整数 n:执行 n 次
|
||
- -1:无限循环
|
||
|
||
### 十、平台相关
|
||
|
||
> Platform 类提供了游戏运行平台的相关信息和判断方法。
|
||
|
||
#### *平台类型*
|
||
|
||
```typescript
|
||
import { Platform, PlatformType } from 'kunpocc';
|
||
|
||
// 平台类型枚举
|
||
enum PlatformType {
|
||
Android = 1, // 安卓
|
||
IOS, // iOS
|
||
HarmonyOS, // 鸿蒙
|
||
WX, // 微信小游戏
|
||
Alipay, // 支付宝小游戏
|
||
Bytedance, // 字节小游戏
|
||
HuaweiQuick, // 华为快游戏
|
||
Browser // 浏览器
|
||
}
|
||
|
||
// 获取当前平台类型
|
||
const currentPlatform = Platform.platform;
|
||
```
|
||
|
||
#### *平台判断*
|
||
|
||
```typescript
|
||
import { Platform } from 'kunpocc';
|
||
|
||
// 原生平台判断
|
||
if (Platform.isNative) {
|
||
console.log('当前是原生平台');
|
||
}
|
||
|
||
// 移动平台判断
|
||
if (Platform.isMobile) {
|
||
console.log('当前是移动平台');
|
||
}
|
||
|
||
// 原生移动平台判断
|
||
if (Platform.isNativeMobile) {
|
||
console.log('当前是原生移动平台');
|
||
}
|
||
|
||
// 具体平台判断
|
||
if (Platform.isAndroid) {
|
||
console.log('当前是安卓平台');
|
||
}
|
||
|
||
if (Platform.isIOS) {
|
||
console.log('当前是iOS平台');
|
||
}
|
||
|
||
if (Platform.isHarmonyOS) {
|
||
console.log('当前是鸿蒙系统');
|
||
}
|
||
|
||
// 小游戏平台判断
|
||
if (Platform.isWX) {
|
||
console.log('当前是微信小游戏');
|
||
}
|
||
|
||
if (Platform.isAlipay) {
|
||
console.log('当前是支付宝小游戏');
|
||
}
|
||
|
||
if (Platform.isBytedance) {
|
||
console.log('当前是字节小游戏');
|
||
}
|
||
|
||
if (Platform.isHuaweiQuick) {
|
||
console.log('当前是华为快游戏');
|
||
}
|
||
|
||
// 浏览器判断
|
||
if (Platform.isBrowser) {
|
||
console.log('当前是浏览器环境');
|
||
}
|
||
```
|
||
|
||
#### *使用示例*
|
||
|
||
```typescript
|
||
import { Platform, PlatformType } from 'kunpocc';
|
||
|
||
// 根据平台类型执行不同逻辑
|
||
switch (Platform.platform) {
|
||
case PlatformType.Android:
|
||
// 安卓平台特定逻辑
|
||
break;
|
||
case PlatformType.IOS:
|
||
// iOS平台特定逻辑
|
||
break;
|
||
case PlatformType.WX:
|
||
// 微信小游戏特定逻辑
|
||
break;
|
||
default:
|
||
// 其他平台逻辑
|
||
break;
|
||
}
|
||
|
||
// 针对不同平台进行适配
|
||
if (Platform.isNativeMobile) {
|
||
// 原生移动平台的处理
|
||
if (Platform.isAndroid) {
|
||
// 安卓特有功能
|
||
} else if (Platform.isIOS) {
|
||
// iOS特有功能
|
||
}
|
||
} else if (Platform.isWX || Platform.isAlipay || Platform.isBytedance) {
|
||
// 小游戏平台的处理
|
||
} else {
|
||
// 浏览器平台的处理
|
||
}
|
||
```
|
||
|
||
|
||
### 十一、屏幕
|
||
|
||
```typescript
|
||
/** 屏幕宽度 */
|
||
public static ScreenWidth: number;
|
||
/** 屏幕高度 */
|
||
public static ScreenHeight: number;
|
||
/** 设计分辨率宽 */
|
||
public static DesignWidth: number;
|
||
/** 设计分辨率高 */
|
||
public static DesignHeight: number;
|
||
/** 安全区外一侧的高度 或 宽度 */
|
||
public static SafeAreaHeight: number;
|
||
/** 安全区的宽度 */
|
||
public static SafeWidth: number;
|
||
/** 安全区的高度 */
|
||
public static SafeHeight: number;
|
||
```
|
||
|
||
|
||
|
||
### 十二、工具类
|
||
|
||
#### *数学工具 (MathTool)*
|
||
|
||
```typescript
|
||
import { MathTool } from 'kunpocc';
|
||
|
||
// 1. 数值限制
|
||
// 将数值限制在指定范围内
|
||
const value = MathTool.clampf(75, 0, 100); // 返回75,因为在0-100范围内
|
||
const value2 = MathTool.clampf(150, 0, 100); // 返回100,因为超出上限
|
||
const value3 = MathTool.clampf(-50, 0, 100); // 返回0,因为低于下限
|
||
|
||
// 2. 随机数生成
|
||
// 生成指定范围内的整数(包含边界值)
|
||
const randomInt = MathTool.rand(1, 10); // 返回1到10之间的整数
|
||
|
||
// 生成指定范围内的浮点数(包含最小值,不包含最大值)
|
||
const randomFloat = MathTool.randRange(0, 1); // 返回0到1之间的浮点数
|
||
|
||
// 3. 角度与弧度转换
|
||
// 角度转弧度
|
||
const radian = MathTool.rad(90); // 90度转换为弧度:约1.57
|
||
|
||
// 弧度转角度
|
||
const degree = MathTool.deg(Math.PI); // π弧度转换为角度:180
|
||
|
||
// 4. 平滑过渡
|
||
// 用于实现数值的平滑变化,常用于相机跟随、UI动画等
|
||
const smoothValue = MathTool.smooth(
|
||
0, // 起始值
|
||
100, // 目标值
|
||
0.16, // 已经过时间(秒)
|
||
0.3 // 响应时间(秒)
|
||
); // 返回一个平滑过渡的中间值
|
||
```
|
||
|
||
使用说明:
|
||
|
||
1. `clampf(value: number, min: number, max: number): number`
|
||
- 将数值限制在指定范围内
|
||
- 如果小于最小值,返回最小值
|
||
- 如果大于最大值,返回最大值
|
||
- 否则返回原值
|
||
|
||
2. `rand(min: number, max: number): number`
|
||
- 生成指定范围内的随机整数
|
||
- 包含最小值和最大值
|
||
- 常用于随机选择、随机掉落等场景
|
||
|
||
3. `randRange(min: number, max: number): number`
|
||
- 生成指定范围内的随机浮点数
|
||
- 包含最小值,不包含最大值
|
||
- 常用于需要精确浮点随机数的场景
|
||
|
||
4. `rad(angle: number): number`
|
||
- 将角度转换为弧度
|
||
- 计算公式:angle * Math.PI / 180
|
||
|
||
5. `deg(radian: number): number`
|
||
- 将弧度转换为角度
|
||
- 计算公式:radian * 180 / Math.PI
|
||
|
||
6. `smooth(current: number, target: number, elapsedTime: number, responseTime: number): number`
|
||
- 计算平滑过渡的值
|
||
- current: 当前值
|
||
- target: 目标值
|
||
- elapsedTime: 已经过时间(秒)
|
||
- responseTime: 响应时间(秒)
|
||
- 常用于实现平滑的相机移动、UI动画等
|
||
|
||
#### *MD5 加密*
|
||
|
||
```typescript
|
||
import { md5 } from 'kunpocc';
|
||
|
||
// 字符串 MD5 加密
|
||
const hash = md5('Hello, World!');
|
||
console.log(hash); // 输出32位MD5哈希值
|
||
|
||
// 注意:
|
||
// 1. 输入必须是字符串类型
|
||
// 2. 不能传入 undefined 或 null
|
||
try {
|
||
md5(null); // 将抛出错误
|
||
} catch (error) {
|
||
console.error('MD5输入不能为null或undefined');
|
||
}
|
||
```
|
||
|
||
## 类型支持
|
||
|
||
该库完全使用 TypeScript 编写,提供完整的类型定义文件。
|
||
|
||
## 许可证
|
||
|
||
ISC License
|
||
|
||
## 作者
|
||
|
||
gongxh
|
||
|
||
## 联系作者
|
||
|
||
* 邮箱: gong.xinhai@163.com
|
||
|
||
## 仓库
|
||
[kunpocc github地址](https://github.com/Gongxh0901/kunpolibrary)
|
||
|
||
[github demo地址](https://github.com/Gongxh0901/KunpoDemo)
|
||
|
||
[gitee demo地址](https://gitee.com/gongxinhai/kunpo-demo)
|