using System; using System.Collections; using System.Collections.Generic; using DamageNumbersPro; using DragonLi.Core; using DragonLi.Frame; using Mirror; using UnityEngine; using UnityEngine.XR; using Random = UnityEngine.Random; /// /// 手类型 /// public enum HandType { Left, Right } public enum TeamType { None = 0, Red=1, Blue=2 } /// /// 手状态 /// public enum HandState { /// /// 空手 /// Empty, /// /// 有武器 /// HaveWeapon } public class Player : NetworkRoomPlayer,IDamagable { public Transform LeftHand; public Transform RightHand; public Transform Aim; public GameObject redHelmetPre; public GameObject blueHelmetPre; public GameObject redArmorPre; public GameObject blueArmorPre; public GameObject dieHelmetPre; public GameObject dieArmorPre; public Collider Collider; public LayerMask AimLayer; [Header("要附加的模型")] public Transform helmet; // 头盔模型 public Transform armor; // 护甲模型(胸口) public float defaultHeight = 1.7f; // 默认参考身高 private float currentHeight; public GameObject invinciblePre; [SyncVar] public TeamType teamType; [NonSerialized] [SyncVar] public bool IsUserAirdropItem; [NonSerialized] [SyncVar] public bool isInvincible; #if UNITY_EDITOR [DisplayOnly] #endif public Vector3 AimVec = Vector3.zero; [SyncVar] public bool isDie; private bool IsAlive = true; private float time = 0; [Header("玩家最大血量")] private float maxHp = 10; private float currentHp; public GameObject redKillUI; public GameObject blueKillUI; #region 枪械参数 /// /// 双手状态 /// public HandState NowHandState = HandState.Empty; /// /// 手上的枪械 /// private List Guns = new List(); /// /// 现在手上的武器 /// public int NowGunIndex = -1; /// /// 左手上的枪 /// // private Transform leftGun; /// /// 右手上的枪 /// private Transform rightGun; public GameObject[] gunsPre; #endregion public new void Start() { base.Start(); if (isLocalPlayer) { GameLocal.Ins.self = this; Collider.enabled = false; StartCoroutine(InitHeight()); } IsUserAirdropItem = false; currentHp= maxHp; ShowInvincible(); if (isServer) { GameManager.Ins.AddData(index); GameManager.Ins.RegisterPlayer(this); Collider.enabled = true; } dieArmorPre.SetActive(false); dieHelmetPre.SetActive(false); redKillUI.SetActive(false); blueKillUI.SetActive(false); HideArmor(); } public override void OnStartLocalPlayer() { base.OnStartLocalPlayer(); SetLayerRecursive(helmet.gameObject, LayerMask.NameToLayer("PlayerLocalHide")); SetLayerRecursive(armor.gameObject, LayerMask.NameToLayer("PlayerLocalHide")); } void SetLayerRecursive(GameObject obj, int layer) { if (obj == null) return; obj.layer = layer; foreach (Transform child in obj.transform) SetLayerRecursive(child.gameObject, layer); } IEnumerator InitHeight() { yield return new WaitForSeconds(1f); Transform mainCamera = GameLocal.Ins.MRCamera.transform; currentHeight = mainCamera.position.y; // 玩家实际身高 } public void Update() { Transform mainCamera = GameLocal.Ins.MRCamera.transform; Transform aim = GameLocal.Ins.Aim.transform; Transform leftControl = GameLocal.Ins.MRLeftControl; Transform rightControl = GameLocal.Ins.MRRightControl; if (isLocalPlayer) { // 同步相机 transform.position = mainCamera.position; transform.rotation = mainCamera.rotation; // 同步注视点 Aim.position = aim.position; Aim.rotation = aim.rotation; #if !UNITY_EDITOR && UNITY_ANDROID && PICO // 同步手柄 LeftHand.transform.position = leftControl.position; LeftHand.transform.rotation = leftControl.rotation; RightHand.transform.position = rightControl.position; RightHand.transform.rotation = rightControl.rotation; #endif // 秒杀当前场上的怪 if (Input.GetKeyDown(KeyCode.Q)) { GameManager.Ins.DamageAllEnemy(); } } if (isServer) { // 发射射线 if (Physics.Raycast(transform.position, transform.forward, out RaycastHit handlingHit, 20f, AimLayer)) { AimVec = handlingHit.point; } else { AimVec = Aim.position; } if (IsUserAirdropItem && Guns[NowGunIndex].userTime > 0) { Guns[NowGunIndex].curUserTime-=Time.deltaTime; if (Guns[NowGunIndex].curUserTime < 0) { IsUserAirdropItem = false; Guns[NowGunIndex].bullet_amount = 0; DelWeapon(); } } if (Input.GetKeyDown(KeyCode.E)) { int curIndex = NowGunIndex + 1>=gunsPre.Length? 0: NowGunIndex+1 ; GiveAirdrop(connectionToClient,(GunType)curIndex,1); } if (Input.GetKeyDown(KeyCode.Q)) { GiveAirdrop(connectionToClient,GunType.WuDiZhao,10); } } invinciblePre.SetActive(isInvincible); } private void LateUpdate() { if (isLocalPlayer) { Transform mainCamera = GameLocal.Ins.MRCamera.transform; if ( helmet == null || armor == null) return; // 更新玩家当前身高 float playerHeight = mainCamera.position.y; if (playerHeight <= 0.5f) return; // 防止Pico数据未初始化 float heightRatio = playerHeight / defaultHeight; // === 头盔始终跟随头部 === helmet.position = Vector3.Lerp(helmet.position, mainCamera.position, Time.deltaTime * 10f); helmet.rotation = Quaternion.Slerp(helmet.rotation, mainCamera.rotation, Time.deltaTime * 10f); // === 护甲根据头显高度偏移 === Vector3 armorPos = mainCamera.position; armorPos.y -= 0.25f * heightRatio; // 头部往下约 0.25米 armor.position = armorPos; // 让护甲方向始终朝向正前方 armor.rotation = Quaternion.Euler(0, mainCamera.eulerAngles.y, 0); } } [ServerCallback] public void OnTriggerEnter(Collider other) { // 开始游戏 if (other.tag == "RedDoor") { Debug.Log("触碰开始"); teamType = TeamType.Red; GameManager.Ins.GivePistol(index); GameManager.Ins.CheckGameStart(); } if (other.tag == "BlueDoor") { Debug.Log("触碰开始"); teamType = TeamType.Blue; GameManager.Ins.GivePistol(index); GameManager.Ins.CheckGameStart(); } } [Server] public void GivePistol() { if(NowHandState!= HandState.Empty) return; Debug.Log("创建武器中..."); PickUpGun(GunType.Pistol, GameManager.Ins.GunInfos[GunType.Pistol][1].BulletAmount); } [ClientRpc] public void ClearGun() { PickUpGun(GunType.Pistol, GameManager.Ins.GunInfos[GunType.Pistol][1].BulletAmount); ShowInvincible(); IsAlive = true; CmdChangeState(false); if (isServer) { Collider.enabled = true; } GameLocal.Ins.DieUI.SetActive(false); currentHp = maxHp; EventDispatcher.TriggerEvent("HpChange", currentHp, maxHp); time = 0f; CmdRequestHideKillUI(); } [ClientRpc] public void GiveArmor() { dieArmorPre.SetActive(false); dieHelmetPre.SetActive(false); redArmorPre.SetActive(teamType==TeamType.Red); blueArmorPre.SetActive(teamType==TeamType.Blue); redHelmetPre.SetActive(teamType==TeamType.Red); blueHelmetPre.SetActive(teamType==TeamType.Blue); } public void HideArmor() { redArmorPre.SetActive(false); blueArmorPre.SetActive(false); redHelmetPre.SetActive(false); blueHelmetPre.SetActive(false); dieArmorPre.SetActive(true); dieHelmetPre.SetActive(true); } [ClientRpc] public void RpcShowKillUI() { redKillUI.SetActive(teamType==TeamType.Red); blueKillUI.SetActive(teamType==TeamType.Blue); HideArmor(); } [Server] public void ServerShowKillUI() { RpcShowKillUI(); } [Server] public void ServerHideKillUI() { RpcHideKillUI(); } [Command] public void CmdRequestShowKillUI() { ServerShowKillUI(); } [Command] public void CmdRequestHideKillUI() { ServerHideKillUI(); } [ClientRpc] void RpcHideKillUI() { redKillUI.SetActive(false); blueKillUI.SetActive(false); dieArmorPre.SetActive(false); dieHelmetPre.SetActive(false); redArmorPre.SetActive(teamType==TeamType.Red); blueArmorPre.SetActive(teamType==TeamType.Blue); redHelmetPre.SetActive(teamType==TeamType.Red); blueHelmetPre.SetActive(teamType==TeamType.Blue); } [TargetRpc] public void GiveAirdrop(NetworkConnectionToClient conn, GunType type, int amount) { if (type == GunType.WuDiZhao) { ShowInvincible(); CoroutineTaskManager.Instance.WaitSecondTodo(() => { HideInvincible(); }, amount); return; } PickUpGun(type, amount); } public void ShowInvincible() { isInvincible = true; } public void HideInvincible() { isInvincible = false; } #region 枪械系统 /// /// 创建武器 /// /// /// [Server] public GameObject CreateWeapon(GunType type) { GameObject gun = null; gun = Instantiate(gunsPre[(int)type]); return gun; } /// /// 装载武器 /// /// /// /// [Server] public Launcher LoadGun(HandType handType, GunType gunType) { GameObject gun = CreateWeapon(gunType); Launcher launcher = gun.GetComponent(); launcher.OnSpawn(index,handType,gunType,teamType); return launcher; } [TargetRpc] public void TriggerEvent(GunType gunType) { EventDispatcher.TriggerEvent("ChangeWeaponIcon", gunType, 0); } [TargetRpc] public void TriggerEventAmount(float amount) { if (amount == -999) amount = 0; EventDispatcher.TriggerEvent("ShowBulletAmount", amount); } /// /// 拾取枪械 /// /// /// [Command(requiresAuthority = false)] public void PickUpGun(GunType gunType, int amount) { Launcher find = null; for (int i = 0; i < Guns.Count; i++) { Launcher launcher = Guns[i]; if (launcher != null && launcher.type == gunType) { find = launcher; break; } } if (find != null) { Debug.Log("添加弹药 - " + gunType); find.StuffBullet(amount); Swith2TargetGun(gunType); } else { Debug.Log("增加新武器 - " + gunType); Launcher left = null; Launcher right = null; right = LoadGun(HandType.Right, gunType); right.SetBulletAmount(amount); Guns.Add(right); Swith2TargetGun(gunType); } } /// /// 切换到下个武器 /// [Command] public void Switch2NextWeaponCmd() { Switch2NextWeapon(); } [Command] public void Switch2BeforeWeaponCmd() { Switch2BeforeWeapon(); } /// /// 切换到下个武器 /// [Server] public void Switch2NextWeapon() { Debug.Log("切换到下个武器"); // 空手 if (NowHandState == HandState.Empty) { Debug.Log("空手->可有武器状态"); NowHandState = HandState.HaveWeapon; } // 无武器 if (Guns.Count <= 0) { Debug.Log("无武器"); return; } NowGunIndex++; if (NowGunIndex > Guns.Count - 1) { NowGunIndex = 0; } UpdateWeapons(); } /// /// 切换到上个武器 /// [Server] public void Switch2BeforeWeapon() { Debug.Log("切换到下个武器"); // 空手 if (NowHandState == HandState.Empty) { Debug.Log("空手->可有武器状态"); NowHandState = HandState.HaveWeapon; } // 无武器 if (Guns.Count <= 0) { Debug.Log("无武器"); return; } NowGunIndex--; if (NowGunIndex < 0) { NowGunIndex = Guns.Count - 1; } UpdateWeapons(); } /// /// 切换到指定枪械 /// [Server] public void Swith2TargetGun(GunType type) { Debug.Log("切换到指定枪械"); int find = -1; for (int i = 0; i < Guns.Count; i++) { Launcher launcher = Guns[i]; if (launcher != null && launcher.type == type) { find = i; break; } } if (find != -1) { NowGunIndex = find; } UpdateWeapons(); } [Command] public void EntertTurret(NetworkIdentity turret) { turret.AssignClientAuthority(connectionToClient); } [Command] public void ExitTurret(NetworkIdentity turret) { turret.RemoveClientAuthority(); } /// /// 武器更新 /// [Server] public void UpdateWeapons() { // if (leftGun != null) // { // leftGun.gameObject.SetActive(false); // NetworkServer.UnSpawn(leftGun.gameObject); // leftGun = null; // } if (rightGun != null) { rightGun.gameObject.SetActive(false); NetworkServer.UnSpawn(rightGun.gameObject); rightGun = null; } for (int i = 0; i < Guns.Count; i++) { if (i == NowGunIndex) { Launcher l1 = Guns[i]; if (l1 != null) { IsUserAirdropItem = l1.type != GunType.Pistol; rightGun = l1.transform; rightGun.gameObject.SetActive(true); NetworkServer.Spawn(l1.gameObject, gameObject); } } } } /// /// 删除武器 /// [Command(requiresAuthority = false)] public void DelWeapon() { bool change = false; for (int i = 0; i < Guns.Count; i++) { Launcher launcher = Guns[i]; if (launcher != null && launcher.bullet_amount <= 0) { change = true; Guns[i] = null; break; } } if (change) { Guns.RemoveAll(x => x == null); Switch2NextWeapon(); } } [Command] public void Switch2EmptyCmd() { Switch2Empty(); } /// /// 切换为空手 /// [Server] public void Switch2Empty() { NowHandState = HandState.Empty; NowGunIndex = -1; UpdateWeapons(); } #endregion #region 玩家生命 [TargetRpc] public void ApplyDamage(float value, int info, Transform _sender,int score) { OnReceiveDamage(value, info, _sender,score*10); } public float OnReceiveDamage(float damage, int info, Transform _sender,int score) { if (isInvincible) damage = 0; bool isCriticalHit = Vector3.Distance(_sender.position, helmet.position) < 1.5f; float curDamage =isCriticalHit? damage*2: damage; SetBlood(-curDamage); #if !UNITY_EDITOR && UNITY_ANDROID && PICO if (_sender != null) { Vector3 forward = transform.forward; Vector3 directionFormHit=(transform.position-_sender.position).normalized; float angle = Vector3.Angle(forward, directionFormHit); int index = Random.Range(0, 4); // if(TrueGearEffectManager.Ins!=null) // TrueGearEffectManager.Ins.OnHit(angle > 90,index,false); } #endif if (currentHp <= 0 && IsAlive) { IsAlive = false; CmdChangeState(true); GameLocal.Ins.DieUI.SetActive(true); EventDispatcher.TriggerEvent("Revive", (int)teamType, 5f); if (isServer) { Collider.enabled = false; } CmdSendHit(info,score); CmdRequestShowKillUI(); MonoSingleton.Instance.WaitSecondTodo(() => { if (IsAlive) return; IsAlive = true; CmdChangeState(false); if (isServer) { Collider.enabled = true; } GameLocal.Ins.DieUI.SetActive(false); currentHp = maxHp; EventDispatcher.TriggerEvent("HpChange", currentHp, maxHp); time = 0f; CmdRequestHideKillUI(); }, 5f, this); } else if (currentHp > 0&& damage>0) { if (GameLocal.Ins.HitUI == null) return currentHp; GameLocal.Ins.HitUI.SetActive(true); MonoSingleton.Instance.WaitSecondTodo(() => GameLocal.Ins.HitUI.SetActive(false), 1f, this); } return currentHp; } [TargetRpc] public void TargetShowKillUI(NetworkConnection target,int score) { EventDispatcher.TriggerEvent("ScoreSound", score); } // 被击中的客户端调用 [Command] public void CmdSendHit(int attackerIndex,int score) { ApplyDamageServer(attackerIndex,score); } [Command] public void CmdChangeState(bool curIsDie) { isDie = curIsDie; // if (isDie) // { // HideArmor(); // } // else // { // GiveArmor(); // } } [Server] void ApplyDamageServer(int attackerId,int score) { if (teamType == TeamType.Red) GameManager.Ins.AddBlueScore(score); if(teamType == TeamType.Blue) GameManager.Ins.AddRedScore(score); Player player = GameManager.Ins.GetPlayerByIndex(attackerId); TargetShowKillUI(player.connectionToClient,score); } public void SetBlood(float num) { currentHp += num; if(num==0) return; EventDispatcher.TriggerEvent("HpChange", currentHp, maxHp); } public float Health { get => currentHp; set => currentHp = value; } #endregion }