消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

404 lines
15 KiB

import { _decorator, Component, Node, Vec3, Vec2, v3, v2, CCInteger, CCFloat, Collider2D, Contact2DType, IPhysics2DContact, RigidBody2D, ERigidBody2DType, sp } from 'cc';
import { BattleDataManager, BezierFallEffectType } from '../BattleDataManager';
import { Monster } from '../Monster';
const { ccclass, property } = _decorator;
// 无人机状态枚举
enum DroneState {
ORBITING, // 轨道飞行
CHASING, // 追击目标
ATTACKING, // 攻击中
RETURNING // 返回轨道
}
@ccclass('Drone')
export class Drone extends Component {
private getDroneManager() {
return this.node.parent?.getComponent('DroneManager') as any;
}
@property
public moveSpeed: number = 300; // 移动速度
@property
public attackRange: number = 100; // 攻击范围
@property
public attackDamage: number = 20; // 攻击力
@property
public attackInterval: number = 1; // 攻击间隔(秒)
@property
public orbitSpeed: number = 1; // 轨道旋转速度(弧度/秒)
@property(Node)
public bulletLaunchNode: Node | null = null; // 子弹发射节点
private currentState: DroneState = DroneState.ORBITING;
private orbitParams: {center: Vec3, a: number, b: number} = {
center: new Vec3(200, 360, 0), // 椭圆中心
a: 150, // 长轴
b: 100 // 短轴
};
private orbitAngle: number = 0; // 轨道角度
private targetMonster: Node | null = null;
private attackTimer: number = 0;
private returnPoint: Vec3 = new Vec3();
private positionOffset: Vec3 = new Vec3(); // 用于避免重叠的偏移
private _tmpOrbitPos: Vec3 = new Vec3();
private _tmpTargetPos: Vec3 = new Vec3();
private _targetMonsterComp: Monster | null = null;
private _offsetRecalcTimer = 0;
private _offsetRecalcInterval = 0.12;
private fuelCount: number = 0; // 燃油计数
_sk:sp.Skeleton = null!;
curAnimationName = ''
protected onLoad(): void {
this._sk = this.node.getComponentInChildren(sp.Skeleton)
}
/**
* 播放 Spine 动画
* @param name 动画名称
* @param callback 动画播放完成后的回调函数
* @param timeScale 动画播放速度倍率
* @param loop 是否循环播放
*/
private playSpine(name: string, callback: Function = null, timeScale = 1, loop = true) {
// 如果节点不存在,则直接返回
if (this.node == null) return;
// 设置动画播放完成后的回调函数
// this._sk.setCompleteListener(() => {
// if (callback) callback();
// });
// 设置动画播放速度倍率,考虑了战斗速度的影响
// this._sk.timeScale = timeScale * 1//BattleManager.Instance.LevelBattle.BattleSpeed;
// 播放指定名称的动画,并设置是否循环播放
this._sk.setAnimation(0, name, loop);
}
playEffect(){
let nameStr = ''
if(this.currentState == DroneState.ATTACKING){
nameStr = '1无人机漂浮'
}else{
nameStr = '2无人机原地飞'
}
if(this.curAnimationName != nameStr){
this.curAnimationName = nameStr
this.playSpine(nameStr)
}
}
// 初始化无人机轨道参数
public init(orbitCenter: Vec3, a: number, b: number, startAngle: number) {
this.orbitParams.center = orbitCenter;
this.orbitParams.a = a;
this.orbitParams.b = b;
this.orbitAngle = startAngle;
// 设置初始位置
const startPos = this.calculateOrbitPosition(startAngle);
this.node.setPosition(startPos);
}
// 计算椭圆轨道上的位置
private calculateOrbitPosition(angle: number): Vec3 {
const x = this.orbitParams.center.x + this.orbitParams.a * Math.cos(angle);
const y = this.orbitParams.center.y + this.orbitParams.b * Math.sin(angle);
this._tmpOrbitPos.x = x;
this._tmpOrbitPos.y = y;
this._tmpOrbitPos.z = 0;
return this._tmpOrbitPos;
}
update(deltaTime: number) {
if (!gg.game.CurentBattle.canUpdateFrame()) return;
const scaledDt = deltaTime * gg.game.CurentBattle.TimeScale;
this.playEffect()
switch (this.currentState) {
case DroneState.ORBITING:
this.updateOrbiting(scaledDt);
break;
case DroneState.CHASING:
this.updateChasing(scaledDt);
break;
case DroneState.ATTACKING:
this.updateAttacking(scaledDt);
break;
case DroneState.RETURNING:
this.updateReturning(scaledDt);
break;
}
}
// 寻找攻击范围内的怪物
private findTarget(){
// const monsters = find('Monsters')?.getComponentsInChildren(Monster) || [];
// const dronePos = this.node.position;
// for (const monster of monsters) {
// if (!monster.node.active) continue;
// const distance = Vec3.distance(dronePos, monster.node.position);
// if (distance <= this.attackRange) {
// return monster;
// }
// }
// return null;
let monster = gg.game.CurentBattle.MonsterSpawner.getDroneTargetMonster(this.node,this.attackRange);
return monster;
}
// 检查攻击同一目标的其他无人机
private getSameTargetDrones(): Drone[] {
if (!this.targetMonster) return [];
const allDrones = this.node.parent.getComponentsInChildren(Drone) || [];
return allDrones.filter(drone =>
drone.targetMonster === this.targetMonster &&
(drone.currentState === DroneState.ATTACKING || drone.currentState === DroneState.CHASING)
);
}
// 更新位置偏移以避免重叠
private updatePositionOffset() {
const sameTargetDrones = this.getSameTargetDrones();
const totalCount = sameTargetDrones.length + 1; // 包括自己
if (totalCount <= 1) {
this.positionOffset.set(0, 0, 0);
return;
}
// 计算偏移角度,形成圆形分布
const index = sameTargetDrones.indexOf(this);
// const angle = (index + 1) * (Math.PI * 2 / totalCount);
const offsetDistance = 50; // 偏移距离,小于无人机一半大小(25)
let x = -(totalCount-1)*offsetDistance/2 + index*offsetDistance;
this.positionOffset.set(x, 0, 0);
// this.positionOffset.set(
// Math.cos(angle) * offsetDistance,
// Math.sin(angle) * offsetDistance,
// 0
// );
}
// 移动到目标位置
private moveToTarget(targetPos: Vec3, deltaTime: number): boolean {
const currentPos = this.node.position;
const dx = targetPos.x - currentPos.x;
const dy = targetPos.y - currentPos.y;
const dz = targetPos.z - currentPos.z;
const distSq = dx * dx + dy * dy + dz * dz;
const moveStep = this.moveSpeed * deltaTime;
const moveStepSq = moveStep * moveStep;
if (distSq <= moveStepSq) {
this.node.setPosition(targetPos.x, targetPos.y, targetPos.z);
return true;
}
const dist = Math.sqrt(distSq);
const ratio = moveStep / dist;
this.node.setPosition(
currentPos.x + dx * ratio,
currentPos.y + dy * ratio,
currentPos.z + dz * ratio
);
return false;
}
// 寻找最近的轨道点
private findNearestOrbitPoint(): Vec3 {
const currentPos = this.node.position;
let nearestAngle = 0;
let minDistance = Infinity;
// 采样多个角度找到最近点
for (let angle = 0; angle < Math.PI * 2; angle += 0.1) {
const pos = this.calculateOrbitPosition(angle);
const dist = Vec3.distance(currentPos, pos);
if (dist < minDistance) {
minDistance = dist;
nearestAngle = angle;
}
}
this.orbitAngle = nearestAngle;
return this.calculateOrbitPosition(nearestAngle);
}
// 轨道飞行状态更新
private updateOrbiting(deltaTime: number) {
// 检查是否有可攻击目标
const target = this.findTarget();
if (target) {
this.targetMonster = target;
this._targetMonsterComp = target.getComponent(Monster);
this.currentState = DroneState.CHASING;
this._offsetRecalcTimer = this._offsetRecalcInterval;
return;
}
// 沿椭圆轨道移动
this.orbitAngle += this.orbitSpeed * deltaTime;
if (this.orbitAngle >= Math.PI * 2) {
this.orbitAngle -= Math.PI * 2;
}
const newPos = this.calculateOrbitPosition(this.orbitAngle);
this.node.setPosition(newPos);
}
// 追击状态更新
private updateChasing(deltaTime: number) {
if (!this.targetMonster || !this.targetMonster.isValid) {
this._targetMonsterComp = null;
this.currentState = DroneState.RETURNING;
this.returnPoint = this.findNearestOrbitPoint();
return;
}
if (!this._targetMonsterComp) this._targetMonsterComp = this.targetMonster.getComponent(Monster);
if (this._targetMonsterComp?.getIsDead()) {
this._targetMonsterComp = null;
this.currentState = DroneState.RETURNING;
this.returnPoint = this.findNearestOrbitPoint();
return;
}
// 计算目标上方50单位的位置并应用偏移
this._offsetRecalcTimer += deltaTime;
if (this._offsetRecalcTimer >= this._offsetRecalcInterval) {
this._offsetRecalcTimer = 0;
this.updatePositionOffset();
}
const tp = this.targetMonster.position;
this._tmpTargetPos.x = tp.x + this.positionOffset.x;
this._tmpTargetPos.y = tp.y + 200 + this.positionOffset.y;
this._tmpTargetPos.z = tp.z + this.positionOffset.z;
// 移动到目标位置
const reached = this.moveToTarget(this._tmpTargetPos, deltaTime);
if (reached) {
this.currentState = DroneState.ATTACKING;
this._offsetRecalcTimer = this._offsetRecalcInterval;
this.attackTimer = 0;
}
}
// 攻击状态更新
private updateAttacking(deltaTime: number) {
if (!this.targetMonster || !this.targetMonster.isValid) {
this._targetMonsterComp = null;
// 目标已消失,检查新目标
const newTarget = this.findTarget();
if (newTarget) {
this.targetMonster = newTarget;
this._targetMonsterComp = newTarget.getComponent(Monster);
this.currentState = DroneState.CHASING;
this._offsetRecalcTimer = this._offsetRecalcInterval;
} else {
this.currentState = DroneState.RETURNING;
this._targetMonsterComp = null;
this.returnPoint = this.findNearestOrbitPoint();
}
return;
}
if (!this._targetMonsterComp) this._targetMonsterComp = this.targetMonster.getComponent(Monster);
if (this._targetMonsterComp?.getIsDead()) {
const newTarget = this.findTarget();
if (newTarget) {
this.targetMonster = newTarget;
this._targetMonsterComp = newTarget.getComponent(Monster);
this.currentState = DroneState.CHASING;
this._offsetRecalcTimer = this._offsetRecalcInterval;
} else {
this.currentState = DroneState.RETURNING;
this._targetMonsterComp = null;
this.returnPoint = this.findNearestOrbitPoint();
}
return;
}
// 保持在目标上方
this._offsetRecalcTimer += deltaTime;
if (this._offsetRecalcTimer >= this._offsetRecalcInterval) {
this._offsetRecalcTimer = 0;
this.updatePositionOffset();
}
const tp = this.targetMonster.position;
this.node.setPosition(
tp.x + this.positionOffset.x,
tp.y + 200 + this.positionOffset.y,
tp.z + this.positionOffset.z
);
// 攻击计时器
// this.attackTimer += deltaTime;
// if (this.attackTimer >= this.attackInterval) {
// this.attackTimer = 0;
// this.attackTarget();
// }
}
// 返回轨道状态更新
private updateReturning(deltaTime: number) {
// 检查是否有新目标
const newTarget = this.findTarget();
if (newTarget) {
this.targetMonster = newTarget;
this._targetMonsterComp = newTarget.getComponent(Monster);
this.currentState = DroneState.CHASING;
this._offsetRecalcTimer = this._offsetRecalcInterval;
return;
}
// 返回轨道
const reached = this.moveToTarget(this.returnPoint, deltaTime);
if (reached) {
this.currentState = DroneState.ORBITING;
this.targetMonster = null;
this._targetMonsterComp = null;
}
}
// 攻击目标
public attackTarget(weaponId:number) {
if (this.currentState == DroneState.ATTACKING && this.targetMonster && this.targetMonster.isValid && !this.targetMonster.getComponent(Monster).getIsDead()) {
// console.log("攻击目标attackTarget");
let now = new Date().getTime()
const manager = this.getDroneManager();
if(manager && now - manager.audio_timeStamp > 140){
manager.audio_timeStamp = now
gg.audio.playEffect({ name: '无人机攻击',path:'sound/武器音效/'});
}
let isFuelBomb = false
//特殊技能(丢燃烧弹)
let weaponPropertyData = BattleDataManager.getWeaponAddProperty(weaponId)
let specialSkillAddFallEffectInfo = weaponPropertyData.specialSkillAddFallEffectInfo
for(let i = 0;i<specialSkillAddFallEffectInfo.length;i++){
let buffInfo = specialSkillAddFallEffectInfo[i]
let arr = buffInfo.split(',')
let buffType = Number(arr[0])
//落地添加燃烧区域
if(buffType == BezierFallEffectType.fallBombBurnArea){
let atkCount = Number(arr[7])//多少次普攻发射一次燃油弹
this.fuelCount++
if(this.fuelCount >= atkCount){
isFuelBomb = true
this.fuelCount = 0;
gg.game.CurentBattle.SkillController.executeDroneWeaponSkill(weaponId,this.bulletLaunchNode.worldPosition.clone().add(v3(0,-20,0)),this.targetMonster.position.clone(),true)
break
}
}
}
if(!isFuelBomb){
gg.game.CurentBattle.SkillController.executeDroneWeaponSkill(weaponId,this.bulletLaunchNode.worldPosition.clone().add(v3(0,-20,0)),this.targetMonster.position.clone(),false)
}
}
}
}