220 lines
5.6 KiB
C#
220 lines
5.6 KiB
C#
using System;
|
||
using DragonLi.Core;
|
||
using DragonLi.Frame;
|
||
using Mirror;
|
||
using UnityEngine;
|
||
|
||
public class Bullet : NetworkBehaviour
|
||
{
|
||
/// <summary>
|
||
/// 子弹类型
|
||
/// </summary>
|
||
#if UNITY_EDITOR
|
||
[DisplayOnly]
|
||
#endif
|
||
public BulletType type;
|
||
|
||
[Header("伤害")]
|
||
#if UNITY_EDITOR
|
||
[DisplayOnly]
|
||
#endif
|
||
public float damage = 0;
|
||
|
||
[Header("破韧")]
|
||
#if UNITY_EDITOR
|
||
[DisplayOnly]
|
||
#endif
|
||
public float deToughness = 0;
|
||
|
||
[Header("击中删除时间")]
|
||
public float despawn_delay = 0.1f;
|
||
[Header("自动删除时间")]
|
||
public float auto_despawn_delay = 5f;
|
||
|
||
[Header("撞击预制体")]
|
||
public GameObject impact_prefab;
|
||
[Header("撞击删除时间")]
|
||
public float impact_despawn_time = 1f;
|
||
|
||
[Header("是否使用重力")]
|
||
public bool use_gravity = false;
|
||
public bool hit_trigger = false;
|
||
|
||
[Header("目标图层")]
|
||
public LayerMask HitLayer;
|
||
|
||
#if UNITY_EDITOR
|
||
[DisplayOnly]
|
||
#endif
|
||
public int ownerIndex;
|
||
|
||
private Rigidbody rigidbodyComponent;
|
||
/// <summary>
|
||
/// 刚体组件
|
||
/// </summary>
|
||
public Rigidbody RigidbodyComponent
|
||
{
|
||
get
|
||
{
|
||
if (rigidbodyComponent == null)
|
||
{
|
||
rigidbodyComponent = GetComponentInChildren<Rigidbody>();
|
||
}
|
||
return rigidbodyComponent;
|
||
}
|
||
}
|
||
|
||
private bool _isHit = false;
|
||
private bool _isValid = true;
|
||
private float _despawnTime = 0f;
|
||
private RaycastHit _handlingHit;
|
||
|
||
#region 生命周期
|
||
public void Awake()
|
||
{
|
||
RigidbodyComponent.useGravity = use_gravity;
|
||
RigidbodyComponent.constraints = (RigidbodyConstraints)112;
|
||
}
|
||
|
||
public void OnEnable()
|
||
{
|
||
_isHit = false;
|
||
_isValid = true;
|
||
_despawnTime = Time.time + auto_despawn_delay;
|
||
}
|
||
|
||
public void Update()
|
||
{
|
||
if (isServer)
|
||
{
|
||
if (_isValid)
|
||
{
|
||
if (_isHit)
|
||
{
|
||
DespawnSelf();
|
||
return;
|
||
}
|
||
if (_despawnTime < Time.time)
|
||
{
|
||
_isValid = false;
|
||
NetworkServer.Destroy(transform.gameObject);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
internal void FixedUpdate()
|
||
{
|
||
if (isServer && !_isHit && HitCheck())
|
||
{
|
||
// Debug.Log("撞击");
|
||
_isHit = true;
|
||
SpawnImpact();
|
||
ApplyDamage();
|
||
}
|
||
OnFixedUpdate();
|
||
}
|
||
|
||
/// <summary>
|
||
/// This will be called when fixedupdate called
|
||
/// </summary>
|
||
protected virtual void OnFixedUpdate() { }
|
||
|
||
#endregion
|
||
|
||
[Server]
|
||
public virtual void OnSpawn(int curOwnerIndex, Vector3 recoil, float recoilCount)
|
||
{
|
||
if (curOwnerIndex != -1)
|
||
ownerIndex = curOwnerIndex;
|
||
rigidbodyComponent.velocity = recoil.normalized * recoilCount;
|
||
rigidbodyComponent.rotation = Quaternion.LookRotation(recoil.normalized);
|
||
}
|
||
|
||
|
||
[Server]
|
||
public virtual void OnSpawn( Vector3 targetPos, float speed)
|
||
{
|
||
// 计算方向(忽略 Y 轴,让子弹水平飞行)
|
||
Vector3 dir = (targetPos - transform.position);
|
||
dir.y = 0f; // 固定 Y,不让子弹上下飞
|
||
dir.Normalize();
|
||
|
||
// 设置刚体运动
|
||
rigidbodyComponent.velocity = dir * speed;
|
||
rigidbodyComponent.rotation = Quaternion.LookRotation(dir, Vector3.up);
|
||
}
|
||
|
||
[Server]
|
||
public void DespawnSelf()
|
||
{
|
||
_isValid = false;
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(transform.gameObject);
|
||
}, despawn_delay);
|
||
}
|
||
|
||
[Server]
|
||
public virtual void SpawnImpact()
|
||
{
|
||
if (impact_prefab != null)
|
||
{
|
||
GameObject impact = Instantiate(impact_prefab);
|
||
Debug.Log("生成击中点");
|
||
impact.transform.position = _handlingHit.point;
|
||
NetworkServer.Spawn(impact);
|
||
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
|
||
{
|
||
NetworkServer.Destroy(impact);
|
||
}, impact_despawn_time);
|
||
// 碰撞点的法线方向
|
||
Vector3 normal = _handlingHit.normal;
|
||
// 在这里处理特效的生成和方向
|
||
// 计算特效的旋转方向,使用法线信息
|
||
Quaternion rotation = Quaternion.LookRotation(normal);
|
||
// 将特效的旋转方向设置为法线方向
|
||
impact.transform.rotation = rotation;
|
||
}
|
||
}
|
||
|
||
[Server]
|
||
public virtual bool HitCheck()
|
||
{
|
||
Vector3 position = transform.position;
|
||
Vector3 velocity = RigidbodyComponent.velocity * Time.deltaTime;
|
||
if (Physics.Raycast(position, velocity, out _handlingHit, velocity.magnitude, HitLayer))
|
||
{
|
||
if (hit_trigger && _handlingHit.collider.isTrigger)
|
||
{
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
[Server]
|
||
public virtual void ApplyDamage()
|
||
{
|
||
// IDamagable component = _handlingHit.transform.GetComponent<IDamagable>();
|
||
IDamagable component = _handlingHit.transform.GetComponent<IDamagable>();
|
||
if (component != null)
|
||
{
|
||
OnApplyDamage(component);
|
||
}
|
||
|
||
Debug.Log("受伤单位:"+_handlingHit.collider.name);
|
||
Player hitPlayer = _handlingHit.transform.GetComponentInParent<Player>();
|
||
if (hitPlayer != null)
|
||
{
|
||
OnHitPlayer(hitPlayer.index);
|
||
}
|
||
}
|
||
|
||
[Server]
|
||
public virtual void OnApplyDamage(IDamagable damagable) { }
|
||
|
||
[Server]
|
||
public virtual void OnHitPlayer(int index) { }
|
||
} |