using System; using System.Collections; using System.Collections.Generic; using DragonLi.Core; using DragonLi.Frame; using Mirror; using UnityEngine; using UnityEngine.XR; public class Launcher : Entity { [Header("子弹")] public GameObject bullet_prefab; public float bullet_speed = 100f; [SyncVar] public float bullet_amount = 0f; public float damage = 10f; public float shootrate = 10f; public int bullet_per_shoot = 1; public bool nature_recoil = false; public Vector2 recoil_mutiply; public Vector2 recoil_recover_rate = Vector2.one * 10f; [Header("开火")] public GameObject muzzle_prefab; public float muzzle_despawn_time; [Header("弹壳")] public GameObject shell_key; public float shell_outforce; public float shell_despawn_delay; /// /// Where should we spawn bullet /// public Transform LaunchPoint; /// /// Where to spawn shell /// public Transform ShellOutPoint; /// /// If time.time is bigger than this value, so the gun can shoot /// [NonSerialized] [SyncVar] public float nextShootTime = 0f; [NonSerialized] [SyncVar] public float Interval = 0f; [NonSerialized] public float shootInterval = 0f; [NonSerialized] [SyncVar] public HandType hand = HandType.Right; private float recoilVert = 0f; private float recoilHori = 0f; public override void OnEnable() { base.OnEnable(); } public sealed override void InitData() { Data.Add("bullet_prefab", new DataRow(SupportDataType.UObject) { Name = "bullet_prefab" }); Data.Add("bullet_speed", new DataRow(SupportDataType.Float) { Name = "bullet_speed", FloatValue = 100f }); Data.Add("damage", new DataRow(SupportDataType.Float) { Name = "damage", FloatValue = 1000f }); Data.Add("shootrate", new DataRow(SupportDataType.Float) { Name = "shootrate", FloatValue = 10f }); Data.Add("bullet_per_shoot", new DataRow(SupportDataType.Int) { Name = "bullet_per_shoot", IntValue = 1 }); Data.Add("nature_recoil", new DataRow(SupportDataType.Boolean) { Name = "nature_recoil", BooleanValue = false }); Data.Add("recoil_mutiply", new DataRow(SupportDataType.Vector2) { Name = "recoil_mutiply" }); Data.Add("recoil_recover_rate", new DataRow(SupportDataType.Vector2) { Name = "recoil_recover_rate", Vector2Value = Vector2.one * 10f }); Data.Add("muzzle_prefab", new DataRow(SupportDataType.UObject) { Name = "muzzle_prefab" }); Data.Add("muzzle_despawn_time", new DataRow(SupportDataType.Float) { Name = "muzzle_despawn_time" }); Data.Add("shell_key", new DataRow(SupportDataType.UObject) { Name = "shell_key" }); Data.Add("shell_outforce", new DataRow(SupportDataType.Float) { Name = "shell_outforce" }); Data.Add("shell_despawn_delay", new DataRow(SupportDataType.Float) { Name = "shell_despawn_delay" }); Data["bullet_prefab"].ObjectValue = bullet_prefab; Data["bullet_speed"].FloatValue = bullet_speed; //Data["damage"].FloatValue = 1000.0f; Data["shootrate"].FloatValue = shootrate; Data["bullet_per_shoot"].IntValue = bullet_per_shoot; Data["nature_recoil"].BooleanValue = nature_recoil; Data["recoil_mutiply"].Vector2Value = recoil_mutiply; Data["recoil_recover_rate"].Vector2Value = recoil_recover_rate; Data["muzzle_prefab"].ObjectValue = muzzle_prefab; Data["muzzle_despawn_time"].FloatValue = muzzle_despawn_time; Data["shell_key"].ObjectValue = shell_key; Data["shell_outforce"].FloatValue = shell_outforce; Data["shell_despawn_delay"].FloatValue = shell_despawn_delay; base.InitData(); } [Server] public void Shoot() { Shoot(-1); } [Server] public void Shoot(int ownerIndex) { Shoot(LaunchPoint.position + LaunchPoint.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) { bullet_amount--; } if (bullet_amount <= 0 && bullet_amount != -999) { LauncherEmpty(); } for (int i = 0; i < Data["bullet_per_shoot"].IntValue; i++) { SpawnBullet(LaunchPoint.position, target - LaunchPoint.position, ownerIndex); } SpawnShell(); SpawnMuzzle(LaunchPoint.position); nextShootTime = Time.time + shootInterval; return true; } [TargetRpc] public void LauncherEmpty() { // GameInit.Ins.self.DelWeapon(); } public override void Awake() { base.Awake(); shootInterval = 1f / Data["shootrate"].FloatValue; } /// /// If you are making a shooter game and you want recoil, you can override this functions. /// /// /// protected virtual Vector3 CalculateRecoil(Vector3 direction) { if (Data["nature_recoil"].BooleanValue) { return direction + Vector3.up * UnityEngine.Random.Range(0f - Data["recoil_mutiply"].Vector2Value.y, Data["recoil_mutiply"].Vector2Value.y) + LaunchPoint.right * UnityEngine.Random.Range(0f - Data["recoil_mutiply"].Vector2Value.x, Data["recoil_mutiply"].Vector2Value.x); } return direction; } [Server] public virtual Transform SpawnBullet(Vector3 startPoint, Vector3 direction, int ownerIndex) { GameObject bullet = Instantiate(bullet_prefab, startPoint, LaunchPoint.rotation); Transform val = bullet.transform; NetworkServer.Spawn(val.gameObject); Bullet component = val.GetComponent(); component.Init(ownerIndex); Rigidbody rigidbodyComponent = component.RigidbodyComponent; Vector3 vector = CalculateRecoil(direction); rigidbodyComponent.velocity = vector.normalized * Data["bullet_speed"].FloatValue; rigidbodyComponent.rotation = Quaternion.LookRotation(vector.normalized); return val; } /// /// 填充子弹 /// public void StuffBullet(int amount) { if (amount < 0 && amount != -999) { return; } bullet_amount += amount; } [Server] protected void SpawnMuzzle(Vector3 startPoint) { if (muzzle_prefab != null) { Transform val = Instantiate(muzzle_prefab, startPoint, new Quaternion(0, 0, 0, 0)).transform; val.forward = LaunchPoint.forward; NetworkServer.Spawn(val.gameObject); if (val == null) { this.LogEditorOnly("Failed to spawn muzzle"); return; } CoroutineTaskManager.Instance.WaitSecondTodo(() => { NetworkServer.Destroy(val.gameObject); }, Data["muzzle_despawn_time"].FloatValue); } } [Server] protected void SpawnShell() { if (shell_key != null && ShellOutPoint != null) { Transform val = Instantiate(shell_key, ShellOutPoint.position, Quaternion.Euler(UnityEngine.Random.insideUnitSphere * 360f)).transform; NetworkServer.Spawn(val.gameObject); Rigidbody component = ((Component)val).GetComponent(); if (component != null) { component.velocity = ShellOutPoint.forward * Data["shell_outforce"].FloatValue; } CoroutineTaskManager.Instance.WaitSecondTodo(() => { NetworkServer.Destroy(val.gameObject); }, Data["shell_despawn_delay"].FloatValue); } } }