import { _decorator, Component } from 'cc'; import { HitEffectConfig, HitResult } from '../BulletTypes'; const { ccclass } = _decorator; /** * 命中效果(可移植版):纯逻辑整合,不直接与敌人系统耦合 */ @ccclass('BCBulletHitEffect') export class BulletHitEffect extends Component { private effects: HitEffectConfig[] = []; private remainingPierce = 0; private remainingRicochet = 0; public init(effects: HitEffectConfig[]) { this.effects = [...(effects ?? [])].sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0)); // 初始化穿透与弹射计数 const pierce = this.effects.find(e => e.type === 'pierce_damage'); const ricochet = this.effects.find(e => e.type === 'ricochet_damage'); this.remainingPierce = Math.max(0, pierce?.pierceCount ?? 0); this.remainingRicochet = Math.max(0, ricochet?.ricochetCount ?? 0); } /** * 计算命中后结果(纯数据),由上层去应用到敌人/场景 */ public applyOnHit(): HitResult { if (!this.effects || this.effects.length === 0) return { didHit: true, damageApplied: 0 }; let damage = 0; let ricochet = false; let ricochetAngle: number | undefined = undefined; let explosion = false; let explosionRadius: number | undefined = undefined; let spawnBurn = false; let burnPayload: HitResult['burn'] = null; for (const e of this.effects) { switch (e.type) { case 'normal_damage': damage += Math.max(0, e.damage ?? 0); break; case 'pierce_damage': damage += Math.max(0, e.damage ?? 0); // 穿透次数在命中后交由生命周期或外层减少 break; case 'ricochet_damage': damage += Math.max(0, e.damage ?? 0); if (this.remainingRicochet > 0) { ricochet = true; ricochetAngle = e.ricochetAngle ?? ricochetAngle; } break; case 'explosion': damage += Math.max(0, e.damage ?? 0); explosion = true; explosionRadius = e.radius ?? explosionRadius; break; case 'ground_burn': // 地面燃烧不直接叠加伤害(由区域 DOT 管理) spawnBurn = true; burnPayload = { damagePerTick: Math.max(0, e.damage ?? 0), duration: Math.max(0, e.duration ?? 0), tickInterval: Math.max(0.05, e.tickInterval ?? 0.5) }; break; } } const res: HitResult = { didHit: true, damageApplied: damage, ricochet, ricochetAngle, pierced: this.remainingPierce > 0, remainingPierce: this.remainingPierce, explosion, explosionRadius, spawnBurn, burn: burnPayload }; return res; } /** 在外层确认穿透后调用,减少计数 */ public consumePierce() { if (this.remainingPierce > 0) this.remainingPierce -= 1; } /** 在外层确认弹射后调用,减少计数 */ public consumeRicochet() { if (this.remainingRicochet > 0) this.remainingRicochet -= 1; } }