using UnityEngine; using BaseGames.Core; using BaseGames.Core.Pool; namespace BaseGames.Combat { /// /// 抛射物基类。子类通过重写 设定初速度。 /// 依赖 子组件进行碰撞伤害检测。 /// [RequireComponent(typeof(Rigidbody2D), typeof(HitBox))] public abstract class Projectile : MonoBehaviour { [HideInInspector] public DamageInfo DamageInfo; [HideInInspector] public Vector2 Direction; protected ProjectileConfigSO _config; protected Rigidbody2D _rb; protected HitBox _hitBox; protected float _aliveTimer; private PooledObject _pooledObject; protected virtual void Awake() { _rb = GetComponent(); _hitBox = GetComponent(); _pooledObject = GetComponent(); } /// 从对象池取出后的初始化入口。 public virtual void Initialize(ProjectileConfigSO config, DamageInfo damageInfo, Vector2 direction, int ownerLayer = 0) { _config = config; DamageInfo = damageInfo; Direction = direction.normalized; _aliveTimer = 0f; SetFactionLayer(ownerLayer); _hitBox.Activate(config.DamageSource); OnInitialized(); } /// 根据发射方所在 Layer 切换到对应的 PlayerProjectile / EnemyProjectile 层。 private void SetFactionLayer(int ownerLayer) { int playerLayer = LayerMask.NameToLayer("Player"); int playerProjLayer = LayerMask.NameToLayer("PlayerProjectile"); int enemyProjLayer = LayerMask.NameToLayer("EnemyProjectile"); if (playerProjLayer < 0 || enemyProjLayer < 0) return; // Layer 尚未创建,保留现有层 gameObject.layer = (ownerLayer == playerLayer) ? playerProjLayer : enemyProjLayer; } /// /// 弹反:将投射物阵营从 EnemyProjectile 切换为 PlayerProjectile。 /// 反转飞行方向,并重置 HitBox 命中记录使其能够命中新目标(敌人)。 /// 由 HurtBox.ReceiveDamage() 在弹反成功后调用。 /// public virtual void ReflectAsPlayerProjectile() { int playerProjLayer = LayerMask.NameToLayer("PlayerProjectile"); if (playerProjLayer < 0) return; gameObject.layer = playerProjLayer; Direction = -Direction; _rb.velocity = -_rb.velocity; // 重置 HitBox 命中记录,确保反射后可命中新目标 _hitBox.Deactivate(); _hitBox.Activate(_config?.DamageSource); } protected virtual void OnInitialized() { } protected virtual void Update() { _aliveTimer += Time.deltaTime; if (_config != null && _aliveTimer >= _config.Lifetime) ReturnToPool(); } /// 停用并归还对象池。 protected void ReturnToPool() { _hitBox.Deactivate(); gameObject.SetActive(false); if (_pooledObject != null && _config != null) ServiceLocator.GetOrDefault()?.Despawn(_config.PoolKey, _pooledObject); } protected virtual void OnDisable() { _aliveTimer = 0f; } } }