332 lines
9.5 KiB
C#
332 lines
9.5 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using BehaviorDesigner.Runtime;
|
||
using DarkTonic.MasterAudio;
|
||
using DragonLi.Core;
|
||
using Mirror;
|
||
using Pathfinding;
|
||
using Pathfinding.RVO;
|
||
using UnityEngine;
|
||
|
||
|
||
public enum PlayerAIState
|
||
{
|
||
Borning = 0,
|
||
Charge = 1,
|
||
Search = 2,
|
||
Run = 3,
|
||
Atk = 4,
|
||
Win=5,
|
||
Die = 99,
|
||
}
|
||
|
||
public enum PlayerAIType
|
||
{
|
||
PlayerAI1=0,
|
||
PlayerAI2=1,
|
||
EndPlayerAi=2,
|
||
}
|
||
|
||
public class PlayerAI : Agent
|
||
{
|
||
private BehaviorTree _behaviorTree;
|
||
|
||
public BehaviorTree behaviorTree
|
||
{
|
||
get
|
||
{
|
||
if (_behaviorTree == null) _behaviorTree = GetComponent<BehaviorTree>();
|
||
return _behaviorTree;
|
||
}
|
||
}
|
||
|
||
private Collider _collider;
|
||
public Collider selfCollider
|
||
{
|
||
get
|
||
{
|
||
if (_collider == null) _collider = GetComponent<Collider>();
|
||
return _collider;
|
||
}
|
||
}
|
||
|
||
public PlayerAIState state;
|
||
|
||
[SyncVar]
|
||
public bool isGet;//是否被锁定
|
||
|
||
[Header("编号")]
|
||
[SyncVar]
|
||
public int id = 0;
|
||
|
||
[SyncVar] public PlayerAIType type;
|
||
|
||
[Header("等级")]
|
||
[SyncVar]
|
||
public int lvl = 0;
|
||
|
||
[Header("速度")]
|
||
[SyncVar]
|
||
public float speed = 0;
|
||
|
||
[Header("攻击力")]
|
||
[SyncVar]
|
||
public float atk = 0;
|
||
|
||
[Header("特殊攻击1攻击力")]
|
||
[SyncVar]
|
||
public float SpecialAtk1 = 0;
|
||
|
||
[Header("特殊攻击2攻击力")]
|
||
[SyncVar]
|
||
public float SpecialAtk2 = 0;
|
||
|
||
[Header("目标引用 (通常由 BT 设置)")]
|
||
public GameObject target = null;
|
||
|
||
public GunAiComponent gun;
|
||
|
||
|
||
// 行为状态(本地/服务器)
|
||
private bool updateAnimatorSpeedValue = false;
|
||
private bool updateAnimatorSpeedFValue = false;
|
||
private bool updateAnimatorSpeedRValue = false;
|
||
|
||
// AI / 行为标志(server 上驱动)
|
||
private bool introPlayed = false;
|
||
private bool isAttacking = false;
|
||
private bool isDead = false;
|
||
|
||
public float killEnemyTime = 10;
|
||
public float curKillEnemyTime;
|
||
void Awake()
|
||
{
|
||
InitAnimator();
|
||
}
|
||
|
||
void InitAnimator()
|
||
{
|
||
// 检测 Animator 参数,以便按需设置 speed / speedf / speedr
|
||
if (AnimatorComponent == null) return;
|
||
AnimatorControllerParameter[] parameters = AnimatorComponent.parameters;
|
||
foreach (AnimatorControllerParameter val in parameters)
|
||
{
|
||
if (val.type == AnimatorControllerParameterType.Float)
|
||
{
|
||
switch (val.name)
|
||
{
|
||
case "speed":
|
||
updateAnimatorSpeedValue = true;
|
||
break;
|
||
case "speedr":
|
||
updateAnimatorSpeedRValue = true;
|
||
break;
|
||
case "speedf":
|
||
updateAnimatorSpeedFValue = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public void ChangeState(PlayerAIState newState)
|
||
{
|
||
state = newState;
|
||
AnimatorComponent.SetInteger("state", (int)newState);
|
||
switch (newState)
|
||
{
|
||
case PlayerAIState.Atk:
|
||
// target = GameManager.Ins.GetEnemy(transform);
|
||
// if(behaviorTree.enabled)
|
||
// behaviorTree.SetVariable("target",(SharedGameObject)target);
|
||
AnimatorComponent.SetInteger("state",1);
|
||
break;
|
||
case PlayerAIState.Win:
|
||
AnimatorComponent.SetBool("isWin",true);
|
||
break;
|
||
}
|
||
}
|
||
|
||
[Server]
|
||
public virtual void OnSpawn(int id, PlayerAIType type, int lvl,GameObject target)
|
||
{
|
||
base.OnSpawn();
|
||
this.id = id;
|
||
this.type = type;
|
||
state = PlayerAIState.Borning;
|
||
this.lvl = lvl;
|
||
speed = 1;
|
||
atk = 1;
|
||
health = 10;
|
||
originHealth = 10;
|
||
aiPath.enabled = true;
|
||
aiPath.maxSpeed = speed;
|
||
killEnemyTime = 10;
|
||
curKillEnemyTime = killEnemyTime;
|
||
// 初始设置(server)
|
||
if (isServer)
|
||
{
|
||
state = PlayerAIState.Borning;
|
||
if (GameManager.Ins.gameState == GameState.EndEvent)
|
||
state = PlayerAIState.Atk;
|
||
if (aiPath != null) aiPath.enabled = true;
|
||
if (rvoController != null) rvoController.enabled = true;
|
||
if (selfCollider != null) selfCollider.enabled = true;
|
||
if (behaviorTree != null) {
|
||
behaviorTree.enabled = true;
|
||
behaviorTree.SetVariable("target",(SharedGameObject)target);
|
||
}
|
||
// 初始血量已在 Agent.OnSpawn 中设置为 originHealth / health
|
||
}
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
OnUpdate();
|
||
}
|
||
|
||
public override void OnUpdate()
|
||
{
|
||
// 只有 Server/Host 驱动移动(rvo / ai),其它客户端只做视觉播放(由 Rpc 通知)
|
||
if (isServer && !isDead)
|
||
{
|
||
// 该方法在 Agent.Update 中由 Server 调用(以前你的实现)
|
||
// 这里我们保持相同更新:更新动画参数 & 旋转等(只在 Server 上操作 AI/移动)
|
||
if (aiPath != null && aiPath.enabled)
|
||
{
|
||
UpdateAnimatorValues(aiPath.velocity);
|
||
}
|
||
else if (RigidbodyComponent)
|
||
{
|
||
UpdateAnimatorValues(RigidbodyComponent.velocity);
|
||
}
|
||
//UpdateRotation();
|
||
|
||
if (state == (PlayerAIState)3)
|
||
{
|
||
curKillEnemyTime-=Time.deltaTime;
|
||
if (curKillEnemyTime <= 0)
|
||
curKillEnemyTime = killEnemyTime;
|
||
if (behaviorTree != null && behaviorTree.enabled)
|
||
{
|
||
behaviorTree.SetVariable("CountdownTime",(SharedFloat)curKillEnemyTime);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
protected void UpdateAnimatorValues(Vector3 vel)
|
||
{
|
||
if (AnimatorComponent != null)
|
||
{
|
||
if (updateAnimatorSpeedValue)
|
||
{
|
||
AnimatorComponent.SetFloat("speed", vel.magnitude);
|
||
}
|
||
Vector3 val;
|
||
if (updateAnimatorSpeedFValue)
|
||
{
|
||
val = Vector3.Project(vel, transform.forward);
|
||
float num = vel.magnitude > 0 ? val.magnitude / (vel.magnitude * (Vector3.Angle(vel, transform.forward) > 90f ? -1f : 1f)) : 0f;
|
||
AnimatorComponent.SetFloat("speedf", num);
|
||
}
|
||
if (updateAnimatorSpeedRValue)
|
||
{
|
||
val = Vector3.Project(vel, transform.right);
|
||
float num2 = vel.magnitude > 0 ? val.magnitude / (vel.magnitude * (Vector3.Angle(vel, transform.right) > 90f ? -1f : 1f)) : 0f;
|
||
AnimatorComponent.SetFloat("speedr", num2);
|
||
}
|
||
}
|
||
|
||
// 如果使用 Animancer 且你希望通过脚本控制 walkClip 的播放,则在 UpdateLocalVisuals 中处理(下文)
|
||
}
|
||
|
||
public virtual void UpdateRotation()
|
||
{
|
||
if (behaviorTree != null)
|
||
{
|
||
target=(GameObject)behaviorTree.GetVariable("target").GetValue();
|
||
}
|
||
if (target != null)
|
||
{
|
||
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(target.transform.position.ReflectVectorXOZ() - transform.position), Time.deltaTime * 10f);
|
||
}
|
||
else
|
||
{
|
||
Vector3 targetPos = (Vector3)behaviorTree.GetVariable("targetPos").GetValue();
|
||
if (targetPos != Vector3.zero)
|
||
{
|
||
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(new Vector3(targetPos.x,transform.position.y,targetPos.z) - transform.position), Time.deltaTime * 10f);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void LateUpdate()
|
||
{
|
||
Vector3 pos = transform.position;
|
||
pos.y = 0f; // 或者设置为地面高度
|
||
transform.position = pos;
|
||
}
|
||
|
||
public virtual void DoAttack()
|
||
{
|
||
if (!isServer) return; // 攻击判定/伤害应由 Server 执行(Host 权威)
|
||
if (GameManager.Ins.gameState == GameState.EndEvent)
|
||
{
|
||
AnimatorComponent.SetInteger("state",5);
|
||
return;
|
||
}
|
||
AnimatorComponent.SetInteger("state",4);
|
||
//调用枪械开枪脚本
|
||
if (behaviorTree != null)
|
||
{
|
||
target=(GameObject)behaviorTree.GetVariable("target").GetValue();
|
||
Vector3 targetPos = (Vector3)behaviorTree.GetVariable("targetPos").GetValue();
|
||
if (target == null)
|
||
{
|
||
if (targetPos != Vector3.zero)
|
||
{
|
||
gun.EnemyShoot(targetPos);
|
||
}
|
||
else
|
||
{
|
||
gun.EnemyShoot(gun.showPos.forward);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
gun.EnemyShoot(target.transform.position);
|
||
}
|
||
}
|
||
}
|
||
|
||
public virtual void StopAttack()
|
||
{
|
||
if (!isServer) return; // 攻击判定/伤害应由 Server 执行(Host 权威)
|
||
AnimatorComponent.SetInteger("state",0);
|
||
}
|
||
|
||
public virtual void EndEvent()
|
||
{
|
||
PlaySound3DRPC("1.63", true);
|
||
}
|
||
|
||
public void ChangeKillEnemyTime()
|
||
{
|
||
curKillEnemyTime = killEnemyTime;
|
||
}
|
||
|
||
public void KillEnemyEvent()
|
||
{
|
||
//gun.Shoot()
|
||
}
|
||
|
||
[ClientRpc]
|
||
public void PlaySound3DRPC(string sound,bool isStop)
|
||
{
|
||
if(isStop)
|
||
MasterAudio.StopAllSoundsOfTransform(transform);
|
||
MasterAudio.PlaySound3DAtTransform(sound, transform);
|
||
}
|
||
}
|