Files
MRCS/Assets/_MrCs/Scripts/Player/Player.cs

590 lines
15 KiB
C#

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;
/// <summary>
/// 手类型
/// </summary>
public enum HandType
{
Left,
Right
}
public enum TeamType
{
None = 0,
Red=1,
Blue=2
}
/// <summary>
/// 手状态
/// </summary>
public enum HandState
{
/// <summary>
/// 空手
/// </summary>
Empty,
/// <summary>
/// 有武器
/// </summary>
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 = 30;
private float currentHp;
public GameObject redKillUI;
public GameObject blueKillUI;
#region
/// <summary>
/// 双手状态
/// </summary>
public HandState NowHandState = HandState.Empty;
private Launcher curGun;
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&& curGun!=null && curGun.userTime > 0)
{
curGun.curUserTime-=Time.deltaTime;
if (curGun.curUserTime < 0)
{
IsUserAirdropItem = false;
curGun.bullet_amount = 0;
DelWeapon();
}
}
}
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();
GameManager.Ins.CleanupGuideArrow();
}
if (other.tag == "BlueDoor")
{
Debug.Log("触碰开始");
teamType = TeamType.Blue;
GameManager.Ins.GivePistol(index);
GameManager.Ins.CheckGameStart();
GameManager.Ins.CleanupGuideArrow();
}
}
[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
/// <summary>
/// 创建武器
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
[Server]
public GameObject CreateWeapon(GunType type)
{
GameObject gun = null;
gun = Instantiate(gunsPre[(int)type]);
return gun;
}
/// <summary>
/// 装载武器
/// </summary>
/// <param name="handType"></param>
/// <param name="gunType"></param>
/// <returns></returns>
[Server]
public Launcher LoadGun(HandType handType, GunType gunType)
{
GameObject gun = CreateWeapon(gunType);
Launcher launcher = gun.GetComponent<Launcher>();
launcher.OnSpawn(index,handType,gunType,teamType);
return launcher;
}
/// <summary>
/// 拾取枪械
/// </summary>
/// <param name="gunType"></param>
/// <param name="owner"></param>
[Command(requiresAuthority = false)]
public void PickUpGun(GunType gunType, int amount)
{
if (curGun != null&&gunType == curGun.type)
{
if(curGun.type== GunType.Pistol)
return;
Debug.Log("添加弹药 - " + gunType);
curGun.StuffBullet(amount);
}
else
{
if (curGun != null)
{
curGun.gameObject.SetActive(false);
NetworkServer.Destroy(curGun.gameObject);
curGun = null;
}
Debug.Log("增加新武器 - " + gunType);
Launcher right = null;
right = LoadGun(HandType.Right, gunType);
right.SetBulletAmount(amount);
NetworkServer.Spawn(right.gameObject,gameObject);
curGun = right;
}
if (gunType != GunType.Pistol)
IsUserAirdropItem = true;
}
/// <summary>
/// 删除武器
/// </summary>
[Command(requiresAuthority = false)]
public void DelWeapon()
{
GivePistol();
}
#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, 2f);
if (isServer)
{
Collider.enabled = false;
}
CmdSendHit(info,score);
CmdRequestShowKillUI();
MonoSingleton<CoroutineTaskManager>.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();
}, 2f, this);
}
else if (currentHp > 0&& damage>0)
{
if (GameLocal.Ins.HitUI == null)
return currentHp;
GameLocal.Ins.HitUI.SetActive(true);
MonoSingleton<CoroutineTaskManager>.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
}