using System; using System.Collections.Generic; using AI; using Base; using Data; using UnityEngine; using UnityEngine.Serialization; namespace Entity { public class Entity:MonoBehaviour,ITick { public AIBase aiTree; public JobBase currentJob; public AttributesDef attributes; public Vector3 direction; public GameObject body; public string affiliation; public bool canSelect = true; public bool IsChase { set; get; } = true; public bool PlayerControlled { set { if (value) { IsChase = true; currentJob = null; } _isPlayerControlled = value; } get => _isPlayerControlled; } public bool IsDead => attributes.health <= 0; private bool _isPlayerControlled = false; private bool _warning = false; public virtual void Init(PawnDef pawnDef) { attributes = pawnDef.attributes.Clone(); aiTree = ConvertToAIBase(pawnDef.behaviorTree); affiliation=pawnDef.affiliation; //定义的tag有限,不用这个了 // if(!string.IsNullOrEmpty(affiliation)) // gameObject.CompareTag(affiliation); } public void Tick() { if (_isPlayerControlled) { UpdatePlayerControls(); } else { AutoBehave(); } } public virtual void TryAttck() { } /// /// 往对应朝向移动moveSpeed*deltaTime的距离 /// public virtual void TryMove() { transform.position+=direction * (attributes.moveSpeed * Time.deltaTime * (IsChase ? 1 : 0.5f)); } public virtual void OnHit(Entity from) { var hit = from.attributes.attack - attributes.defense; if (hit < 0) hit = from.attributes.attack / 100; attributes.health -= hit; currentJob.StopJob(); } public virtual void SetTarget(Vector3 pos) { direction = (pos - transform.position).normalized; } public virtual void Kill() { attributes.health = 0; } private void AutoBehave() { if (currentJob == null || !currentJob.Running) { currentJob = aiTree.GetJob(this); if (currentJob == null) { if (!_warning) { Debug.LogWarning($"{GetType().Name}类型的{name}没有分配到任何工作,给行为树末尾添加等待行为,避免由于没有工作导致无意义的反复查找工作导致性能问题"); _warning = true; } return; } currentJob.StartJob(this); } currentJob.Update(); } private void UpdatePlayerControls() { // 检测 Shift 键状态 var isHoldingShift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); IsChase = !isHoldingShift; // 按住 Shift 时 IsChase = false,否则 true // 获取当前键盘输入状态(2D 移动,只使用 X 和 Y 轴) var inputDirection = Vector2.zero; // 检测 WASD 或方向键输入 if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) { inputDirection += Vector2.up; // 向上移动(Y 轴正方向) } if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) { inputDirection += Vector2.down; // 向下移动(Y 轴负方向) } if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) { inputDirection += Vector2.left; // 向左移动(X 轴负方向) } if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) { inputDirection += Vector2.right; // 向右移动(X 轴正方向) } // 如果有输入方向,则设置目标位置并尝试移动 if (inputDirection == Vector2.zero) return; // 归一化方向向量,确保对角线移动速度一致 inputDirection = inputDirection.normalized; // 设置目标位置(2D 移动,Z 轴保持不变) var targetPosition = transform.position + new Vector3(inputDirection.x, inputDirection.y, 0); // 调用 SetTarget 方法设置目标位置 SetTarget(targetPosition); // 调用 TryMove 方法处理实际移动逻辑 TryMove(); } public static AIBase ConvertToAIBase(BehaviorTreeDef behaviorTreeDef) { if (behaviorTreeDef == null) return null; var aiBase = CreateAIBaseInstance(behaviorTreeDef.className); if (behaviorTreeDef.childTree != null) { foreach (var child in behaviorTreeDef.childTree) { if (child != null) { aiBase.children.Add(ConvertToAIBase(child)); } } } return aiBase; } // 使用反射根据 className 创建具体的 AIBase 子类实例 private static AIBase CreateAIBaseInstance(string className) { if (string.IsNullOrEmpty(className)) throw new ArgumentException("className 不能为空"); if (className.Equals("AIBase", StringComparison.OrdinalIgnoreCase)) { return (AIBase)Activator.CreateInstance(typeof(AIBase)); } // 定义可能的命名空间列表 var possibleNamespaces = new[] { "AI"}; foreach (var ns in possibleNamespaces) { try { // 获取当前程序集 var assembly = typeof(AIBase).Assembly; // 尝试查找类型 var type = assembly.GetType($"{ns}.{className}"); if (type != null && typeof(AIBase).IsAssignableFrom(type)) { // 如果找到合适的类型,则创建实例并返回 return (AIBase)Activator.CreateInstance(type); } } catch { // 忽略单个命名空间的错误,继续尝试下一个命名空间 } } // 如果所有命名空间都未找到对应的类型,抛出异常 throw new InvalidOperationException($"无法找到类型 {className} 或该类型不是 AIBase 的子类"); } } }