Files
pixelheros/assets/script/game/skill/SMoveSystem.ts
walkpan 211f48b6aa feat: 启用物理调试绘制并调整技能配置与移动逻辑
- 启用PhysicsSystem2D的Aabb调试绘制以辅助碰撞检测
- 将射手英雄的技能由[6002,6100]更新为[6005,6006]
- 为SMoveComp添加isHorizontal属性,强制水平移动时保持Y坐标不变
- 技能施放延迟优先使用技能配置的ready值,提高配置灵活性
- 将技能6001和6005的结束类型由animationEnd改为collision,使伤害触发更精确
2026-03-15 13:03:34 +08:00

232 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { v3, Vec3 ,Node} from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { EType, RType, SkillSet } from "../common/config/SkillSet";
import { SMoveDataComp } from "./SMoveComp";
import { smc } from "../common/SingletonModuleComp";
import { SkillView } from "./SkillView";
import { mLogger } from "../common/Logger";
/**
* ==================== 技能移动系统 ====================
*
* 职责:
* 1. 处理技能实体的移动逻辑
* 2. 更新技能位置
* 3. 管理移动生命周期
* 4. 支持多种移动类型
*
* 设计理念:
* - 参考DamageQueueComp的实现方式
* - 独立的移动处理系统
* - 支持从视图层获取的参数
*/
@ecs.register('SMoveSystem')
export class SMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
debugMode: boolean = false;
filter(): ecs.IMatcher {
return ecs.allOf(SMoveDataComp, SkillView);
}
entityEnter(entity: ecs.Entity): void {
const moveComp = entity.get(SMoveDataComp);
const skillView = entity.get(SkillView);
if (!moveComp || !skillView || !skillView.node) return;
// 获取技能配置
const skillConfig = SkillSet[moveComp.s_uuid];
if (!skillConfig) {
mLogger.warn(this.debugMode, 'SMoveSystem', `[SMoveSystem] 技能配置不存在: ${moveComp.s_uuid}`);
return;
}
// 根据配置设置移动速度
if (skillConfig.speed > 0) {
moveComp.speed = skillConfig.speed;
}
// 根据runType设置初始位置
this.initializePosition(moveComp, skillView);
// 开始移动(除了固定位置类型)
if (moveComp.runType !== RType.fixed && moveComp.runType !== RType.fixedEnd) {
moveComp.startMove();
}
mLogger.log(this.debugMode, 'SMoveSystem', `[SMoveSystem] 技能 ${skillConfig.name} 开始移动,类型: ${moveComp.runType}`);
}
/**
* 根据runType初始化技能位置
*/
private initializePosition(moveComp: SMoveDataComp, skillView: SkillView): void {
const node = skillView.node;
switch(moveComp.runType) {
case RType.linear:
// linear类型根据atk_x和atk_y调整位置
const linearPos = v3(
node.position.x + moveComp.atk_x,
node.position.y + moveComp.atk_y,
node.position.z
);
// 如果开启水平移动开关强制目标Y等于起点Y
if (moveComp.isHorizontal) {
moveComp.targetPos.y = linearPos.y;
}
moveComp.rePos(linearPos);
// 设置旋转角度
const direction = new Vec3();
Vec3.subtract(direction, moveComp.targetPos, moveComp.startPos);
if (direction.length() > 0.01) {
const angle = Math.atan2(direction.y, direction.x) * (180 / Math.PI);
node.angle = angle;
}
break;
case RType.fixed:
// 固定起始位置
node.setPosition(moveComp.startPos.x, node.position.y, 0);
break;
case RType.fixedEnd:
// 固定结束位置
node.setPosition(moveComp.targetPos.x > 360 ? 300 : moveComp.targetPos.x, node.position.y, 0);
break;
default:
// 其他类型包括bezier根据atk_x和atk_y调整起始位置
if (moveComp.atk_x !== 0 || moveComp.atk_y !== 0) {
const adjustedStartPos = v3(
moveComp.startPos.x + moveComp.atk_x * moveComp.scale,
moveComp.startPos.y + moveComp.atk_y,
moveComp.startPos.z
);
moveComp.startPos.set(adjustedStartPos);
node.setPosition(adjustedStartPos);
}
break;
}
}
update(entity: ecs.Entity): void {
if(!smc.mission.play ) return;
if(smc.mission.pause) return
const moveComp = entity.get(SMoveDataComp);
const skillView = entity.get(SkillView);
if (!moveComp || !skillView || !skillView.node) return;
// 更新移动进度
const isMoving = moveComp.updateProgress(this.dt);
if (isMoving) {
// 更新节点位置
skillView.node.setPosition(moveComp.currentPos);
// 处理自动旋转(贝塞尔移动)
if (moveComp.runType === RType.bezier) {
this.updateRotation(skillView.node, moveComp);
}
}
// 检查移动完成
if (moveComp.isCompleted && moveComp.autoDestroy) {
// 根据结束类型决定是否销毁
if (moveComp.endType === EType.timeEnd || moveComp.endType === EType.collision) {
entity.destroy();
}
}
}
/**
* 更新节点旋转(用于贝塞尔移动)
*/
private updateRotation(node: Node, moveComp: SMoveDataComp) {
if (moveComp.progress < 1) {
// 计算下一帧的位置来确定方向
const nextProgress = Math.min(moveComp.progress + 0.01, 1);
const nextPos = v3(0, 0, 0);
// 计算下一个位置
const t = nextProgress;
const oneMinusT = 1 - t;
const oneMinusTSquared = oneMinusT * oneMinusT;
const tSquared = t * t;
const twoOneMinusTt = 2 * oneMinusT * t;
nextPos.x = oneMinusTSquared * moveComp.startPos.x +
twoOneMinusTt * moveComp.controlPoint.x +
tSquared * moveComp.targetPos.x;
nextPos.y = oneMinusTSquared * moveComp.startPos.y +
twoOneMinusTt * moveComp.controlPoint.y +
tSquared * moveComp.targetPos.y;
// 计算方向角度
const direction = new Vec3();
Vec3.subtract(direction, nextPos, moveComp.currentPos);
if (direction.length() > 0.01) {
const angle = Math.atan2(direction.y, direction.x) * (180 / Math.PI);
node.angle = angle;
}
}
}
}
/**
* ==================== 技能移动辅助工具 ====================
*/
export class SMoveHelper {
/**
* 为技能实体设置移动参数
*/
static setupMoveForSkill(entity: ecs.Entity, startPos: Vec3, targetPos: Vec3, s_uuid: number): void {
let moveComp = entity.get(SMoveDataComp);
if (!moveComp) {
moveComp = entity.add(SMoveDataComp);
}
moveComp.startPos.set(startPos);
moveComp.targetPos.set(targetPos);
moveComp.s_uuid = s_uuid;
// 从技能配置获取默认参数
const skillConfig = SkillSet[s_uuid];
if (skillConfig) {
moveComp.runType = skillConfig.RType || RType.linear;
moveComp.speed = skillConfig.speed || 500;
}
}
/**
* 检查技能是否正在移动
*/
static isSkillMoving(entity: ecs.Entity): boolean {
const moveComp = entity.get(SMoveDataComp);
return moveComp ? moveComp.isMoving : false;
}
/**
* 获取技能移动统计信息
*/
static getSkillMoveStats(entity: ecs.Entity): any {
const moveComp = entity.get(SMoveDataComp);
return moveComp ? moveComp.getMoveStats() : null;
}
/**
* 停止技能移动
*/
static stopSkillMove(entity: ecs.Entity): void {
const moveComp = entity.get(SMoveDataComp);
if (moveComp) {
moveComp.stopMove();
}
}
}