590 lines
15 KiB
C#
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
|
|
|
|
}
|
|
|
|
|