refactor(skill): 重构技能移动系统,整合移动逻辑到SMoveComp
将技能移动逻辑从SkillView迁移到SMoveComp,实现统一的移动管理 添加多种移动类型支持(线性、贝塞尔、固定位置) 优化移动参数配置,从SkillView获取攻击偏移量
This commit is contained in:
@@ -285,8 +285,8 @@
|
|||||||
},
|
},
|
||||||
"atk_x": 0,
|
"atk_x": 0,
|
||||||
"atk_y": 0,
|
"atk_y": 0,
|
||||||
"runType": 2,
|
"runType": 0,
|
||||||
"endType": 0,
|
"endType": 2,
|
||||||
"_id": ""
|
"_id": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export enum SType {
|
|||||||
zhaohuan = 10,
|
zhaohuan = 10,
|
||||||
buff = 11,
|
buff = 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
//受伤动画名称
|
//受伤动画名称
|
||||||
export enum AtkedName {
|
export enum AtkedName {
|
||||||
atked = "atked",
|
atked = "atked",
|
||||||
@@ -143,7 +144,7 @@ interface IEndAnm {
|
|||||||
// 技能配置接口 - 按照6001格式排列
|
// 技能配置接口 - 按照6001格式排列
|
||||||
export interface SkillConfig {
|
export interface SkillConfig {
|
||||||
uuid:number,name:string,sp_name:string,AtkedName:AtkedName,path:string,TGroup:TGroup,SType:SType,act:string,DTType:DTType,DType:DType,
|
uuid:number,name:string,sp_name:string,AtkedName:AtkedName,path:string,TGroup:TGroup,SType:SType,act:string,DTType:DTType,DType:DType,
|
||||||
ap:number,cd:number,t_num:number,hit_num:number,hit:number,hitcd:number,speed:number,cost:number,with:number,ready:number,endAnm:number,RType:RType,
|
ap:number,cd:number,t_num:number,hit_num:number,hit:number,hitcd:number,speed:number,cost:number,with:number,ready:number,endAnm:number,RType:RType,EType:EType,
|
||||||
buffs:BuffConf[],neAttrs:NeAttrsConf[],info:string,hero?:number ,
|
buffs:BuffConf[],neAttrs:NeAttrsConf[],info:string,hero?:number ,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,17 +152,17 @@ export const SkillSet: Record<number, SkillConfig> = {
|
|||||||
// ========== 基础攻击 ========== 6001-6099
|
// ========== 基础攻击 ========== 6001-6099
|
||||||
6001: {
|
6001: {
|
||||||
uuid:6001,name:"挥击",sp_name:"atk_s1",AtkedName:AtkedName.atked,path:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK,
|
uuid:6001,name:"挥击",sp_name:"atk_s1",AtkedName:AtkedName.atked,path:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK,
|
||||||
ap:100,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,ready:0,endAnm:0,RType:RType.fixed,
|
ap:100,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,ready:0,endAnm:0,RType:RType.fixed,EType:EType.animationEnd,
|
||||||
buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害",
|
buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害",
|
||||||
},
|
},
|
||||||
6002: {
|
6002: {
|
||||||
uuid:6002,name:"挥砍",sp_name:"atk_s2",AtkedName:AtkedName.atked,path:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK,
|
uuid:6002,name:"挥砍",sp_name:"atk_s2",AtkedName:AtkedName.atked,path:"3036",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.ATK,
|
||||||
ap:100,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,ready:0,endAnm:0,RType:RType.fixed,
|
ap:100,cd:1,t_num:1,hit_num:1,hit:1,hitcd:0.2,speed:720,cost:0,with:0,ready:0,endAnm:0,RType:RType.fixed,EType:EType.animationEnd,
|
||||||
buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害",
|
buffs:[],neAttrs:[],info:"向最前方敌人扔出石斧,造成100%攻击的伤害",
|
||||||
},
|
},
|
||||||
6005: {
|
6005: {
|
||||||
uuid:6005,name:"水球",sp_name:"m_water_ball_1",AtkedName:AtkedName.atked,path:"3039",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.MAGE,
|
uuid:6005,name:"水球",sp_name:"m_water_ball_1",AtkedName:AtkedName.atked,path:"3039",TGroup:TGroup.Enemy,SType:SType.damage,act:"atk",DTType:DTType.single,DType:DType.MAGE,
|
||||||
ap:100,cd:5,t_num:1,hit_num:1,hit:2,hitcd:0.3,speed:720,cost:20,with:90,ready:8001,endAnm:9001,RType:RType.linear,
|
ap:100,cd:5,t_num:1,hit_num:1,hit:2,hitcd:0.3,speed:720,cost:20,with:90,ready:8001,endAnm:9001,RType:RType.linear,EType:EType.collision,
|
||||||
buffs:[],neAttrs:[],info:"召唤大火球攻击前方所有敌人,造成300%攻击的伤害,有一定几率施加灼烧",
|
buffs:[],neAttrs:[],info:"召唤大火球攻击前方所有敌人,造成300%攻击的伤害,有一定几率施加灼烧",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,68 +1,471 @@
|
|||||||
import { Vec3, v3 } from "cc";
|
import { Vec3, v3, Node } from "cc";
|
||||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||||
import { BezierMove } from "../BezierMove/BezierMove";
|
import { RType, EType, SkillSet } from "../common/config/SkillSet";
|
||||||
import { RType, SkillSet } from "../common/config/SkillSet";
|
|
||||||
import { BoxSet } from "../common/config/BoxSet";
|
import { BoxSet } from "../common/config/BoxSet";
|
||||||
import { ECSEntity } from "db://oops-framework/libs/ecs/ECSEntity";
|
|
||||||
import { SkillView } from "./SkillView";
|
import { SkillView } from "./SkillView";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 技能移动数据组件
|
* ==================== 技能移动数据组件 ====================
|
||||||
* 存储技能实体的移动相关数据
|
*
|
||||||
|
* 用途:
|
||||||
|
* - 存储技能实体的移动相关数据
|
||||||
|
* - 管理移动状态和参数
|
||||||
|
* - 支持多种移动类型(线性、贝塞尔、固定位置等)
|
||||||
*/
|
*/
|
||||||
@ecs.register('SMoveDataComp')
|
@ecs.register('SMoveDataComp')
|
||||||
export class SMoveDataComp extends ecs.Comp {
|
export class SMoveDataComp extends ecs.Comp {
|
||||||
/** 起始位置 */
|
/** 起始位置 */
|
||||||
startPos: Vec3 = null;
|
startPos: Vec3 = v3(0, 0, 0);
|
||||||
|
|
||||||
/** 目标位置 */
|
/** 目标位置 */
|
||||||
targetPos: Vec3 = null;
|
targetPos: Vec3 = v3(0, 0, 0);
|
||||||
|
|
||||||
|
/** 当前位置 */
|
||||||
|
currentPos: Vec3 = v3(0, 0, 0);
|
||||||
|
|
||||||
/** 移动速度 */
|
/** 移动速度 */
|
||||||
speed: number = 500;
|
speed: number = 500;
|
||||||
/** 移动持续时间 */
|
|
||||||
duration: number = 0;
|
/** 移动进度 (0-1) */
|
||||||
/** 移动方向 */
|
progress: number = 0;
|
||||||
|
|
||||||
|
/** 移动方向缩放 */
|
||||||
scale: number = 1;
|
scale: number = 1;
|
||||||
|
|
||||||
|
/** 技能UUID */
|
||||||
|
s_uuid: number = 0;
|
||||||
|
|
||||||
|
/** 运行类型 */
|
||||||
|
runType: RType = RType.linear;
|
||||||
|
|
||||||
|
/** 结束类型 */
|
||||||
|
endType: EType = EType.collision;
|
||||||
|
|
||||||
|
/** 攻击偏移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;
|
autoDestroy: boolean = true;
|
||||||
s_uuid:number=0;
|
|
||||||
reset() {
|
reset() {
|
||||||
this.startPos.set(0, 0, 0);
|
this.startPos.set(0, 0, 0);
|
||||||
this.targetPos.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.speed = 500;
|
||||||
this.duration = 0;
|
this.progress = 0;
|
||||||
this.scale=1;
|
this.scale = 1;
|
||||||
|
this.s_uuid = 0;
|
||||||
|
this.runType = RType.linear;
|
||||||
|
this.endType = EType.collision;
|
||||||
|
this.atk_x = 0;
|
||||||
|
this.atk_y = 0;
|
||||||
|
this.isMoving = false;
|
||||||
|
this.isCompleted = false;
|
||||||
|
this.startTime = 0;
|
||||||
|
this.totalTime = 0;
|
||||||
this.autoDestroy = true;
|
this.autoDestroy = true;
|
||||||
}
|
}
|
||||||
rePos(originalStart:Vec3){
|
|
||||||
if(!originalStart){
|
/**
|
||||||
return
|
* 重新计算位置(用于线性移动的延长)
|
||||||
|
*/
|
||||||
|
rePos(originalStart: Vec3) {
|
||||||
|
if (!originalStart) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
console.log("[SMoveDataComp]rePos",originalStart,this.targetPos)
|
|
||||||
// 计算延长后的目标点坐标
|
// 对于直线运动,只在x轴方向延长,y轴保持不变
|
||||||
const originalTarget = v3(this.targetPos.x, this.targetPos.y + BoxSet.ATK_Y);
|
const originalTarget = v3(this.targetPos.x, this.targetPos.y + BoxSet.ATK_Y);
|
||||||
const direction = new Vec3();
|
|
||||||
Vec3.subtract(direction, originalTarget, originalStart);
|
// 计算x轴方向
|
||||||
const distance = direction.length();
|
const xDirection = originalTarget.x > originalStart.x ? 1 : -1;
|
||||||
direction.normalize();
|
|
||||||
const extendedTarget = new Vec3();
|
// 延长720像素,但只在x轴方向
|
||||||
Vec3.scaleAndAdd(extendedTarget, originalTarget, direction, 720);
|
const extendedTarget = v3(
|
||||||
|
originalTarget.x + (xDirection * 720),
|
||||||
|
originalStart.y, // y轴保持起始位置不变
|
||||||
|
originalStart.z // z轴保持起始位置不变
|
||||||
|
);
|
||||||
|
|
||||||
this.startPos.set(originalStart);
|
this.startPos.set(originalStart);
|
||||||
this.targetPos.set(extendedTarget);
|
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:
|
||||||
|
// 直线运动:只在x轴移动,y轴保持不变
|
||||||
|
this.currentPos.x = this.startPos.x + (this.targetPos.x - this.startPos.x) * this.progress;
|
||||||
|
this.currentPos.y = this.startPos.y; // y轴保持不变
|
||||||
|
this.currentPos.z = this.startPos.z; // z轴保持不变
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 业务层业务逻辑处理对象 */
|
/**
|
||||||
|
* ==================== 技能移动系统 ====================
|
||||||
|
*
|
||||||
|
* 职责:
|
||||||
|
* 1. 处理技能实体的移动逻辑
|
||||||
|
* 2. 更新技能位置
|
||||||
|
* 3. 管理移动生命周期
|
||||||
|
* 4. 支持多种移动类型
|
||||||
|
*
|
||||||
|
* 设计理念:
|
||||||
|
* - 参考DamageQueueComp的实现方式
|
||||||
|
* - 独立的移动处理系统
|
||||||
|
* - 支持从视图层获取的参数
|
||||||
|
*/
|
||||||
|
@ecs.register('SMoveSystem')
|
||||||
export class SMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
export class SMoveSystem extends ecs.ComblockSystem implements ecs.ISystemUpdate {
|
||||||
|
|
||||||
filter(): ecs.IMatcher {
|
filter(): ecs.IMatcher {
|
||||||
return ecs.allOf(SMoveDataComp,SkillView);
|
return ecs.allOf(SMoveDataComp, SkillView);
|
||||||
}
|
|
||||||
entityEnter(e: ecs.Entity): void {
|
|
||||||
// 注:自定义业务逻辑
|
|
||||||
let s_uuid=e.get(SMoveDataComp).s_uuid
|
|
||||||
let SConf=SkillSet[s_uuid]
|
|
||||||
|
|
||||||
}
|
|
||||||
update(entity: ECSEntity): void {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
console.warn(`[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();
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(`[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
|
||||||
|
);
|
||||||
|
moveComp.rePos(linearPos);
|
||||||
|
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 {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -56,19 +56,24 @@ export class Skill extends ecs.Entity {
|
|||||||
|
|
||||||
// 初始视图
|
// 初始视图
|
||||||
const SView = node.getComponent(SkillView);
|
const SView = node.getComponent(SkillView);
|
||||||
console.log("load skill SView",SView)
|
|
||||||
// 只设置必要的运行时属性,配置信息通过 SkillSet[uuid] 访问
|
// 只设置必要的运行时属性,配置信息通过 SkillSet[uuid] 访问
|
||||||
// 核心标识
|
// 核心标识
|
||||||
SView.s_uuid= s_uuid
|
SView.s_uuid= s_uuid
|
||||||
SView.group= caster.box_group
|
SView.group= caster.box_group
|
||||||
|
|
||||||
this.add(SView);
|
this.add(SView);
|
||||||
// 初始化移动组件
|
|
||||||
|
// 初始化移动组件 - 从SkillView获取移动参数
|
||||||
const sMoveCom = this.get(SMoveDataComp);
|
const sMoveCom = this.get(SMoveDataComp);
|
||||||
sMoveCom.startPos=startPos
|
sMoveCom.startPos.set(startPos);
|
||||||
sMoveCom.targetPos=targetPos
|
sMoveCom.targetPos.set(targetPos);
|
||||||
sMoveCom.s_uuid=s_uuid
|
sMoveCom.s_uuid = s_uuid;
|
||||||
sMoveCom.scale=caster.node.scale.x < 0 ? -1 : 1
|
sMoveCom.scale = caster.node.scale.x < 0 ? -1 : 1;
|
||||||
|
sMoveCom.runType = config.RType;
|
||||||
|
sMoveCom.endType = config.EType;
|
||||||
|
// 从SkillView获取移动参数,位置初始化由SMoveSystem统一处理
|
||||||
|
sMoveCom.atk_x = SView.atk_x;
|
||||||
|
sMoveCom.atk_y = SView.atk_y;
|
||||||
|
|
||||||
let cAttrsComp=caster.ent.get(HeroAttrsComp)
|
let cAttrsComp=caster.ent.get(HeroAttrsComp)
|
||||||
// 初始化数据组件
|
// 初始化数据组件
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
|
|||||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
import { DTType, EType, RType, SkillConfig, SkillSet } from "../common/config/SkillSet";
|
import { DTType, EType, RType, SkillConfig, SkillSet } from "../common/config/SkillSet";
|
||||||
import { BezierMove } from "../BezierMove/BezierMove";
|
|
||||||
import { BoxSet, FacSet } from "../common/config/BoxSet";
|
import { BoxSet, FacSet } from "../common/config/BoxSet";
|
||||||
import { SDataCom } from "./SDataCom";
|
import { SDataCom } from "./SDataCom";
|
||||||
import { SMoveDataComp } from "./SMoveComp";
|
import { SMoveDataComp } from "./SMoveComp";
|
||||||
@@ -24,10 +23,6 @@ export class SkillView extends CCComp {
|
|||||||
atk_x: number = 0
|
atk_x: number = 0
|
||||||
@property({ type: CCInteger })
|
@property({ type: CCInteger })
|
||||||
atk_y: number = 0
|
atk_y: number = 0
|
||||||
@property({ type: CCInteger })
|
|
||||||
runType: RType = 0 //技能运行类型 0-线性 1-贝塞尔 2-开始位置固定 3-目标位置固定
|
|
||||||
@property({ type: CCInteger })
|
|
||||||
endType: EType = 0 //
|
|
||||||
|
|
||||||
anim:Animation=null;
|
anim:Animation=null;
|
||||||
group:number=0;
|
group:number=0;
|
||||||
@@ -44,87 +39,30 @@ export class SkillView extends CCComp {
|
|||||||
collider.group = this.group;
|
collider.group = this.group;
|
||||||
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
||||||
}
|
}
|
||||||
const SMove=this.ent.get(SMoveDataComp)
|
if(this.node.getComponent(Animation)){
|
||||||
// 计算延长后的目标点坐标
|
let anim = this.node.getComponent(Animation);
|
||||||
|
//console.log("[SkillCom]:has anim",anim)
|
||||||
switch(this.runType){
|
anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
|
||||||
case RType.linear:
|
|
||||||
SMove.rePos(v3(this.node.position.x + this.atk_x, this.node.position.y + this.atk_y))
|
|
||||||
this.do_linear(SMove.startPos,SMove.targetPos)
|
|
||||||
break
|
|
||||||
case RType.bezier:
|
|
||||||
this.do_bezier(SMove.startPos,SMove.targetPos)
|
|
||||||
break
|
|
||||||
case RType.fixed:
|
|
||||||
this.do_fixedStart(SMove.startPos,SMove.targetPos)
|
|
||||||
break
|
|
||||||
case RType.fixedEnd:
|
|
||||||
this.do_fixedEnd(SMove.startPos,SMove.targetPos)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
onBeginContact (seCol: Collider2D, oCol: Collider2D) {
|
onBeginContact (seCol: Collider2D, oCol: Collider2D) {
|
||||||
// console.log(this.scale+"碰撞开始 ",seCol,oCol);
|
// console.log(this.scale+"碰撞开始 ",seCol,oCol);
|
||||||
if(this.endType!=EType.collision) return
|
if(this.SConf.EType!=EType.collision) return
|
||||||
let target = oCol.getComponent(HeroViewComp)
|
let target = oCol.getComponent(HeroViewComp)
|
||||||
let model=target.ent.get(HeroAttrsComp)
|
let model=target.ent.get(HeroAttrsComp)
|
||||||
if(model.is_dead) return
|
if(model.is_dead) return
|
||||||
if(oCol.group!=this.group){
|
if(oCol.group!=this.group){
|
||||||
if(target == null) return;
|
if(target == null) return;
|
||||||
if (!this.SConf) return;
|
if (!this.SConf) return;
|
||||||
if(this.endType==EType.collision){
|
if(this.SConf.EType==EType.collision){
|
||||||
this.apply_damage(target)
|
this.apply_damage(target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_bezier(startPos:Vec3,targetPos:Vec3){
|
|
||||||
let bm=this.node.getComponent(BezierMove)
|
|
||||||
this.node.angle +=10
|
|
||||||
// bm.speed=700
|
|
||||||
if(this.group==BoxSet.MONSTER) {bm.controlPointSide=-1 }
|
|
||||||
bm.rotationSmoothness=0.6
|
|
||||||
bm.moveTo(targetPos)
|
|
||||||
}
|
|
||||||
do_linear(startPos:Vec3,targetPos:Vec3){
|
|
||||||
let bm=this.node.getComponent(BezierMove)
|
|
||||||
let s_x=startPos.x
|
|
||||||
let s_y=startPos.y
|
|
||||||
let t_x=targetPos.x
|
|
||||||
let t_y=targetPos.y
|
|
||||||
// 设定目标x
|
|
||||||
targetPos.x = 400;
|
|
||||||
if(this.group == BoxSet.MONSTER) {
|
|
||||||
bm.controlPointSide = -1;
|
|
||||||
targetPos.x = -400;
|
|
||||||
}
|
|
||||||
// 计算斜率
|
|
||||||
const k = (t_y - s_y) / (t_x - s_x);
|
|
||||||
// 按直线公式计算新的y
|
|
||||||
targetPos.y = k * (targetPos.x - s_x) + s_y;
|
|
||||||
bm.controlPointOffset=0
|
|
||||||
bm.rotationSmoothness=0.6
|
|
||||||
bm.moveTo(targetPos);
|
|
||||||
}
|
|
||||||
do_fixedEnd(startPos:Vec3,targetPos:Vec3){
|
|
||||||
this.node.setPosition(targetPos.x > 360?300:targetPos.x,this.node.position.y,0)
|
|
||||||
this.do_anim()
|
|
||||||
}
|
|
||||||
do_fixedStart(startPos:Vec3,targetPos:Vec3){
|
|
||||||
// console.log("do_fixedStart",startPos,targetPos)
|
|
||||||
this.node.setPosition(startPos.x,this.node.position.y,0)
|
|
||||||
this.do_anim()
|
|
||||||
}
|
|
||||||
do_anim(){
|
|
||||||
if(this.node.getComponent(Animation)){
|
|
||||||
let anim = this.node.getComponent(Animation);
|
|
||||||
//console.log("[SkillCom]:has anim",anim)
|
|
||||||
anim.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onAnimationFinished(){
|
onAnimationFinished(){
|
||||||
if(this.endType==EType.animationEnd){
|
if(this.SConf.EType==EType.animationEnd){
|
||||||
this.ent.destroy()
|
this.ent.destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +134,7 @@ export class SkillView extends CCComp {
|
|||||||
this.sData.hit_count++
|
this.sData.hit_count++
|
||||||
|
|
||||||
// 检查技能是否应该销毁
|
// 检查技能是否应该销毁
|
||||||
if( this.sData.hit_count>=(this.SConf.hit+ this.sData.Attrs[Attrs.PUNCTURE])&&(this.SConf.DTType!=DTType.range)&&(this.endType!=EType.animationEnd)&&(this.endType!=EType.timeEnd)) this.ent.destroy// 技能命中次数
|
if( this.sData.hit_count>=(this.SConf.hit+ this.sData.Attrs[Attrs.PUNCTURE])&&(this.SConf.DTType!=DTType.range)&&(this.SConf.EType!=EType.animationEnd)&&(this.SConf.EType!=EType.timeEnd)) this.ent.destroy// 技能命中次数
|
||||||
}
|
}
|
||||||
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
/** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */
|
||||||
reset() {
|
reset() {
|
||||||
|
|||||||
Reference in New Issue
Block a user