Files
Zombie/Assets/_Zombie/Scripts/Guns/Launcher.cs
2025-08-30 18:18:34 +08:00

243 lines
5.9 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using DarkTonic.MasterAudio;
using DragonLi.Core;
using Mirror;
using UnityEngine;
using UnityEngine.XR;
public class Launcher : NetworkBehaviour
{
[Header("枪械类型")]
#if UNITY_EDITOR
[DisplayOnly]
#endif
[SyncVar]
public GunType type;
[Header("枪械射速(s)")]
#if UNITY_EDITOR
[DisplayOnly]
#endif
public float shootRate = 10f;
[Header("枪械后坐力")]
#if UNITY_EDITOR
[DisplayOnly]
#endif
public float recoil = 100f;
[Header("子弹创建位置")]
public Transform bulletPoint;
[Header("子弹预制体")]
public GameObject bullet_prefab;
[Header("子弹数量")]
#if UNITY_EDITOR
[DisplayOnly]
#endif
[SyncVar]
public float bullet_amount = 0f;
[SyncVar]
public float bullet_attack = 0f;
[Header("枪械持有位置")]
#if UNITY_EDITOR
[DisplayOnly]
#endif
[SyncVar]
public HandType hand = HandType.Right;
[Header("子弹每次射击量")]
#if UNITY_EDITOR
[DisplayOnly]
#endif
public int bullet_per_shoot = 1;
[Header("开火创建位置")]
public Transform muzzlePoint;
[Header("开火预制体")]
public GameObject muzzle_prefab;
[Header("开火销毁时间")]
public float muzzle_despawn_time = 1;
[Header("开枪音效")]
[SoundGroup]
public string shotSound;
[Header("弹壳创建位置")]
public Transform shellPoint;
[Header("弹壳预制体")]
public GameObject shell_prefab;
[Header("弹壳朝向")]
public float shell_outforce;
[Header("弹壳销毁时间")]
public float shell_despawn_delay;
[NonSerialized]
public InputDevice leftHandDevice;
[NonSerialized]
public InputDevice rightHandDevice;
/// <summary>
/// If time.time is bigger than this value, so the gun can shoot
/// </summary>
[NonSerialized]
[SyncVar]
public float nextShootTime = 0f;
private float _shootInterval = 0f;
public int curOwnerIndex;
public void Awake()
{
_shootInterval = 1f / shootRate;
bullet_amount = -999;
}
public virtual void Start()
{
#if !UNITY_EDITOR
leftHandDevice = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand);
rightHandDevice = InputDevices.GetDeviceAtXRNode(XRNode.RightHand);
#endif
}
[Server]
public void Shoot()
{
Shoot(curOwnerIndex);
}
[Server]
public bool Shoot(int ownerIndex)
{
return Shoot(bulletPoint.position + bulletPoint.forward * 1f, ownerIndex);
}
[Server]
public virtual bool Shoot(Vector3 target, int ownerIndex)
{
// 弹量不够
if (bullet_amount <= 0 && bullet_amount != -999)
{
return false;
}
// 未冷却
if (nextShootTime > Time.time)
{
return false;
}
if (bullet_amount > 0&& GameManager.Ins.gameState==GameState.Playing)
{
bullet_amount--;
EventDispatcher.TriggerEvent("UserGun", bullet_amount);
}
if (bullet_amount <= 0 && bullet_amount != -999)
{
LauncherEmpty();
}
for (int i = 0; i < bullet_per_shoot; i++)
{
SpawnBullet(ownerIndex, target - bulletPoint.position);
}
//GameManager.Ins.PlaySound3DRPC(shotSound,transform,false);
SpawnShell();
SpawnMuzzle();
nextShootTime = Time.time + _shootInterval;
return true;
}
[TargetRpc]
public void LauncherEmpty()
{
GameLocal.Ins.self.DelWeapon();
}
[Server]
public virtual Transform SpawnBullet(int ownerIndex, Vector3 direction)
{
GameObject bullet = Instantiate(bullet_prefab, bulletPoint.position, bulletPoint.rotation);
Transform val = bullet.transform;
NetworkServer.Spawn(val.gameObject);
Bullet component = val.GetComponent<Bullet>();
component.OnSpawn(ownerIndex, direction, recoil);
return val;
}
/// <summary>
/// 填充子弹
/// </summary>
public void StuffBullet(int amount)
{
if (amount < 0 && amount != -999)
{
return;
}
bullet_amount = amount;
}
public void SetBulletAmount(int amount,int ownerIndex)
{
if (amount < 0 && amount != -999)
{
return;
}
curOwnerIndex = ownerIndex;
GunInfo gunInfo = GameManager.Ins.GunInfos[type];
shootRate = gunInfo.ShootRate;
recoil = gunInfo.Recoil;
_shootInterval = 1f / shootRate;
bullet_amount = amount;
}
[Server]
protected void SpawnMuzzle()
{
if (muzzle_prefab != null)
{
Transform val = Instantiate(muzzle_prefab, muzzlePoint.position, new Quaternion(0, 0, 0, 0)).transform;
val.forward = muzzlePoint.forward;
NetworkServer.Spawn(val.gameObject);
if (val == null)
{
this.LogEditorOnly("Failed to spawn muzzle");
return;
}
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
NetworkServer.Destroy(val.gameObject);
}, muzzle_despawn_time);
}
}
[Server]
protected void SpawnShell()
{
if (shell_prefab != null && shellPoint != null)
{
Transform val = Instantiate(shell_prefab, shellPoint.position, Quaternion.Euler(UnityEngine.Random.insideUnitSphere * 360f)).transform;
NetworkServer.Spawn(val.gameObject);
Rigidbody component = val.GetComponent<Rigidbody>();
if (component != null)
{
component.velocity = shellPoint.forward * shell_outforce;
}
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
NetworkServer.Destroy(val.gameObject);
}, shell_despawn_delay);
}
}
}