97 lines
3.5 KiB
C#
97 lines
3.5 KiB
C#
using UnityEngine;
|
|
using BaseGames.Core;
|
|
using BaseGames.Core.Pool;
|
|
|
|
namespace BaseGames.Combat
|
|
{
|
|
/// <summary>
|
|
/// 抛射物基类。子类通过重写 <see cref="OnInitialized"/> 设定初速度。
|
|
/// 依赖 <see cref="HitBox"/> 子组件进行碰撞伤害检测。
|
|
/// </summary>
|
|
[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<Rigidbody2D>();
|
|
_hitBox = GetComponent<HitBox>();
|
|
_pooledObject = GetComponent<PooledObject>();
|
|
}
|
|
|
|
/// <summary>从对象池取出后的初始化入口。</summary>
|
|
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();
|
|
}
|
|
|
|
/// <summary>根据发射方所在 Layer 切换到对应的 PlayerProjectile / EnemyProjectile 层。</summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 弹反:将投射物阵营从 EnemyProjectile 切换为 PlayerProjectile。
|
|
/// 反转飞行方向,并重置 HitBox 命中记录使其能够命中新目标(敌人)。
|
|
/// 由 HurtBox.ReceiveDamage() 在弹反成功后调用。
|
|
/// </summary>
|
|
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();
|
|
}
|
|
|
|
/// <summary>停用并归还对象池。</summary>
|
|
protected void ReturnToPool()
|
|
{
|
|
_hitBox.Deactivate();
|
|
gameObject.SetActive(false);
|
|
if (_pooledObject != null && _config != null)
|
|
ServiceLocator.GetOrDefault<IObjectPoolService>()?.Despawn(_config.PoolKey, _pooledObject);
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
_aliveTimer = 0f;
|
|
}
|
|
}
|
|
}
|