- 启用PhysicsSystem2D的Aabb调试绘制以辅助碰撞检测 - 将射手英雄的技能由[6002,6100]更新为[6005,6006] - 为SMoveComp添加isHorizontal属性,强制水平移动时保持Y坐标不变 - 技能施放延迟优先使用技能配置的ready值,提高配置灵活性 - 将技能6001和6005的结束类型由animationEnd改为collision,使伤害触发更精确
263 lines
7.3 KiB
TypeScript
263 lines
7.3 KiB
TypeScript
import { Vec3, v3, Node } from "cc";
|
|
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
|
import { RType, EType, SkillSet } from "../common/config/SkillSet";
|
|
import { BoxSet } from "../common/config/GameSet";
|
|
import { SkillView } from "./SkillView";
|
|
import { smc } from "../common/SingletonModuleComp";
|
|
|
|
/**
|
|
* ==================== 技能移动数据组件 ====================
|
|
*
|
|
* 用途:
|
|
* - 存储技能实体的移动相关数据
|
|
* - 管理移动状态和参数
|
|
* - 支持多种移动类型(线性、贝塞尔、固定位置等)
|
|
*/
|
|
@ecs.register('SMoveDataComp')
|
|
export class SMoveDataComp extends ecs.Comp {
|
|
/** 起始位置 */
|
|
startPos: Vec3 = v3(0, 0, 0);
|
|
|
|
/** 目标位置 */
|
|
targetPos: Vec3 = v3(0, 0, 0);
|
|
|
|
/** 当前位置 */
|
|
currentPos: Vec3 = v3(0, 0, 0);
|
|
|
|
/** 移动速度 */
|
|
speed: number = 500;
|
|
|
|
/** 移动进度 (0-1) */
|
|
progress: number = 0;
|
|
|
|
/** 移动方向缩放 */
|
|
scale: number = 1;
|
|
|
|
/** 技能UUID */
|
|
s_uuid: number = 0;
|
|
|
|
/** 运行类型 */
|
|
runType: RType = RType.linear;
|
|
|
|
/** 结束类型 */
|
|
endType: EType = EType.collision;
|
|
|
|
/** 是否强制水平移动 */
|
|
isHorizontal: boolean = true;
|
|
|
|
/** 攻击偏移X - 从视图层传递 */
|
|
atk_x: number = 0;
|
|
|
|
/** 攻击偏移Y - 从视图层传递 */
|
|
atk_y: number = 0;
|
|
|
|
/** 是否正在移动 */
|
|
isMoving: boolean = false;
|
|
|
|
/** 是否已完成移动 */
|
|
isCompleted: boolean = false;
|
|
|
|
/** 移动开始时间 */
|
|
startTime: number = 0;
|
|
|
|
/** 移动总时间 */
|
|
totalTime: number = 0;
|
|
|
|
/** 贝塞尔曲线控制点 */
|
|
controlPoint: Vec3 = v3(0, 0, 0);
|
|
|
|
/** 是否自动销毁(到达目标后) */
|
|
autoDestroy: boolean = true;
|
|
|
|
reset() {
|
|
this.startPos.set(0, 0, 0);
|
|
this.targetPos.set(0, 0, 0);
|
|
this.currentPos.set(0, 0, 0);
|
|
this.controlPoint.set(0, 0, 0);
|
|
this.speed = 500;
|
|
this.progress = 0;
|
|
this.scale = 1;
|
|
this.s_uuid = 0;
|
|
this.runType = RType.linear;
|
|
this.endType = EType.collision;
|
|
this.isHorizontal = true;
|
|
this.atk_x = 0;
|
|
this.atk_y = 0;
|
|
this.isMoving = false;
|
|
this.isCompleted = false;
|
|
this.startTime = 0;
|
|
this.totalTime = 0;
|
|
this.autoDestroy = true;
|
|
}
|
|
|
|
/**
|
|
* 重新计算位置(用于线性移动的延长)
|
|
*/
|
|
rePos(originalStart: Vec3) {
|
|
if (!originalStart) {
|
|
return;
|
|
}
|
|
|
|
// 计算方向向量
|
|
const direction = new Vec3();
|
|
Vec3.subtract(direction, this.targetPos, originalStart);
|
|
direction.normalize();
|
|
|
|
// 延长720像素
|
|
const extendedTarget = new Vec3();
|
|
Vec3.scaleAndAdd(extendedTarget, originalStart, direction, 720);
|
|
|
|
this.startPos.set(originalStart);
|
|
this.targetPos.set(extendedTarget);
|
|
}
|
|
|
|
/**
|
|
* 开始移动
|
|
*/
|
|
startMove() {
|
|
this.isMoving = true;
|
|
this.isCompleted = false;
|
|
this.progress = 0;
|
|
this.startTime = Date.now();
|
|
this.currentPos.set(this.startPos);
|
|
|
|
// 根据移动类型计算总时间和控制点
|
|
this.calculateMoveParameters();
|
|
}
|
|
|
|
/**
|
|
* 计算移动参数
|
|
*/
|
|
private calculateMoveParameters() {
|
|
const distance = Vec3.distance(this.startPos, this.targetPos);
|
|
this.totalTime = distance / this.speed;
|
|
|
|
// 为贝塞尔移动生成控制点
|
|
if (this.runType === RType.bezier) {
|
|
this.generateBezierControlPoint();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成贝塞尔曲线控制点
|
|
*/
|
|
private generateBezierControlPoint() {
|
|
const midPoint = new Vec3();
|
|
Vec3.lerp(midPoint, this.startPos, this.targetPos, 0.5);
|
|
|
|
// 计算垂直方向
|
|
const direction = new Vec3();
|
|
Vec3.subtract(direction, this.targetPos, this.startPos);
|
|
const perpendicular = v3(-direction.y, direction.x, 0);
|
|
perpendicular.normalize();
|
|
|
|
// 根据scale决定控制点方向
|
|
const offset = 100 * this.scale;
|
|
Vec3.scaleAndAdd(this.controlPoint, midPoint, perpendicular, offset);
|
|
}
|
|
|
|
/**
|
|
* 更新移动进度
|
|
*/
|
|
updateProgress(deltaTime: number): boolean {
|
|
if (!this.isMoving || this.isCompleted) {
|
|
return false;
|
|
}
|
|
|
|
this.progress += deltaTime / this.totalTime;
|
|
|
|
if (this.progress >= 1) {
|
|
this.progress = 1;
|
|
this.isCompleted = true;
|
|
this.isMoving = false;
|
|
}
|
|
|
|
// 根据移动类型计算当前位置
|
|
this.calculateCurrentPosition();
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 根据移动类型计算当前位置
|
|
*/
|
|
private calculateCurrentPosition() {
|
|
switch (this.runType) {
|
|
case RType.linear:
|
|
// 直线运动
|
|
Vec3.lerp(this.currentPos, this.startPos, this.targetPos, this.progress);
|
|
break;
|
|
|
|
case RType.bezier:
|
|
this.calculateBezierPosition(this.progress);
|
|
break;
|
|
|
|
case RType.fixed:
|
|
case RType.fixedEnd:
|
|
// 固定位置类型不需要移动
|
|
this.currentPos.set(this.startPos);
|
|
break;
|
|
|
|
default:
|
|
Vec3.lerp(this.currentPos, this.startPos, this.targetPos, this.progress);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算贝塞尔曲线位置
|
|
*/
|
|
private calculateBezierPosition(t: number) {
|
|
// 二次贝塞尔曲线公式: B(t) = (1-t)²P0 + 2(1-t)tP1 + t²P2
|
|
const oneMinusT = 1 - t;
|
|
const oneMinusTSquared = oneMinusT * oneMinusT;
|
|
const tSquared = t * t;
|
|
const twoOneMinusTt = 2 * oneMinusT * t;
|
|
|
|
this.currentPos.x = oneMinusTSquared * this.startPos.x +
|
|
twoOneMinusTt * this.controlPoint.x +
|
|
tSquared * this.targetPos.x;
|
|
|
|
this.currentPos.y = oneMinusTSquared * this.startPos.y +
|
|
twoOneMinusTt * this.controlPoint.y +
|
|
tSquared * this.targetPos.y;
|
|
|
|
this.currentPos.z = oneMinusTSquared * this.startPos.z +
|
|
twoOneMinusTt * this.controlPoint.z +
|
|
tSquared * this.targetPos.z;
|
|
}
|
|
|
|
/**
|
|
* 停止移动
|
|
*/
|
|
stopMove() {
|
|
this.isMoving = false;
|
|
this.isCompleted = true;
|
|
}
|
|
|
|
/**
|
|
* 获取移动统计信息(用于调试)
|
|
*/
|
|
getMoveStats(): {
|
|
isMoving: boolean;
|
|
isCompleted: boolean;
|
|
progress: number;
|
|
runType: RType;
|
|
endType: EType;
|
|
totalTime: number;
|
|
elapsedTime: number;
|
|
} {
|
|
const currentTime = Date.now();
|
|
return {
|
|
isMoving: this.isMoving,
|
|
isCompleted: this.isCompleted,
|
|
progress: this.progress,
|
|
runType: this.runType,
|
|
endType: this.endType,
|
|
totalTime: this.totalTime,
|
|
elapsedTime: (currentTime - this.startTime) / 1000
|
|
};
|
|
}
|
|
}
|
|
|