2026-02-13 09:22:11 -05:00
|
|
|
|
using System.Collections.Generic;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
using Cielonos.MainGame.Characters;
|
2026-05-23 08:27:50 -04:00
|
|
|
|
using Cielonos.MainGame.Inventory;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
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<Projectile>(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)
|
|
|
|
|
|
{
|
2026-06-12 17:11:39 -04:00
|
|
|
|
// 既不在伤害阶段也不在反应窗口,直接跳过
|
|
|
|
|
|
if (!isEnabling && !isReactionActive)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CharacterBase targetCharacter = characterCollider.GetComponentInParent<CharacterBase>();
|
|
|
|
|
|
|
2026-05-23 08:27:50 -04:00
|
|
|
|
if (!IsValidTarget(targetCharacter)) return;
|
|
|
|
|
|
|
2026-06-12 17:11:39 -04:00
|
|
|
|
// 已在 grace window 期间成功反应的目标不再处理
|
|
|
|
|
|
if (reactedTargets.Contains(targetCharacter.gameObject))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-23 08:27:50 -04:00
|
|
|
|
if (hitSm.checkedObjects.Contains(targetCharacter.gameObject))
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-05-23 08:27:50 -04:00
|
|
|
|
return;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
2026-05-23 08:27:50 -04:00
|
|
|
|
|
2026-06-12 17:11:39 -04:00
|
|
|
|
// 仅在反应窗口内(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 阶段:造成伤害
|
2026-05-23 08:27:50 -04:00
|
|
|
|
hitSm.AddCheckedObject(targetCharacter.gameObject);
|
|
|
|
|
|
HitOnTarget(characterCollider, hitPosition, out _);
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void HitEnvironment(Collider other, Vector3 hitPosition)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ignoreEnvironment)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-08 05:27:53 -05:00
|
|
|
|
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"))
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
|
|
|
|
|
//特效
|
|
|
|
|
|
GenerateHitEffect(hitPosition);
|
|
|
|
|
|
//音效
|
|
|
|
|
|
PlaySoundFX(hitPosition);
|
|
|
|
|
|
|
|
|
|
|
|
LeanPool.Despawn(topParent.gameObject);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public partial class Projectile
|
|
|
|
|
|
{
|
2026-06-12 17:11:39 -04:00
|
|
|
|
protected override void HitOnTarget(Collider hitCollider, Vector3 hitPosition, out Attack.Result result,
|
|
|
|
|
|
bool onlyCheckReaction = false)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
2026-06-12 17:11:39 -04:00
|
|
|
|
base.HitOnTarget(hitCollider, hitPosition, out result, onlyCheckReaction);
|
|
|
|
|
|
|
|
|
|
|
|
if (onlyCheckReaction) return;
|
2025-11-25 08:19:33 -05:00
|
|
|
|
|
2026-05-23 08:27:50 -04:00
|
|
|
|
if (!result.isReflected && ++currentPenetrateCount >= maximumPenetrateCount)
|
2025-11-25 08:19:33 -05:00
|
|
|
|
{
|
|
|
|
|
|
LeanPool.Despawn(topParent.gameObject);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-08 05:27:53 -05:00
|
|
|
|
|
2025-12-24 16:58:51 -05:00
|
|
|
|
public void Explode(Vector3 hitPosition = default)
|
2025-12-08 05:27:53 -05:00
|
|
|
|
{
|
2025-12-24 16:58:51 -05:00
|
|
|
|
if (hitPosition == default)
|
|
|
|
|
|
{
|
|
|
|
|
|
hitPosition = transform.position;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-08 05:27:53 -05:00
|
|
|
|
GenerateHitEffect(hitPosition);
|
|
|
|
|
|
PlaySoundFX(hitPosition);
|
|
|
|
|
|
LeanPool.Despawn(topParent.gameObject);
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|
2026-02-13 09:22:11 -05:00
|
|
|
|
|
|
|
|
|
|
public partial class Projectile
|
|
|
|
|
|
{
|
|
|
|
|
|
public void Reflect(CharacterBase newCreator, Vector3 newDirection = default, float newSpeed = 50f)
|
|
|
|
|
|
{
|
|
|
|
|
|
CharacterBase originalCreator = creator;
|
2026-06-05 04:21:00 -04:00
|
|
|
|
newDirection = newDirection == default ? (originalCreator.CenterPosition - transform.position).normalized : newDirection;
|
2026-02-13 09:22:11 -05:00
|
|
|
|
SetLinearDirectionMoveModule<Projectile>(newDirection, 50f);
|
|
|
|
|
|
this.creator = newCreator;
|
|
|
|
|
|
targetFractions = new List<Fraction> { originalCreator.fraction };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-25 08:19:33 -05:00
|
|
|
|
}
|