Files
DefendNJ/Assets/_DefendNJ/Scripts/AI/PlayerAI.cs
2025-09-24 11:10:05 +08:00

248 lines
6.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections;
using System.Collections.Generic;
using BehaviorDesigner.Runtime;
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,
Die = 99,
}
public enum PlayerAIType
{
PlayerAI1=0,
PlayerAI2=1,
}
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;
[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;
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;
}
}
}
}
[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;
AiInfo enemyInfo = GameManager.Ins.AiInfos[id];
speed = 1;
atk = 1;
health = 10;
originHealth = 10;
aiPath.enabled = true;
aiPath.maxSpeed = speed;
// 初始设置server
if (isServer)
{
state = PlayerAIState.Borning;
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();
}
}
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 (target != null)
{
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(target.transform.position.ReflectVectorXOZ() - 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 权威)
AnimatorComponent.SetInteger("state",1);
//调用枪械开枪脚本
gun.AiShoot();
}
public virtual void StopAttack()
{
if (!isServer) return; // 攻击判定/伤害应由 Server 执行Host 权威)
AnimatorComponent.SetInteger("state",0);
}
public virtual void EndEvent()
{
}
public void ChangeKillEnemyTime()
{
behaviorTree.SetVariable("CountdownTime",(SharedFloat)10f);
}
public void KillEnemyEvent()
{
//gun.Shoot()
}
}