mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-06-23 19:22:47 +08:00
新增与优化核心模块 🎯 GUI 交互增强 ButtonInterceptor:按钮点击事件劫持器 劫持 EventHandler.emitEvents / ButtonSimple.onClick 核心方法 支持多类型按钮音效配置注册,按按钮类型自动匹配音效 单例模式管理,支持全局动态激活 / 停用拦截功能 🧩 对象池管理系统 GameNodePool:通用游戏节点对象池管理器 基于预制体(Prefab)UUID 实现池化隔离管理 支持特效、UI 元素等高频对象预加载、复用与回收 全局单例访问,统一管控对象创建 / 销毁逻辑 🔊 音频管理系统 AudioManager:音频核心管理器 独立背景音乐(AudioMusic)+ 音效池(AudioEffectPool)双模块 支持全局音量控制、播放状态恢复与场景切换管理 AudioEffect:基础音效播放器 AudioEnum:音频类型、音效分类枚举定义 📦 资源加载系统 ResLoader:资源加载核心控制器 资源包(Bundle)统一管理 + 并发加载限流控制 远程资源本地缓存、自动释放与内存优化 完整加载进度回调 + 错误异常处理机制 ResTypes:资源类型规范定义 ResErrors:资源加载错误码与异常处理 ResUtils:资源路径、格式转换等工具方法 🧱 模块化组件系统 GameComponent:游戏显示对象组件基类 集成资源自动引用计数(RC)管理 模块化部件(GamePartRegistry)插拔式架构 内置音频、按钮、事件、键盘、节点、对象池、资源七大部件 部件封装: GamePartAudio:音频功能部件 GamePartButton:按钮交互部件 GamePartEvent:全局事件部件 GamePartKeyboard:键盘输入部件 GamePartNode:节点操作部件 GamePartNodePool:对象池调用部件 GamePartRes:资源加载部件 📝 类型定义完善 新增 IAudio 音频数据与播放参数接口 统一全模块 TS 类型定义与导出规范 优化接口注释与类型约束,提升开发体验
169 lines
5.0 KiB
TypeScript
169 lines
5.0 KiB
TypeScript
import { Component, error, Node, Vec3, _decorator } from 'cc';
|
||
import { Timer } from '../../core/common/timer/Timer';
|
||
|
||
const { ccclass } = _decorator;
|
||
|
||
/** 移动到指定目标位置 */
|
||
@ccclass('MoveTo')
|
||
export class MoveTo extends Component {
|
||
/** 目标位置 */
|
||
target: Vec3 | Node | null = null;
|
||
/** 移动方向 */
|
||
velocity: Vec3 = new Vec3();
|
||
/** 移动速度(每秒移动的像素距离) */
|
||
speed = 0;
|
||
/** 是否计算将 Y 轴带入计算 */
|
||
hasYAxis = true;
|
||
|
||
/** 坐标标(默认本地坐标) */
|
||
ns: number = Node.NodeSpace.LOCAL;
|
||
/** 偏移距离 */
|
||
offset = 0;
|
||
/** 偏移向量 */
|
||
offsetVector: Vec3 | null = null;
|
||
/** 移动开始 */
|
||
onStart: Function | null = null;
|
||
/** 移动完成回调 */
|
||
onComplete: Function | null = null;
|
||
/** 距离变化时 */
|
||
onChange: Function | null = null;
|
||
|
||
/** 延时触发器 */
|
||
private timer: Timer = new Timer();
|
||
/** 终点备份 */
|
||
private end: Vec3 | null = null;
|
||
/** 复用向量——避免每帧分配 Vec3 对象 */
|
||
private _temp: Vec3 = new Vec3();
|
||
|
||
protected onLoad(): void {
|
||
this.enabled = false;
|
||
}
|
||
|
||
move() {
|
||
this.enabled = true;
|
||
}
|
||
|
||
protected update(dt: number) {
|
||
let end: Vec3 | null = null;
|
||
|
||
if (this.speed <= 0) {
|
||
error('[MoveTo] 移动速度必须要大于零');
|
||
this.exit();
|
||
return;
|
||
}
|
||
|
||
if (this.target instanceof Node) {
|
||
if (!this.target.isValid) {
|
||
this.exit();
|
||
return;
|
||
}
|
||
end = this.ns === Node.NodeSpace.WORLD ? this.target.worldPosition : this.target.position;
|
||
}
|
||
else {
|
||
end = this.target as Vec3;
|
||
}
|
||
|
||
// 移动目标节点被释放时
|
||
if (end === null) {
|
||
this.exit();
|
||
return;
|
||
}
|
||
|
||
// 目标移动后,重计算移动方向与移动到目标点的速度
|
||
if (this.end === null || !this.end.strictEquals(end)) {
|
||
let target = end.clone();
|
||
if (this.offsetVector) {
|
||
target = target.add(this.offsetVector);
|
||
}
|
||
|
||
if (this.hasYAxis === false) {
|
||
target.y = 0;
|
||
}
|
||
|
||
// 移动方向与移动速度(直接写入 velocity,避免 new Vec3)
|
||
const start = this.ns === Node.NodeSpace.WORLD ? this.node.worldPosition : this.node.position;
|
||
Vec3.subtract(this.velocity, target, start);
|
||
this.velocity.normalize();
|
||
|
||
// 移动时间与目标偏位置计算
|
||
const distance = Vec3.distance(start, target) - this.offset;
|
||
|
||
// 目标位置修改事件
|
||
this.onChange?.call(this);
|
||
|
||
if (distance <= 0) {
|
||
this.exit();
|
||
return;
|
||
}
|
||
else {
|
||
this.onStart?.call(this);
|
||
this.timer.step = distance / this.speed;
|
||
this.end = end.clone();
|
||
}
|
||
}
|
||
|
||
if (this.speed > 0) {
|
||
// _temp = velocity * speed * dt(写入预分配向量,零分配)
|
||
Vec3.multiplyScalar(this._temp, this.velocity, this.speed * dt);
|
||
const curPos = this.ns === Node.NodeSpace.WORLD
|
||
? this.node.worldPosition
|
||
: this.node.position;
|
||
this._temp.x += curPos.x;
|
||
this._temp.y += curPos.y;
|
||
this._temp.z += curPos.z;
|
||
if (this.ns === Node.NodeSpace.WORLD) {
|
||
this.node.worldPosition = this._temp;
|
||
}
|
||
else {
|
||
this.node.position = this._temp;
|
||
}
|
||
}
|
||
|
||
// 移动完成事件
|
||
if (this.timer.update(dt)) {
|
||
if (this.offset === 0 && this.end) {
|
||
if (this.ns === Node.NodeSpace.WORLD) {
|
||
this.node.worldPosition = this.end;
|
||
}
|
||
else {
|
||
this.node.position = this.end;
|
||
}
|
||
}
|
||
this.exit();
|
||
}
|
||
}
|
||
|
||
private exit() {
|
||
if (this.onComplete) {
|
||
this.onComplete.call(this);
|
||
}
|
||
this.enabled = false;
|
||
|
||
this.target = null;
|
||
this.velocity.set(0, 0, 0);
|
||
this.speed = 0;
|
||
this.hasYAxis = true;
|
||
this.ns = Node.NodeSpace.LOCAL;
|
||
this.offset = 0;
|
||
this.offsetVector = null;
|
||
this.onStart = null;
|
||
this.onComplete = null;
|
||
this.onChange = null;
|
||
this.timer.reset();
|
||
this.end = null;
|
||
}
|
||
|
||
/**
|
||
* 组件销毁时清理资源
|
||
*/
|
||
protected onDestroy() {
|
||
// 清理所有回调引用,防止内存泄漏
|
||
this.target = null;
|
||
this.onStart = null;
|
||
this.onComplete = null;
|
||
this.onChange = null;
|
||
this.offsetVector = null;
|
||
this.end = null;
|
||
this.timer.reset();
|
||
}
|
||
} |