using System.Collections.Generic; using Cielonos.MainGame.Characters; using Cielonos.MainGame.Inventory; using Lean.Pool; using UnityEngine; namespace Cielonos.MainGame { public partial class Projectile : AttackAreaBase { protected bool ignoreEnvironment = false; protected int maximumPenetrateCount = 1; protected int currentPenetrateCount = 0; public virtual Projectile Initialize(CharacterBase creator, bool ignoreEnvironment, int penetrateCount = 1, params Fraction[] targetFractions) { return Initialize(creator, null, ignoreEnvironment, penetrateCount, targetFractions); } public virtual Projectile Initialize(CharacterBase creator, ItemBase itemSource, bool ignoreEnvironment, int penetrateCount = 1, params Fraction[] targetFractions) { Projectile projectile = base.Initialize(creator, itemSource, targetFractions); projectile.ignoreEnvironment = ignoreEnvironment; projectile.maximumPenetrateCount = penetrateCount; return projectile; } private void OnTriggerStay(Collider other) { if (raycastSm != null) { HitCharacter(other, default); HitEnvironment(other, default); } } public override void HitCharacter(Collider characterCollider, Vector3 hitPosition) { // 既不在伤害阶段也不在反应窗口,直接跳过 if (!isEnabling && !isReactionActive) { return; } CharacterBase targetCharacter = characterCollider.GetComponentInParent(); if (!IsValidTarget(targetCharacter)) return; // 已在 grace window 期间成功反应的目标不再处理 if (reactedTargets.Contains(targetCharacter.gameObject)) { return; } if (hitSm.checkedObjects.Contains(targetCharacter.gameObject)) { return; } // 仅在反应窗口内(enable 阶段之前或之后),只做反应检测 if (!isEnabling && isReactionActive) { HitOnTarget(characterCollider, hitPosition, out Attack.Result graceResult, onlyCheckReaction: true); if (graceResult.isBlocked || graceResult.isDodged) { reactedTargets.Add(targetCharacter.gameObject); hitSm.AddCheckedObject(targetCharacter.gameObject); } return; } // 正常 enable 阶段:造成伤害 hitSm.AddCheckedObject(targetCharacter.gameObject); HitOnTarget(characterCollider, hitPosition, out _); } public override void HitEnvironment(Collider other, Vector3 hitPosition) { if (ignoreEnvironment) { return; } if (other.gameObject.layer == LayerMask.NameToLayer("Default") || other.gameObject.layer == LayerMask.NameToLayer("Ground") || other.gameObject.layer == LayerMask.NameToLayer("Wall") || other.gameObject.layer == LayerMask.NameToLayer("FadableEnvironment") || other.gameObject.layer == LayerMask.NameToLayer("UnfadableEnvironment")) { //特效 GenerateHitEffect(hitPosition); //音效 PlaySoundFX(hitPosition); LeanPool.Despawn(topParent.gameObject); } } } public partial class Projectile { protected override void HitOnTarget(Collider hitCollider, Vector3 hitPosition, out Attack.Result result, bool onlyCheckReaction = false) { base.HitOnTarget(hitCollider, hitPosition, out result, onlyCheckReaction); if (onlyCheckReaction) return; if (!result.isReflected && ++currentPenetrateCount >= maximumPenetrateCount) { LeanPool.Despawn(topParent.gameObject); } } public void Explode(Vector3 hitPosition = default) { if (hitPosition == default) { hitPosition = transform.position; } GenerateHitEffect(hitPosition); PlaySoundFX(hitPosition); LeanPool.Despawn(topParent.gameObject); } } public partial class Projectile { public void Reflect(CharacterBase newCreator, Vector3 newDirection = default, float newSpeed = 50f) { CharacterBase originalCreator = creator; newDirection = newDirection == default ? (originalCreator.CenterPosition - transform.position).normalized : newDirection; SetLinearDirectionMoveModule(newDirection, 50f); this.creator = newCreator; targetFractions = new List { originalCreator.fraction }; } } }