using System; using System.Collections.Generic; using AI; using Base; using Data; using Prefab; using UnityEngine; using UnityEngine.Serialization; namespace Entity { public class Entity:MonoBehaviour,ITick { public SpriteAnimator animatorPrefab; public ImagePrefab imagePrefab; public AIBase aiTree; public JobBase currentJob; public AttributesDef attributes=new(); 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; private Dictionary> bodyAnimationNode=new(); private Dictionary bodyNodes = new(); private Orientation currentOrientation = Orientation.Down; public virtual void Init(PawnDef pawnDef) { attributes = pawnDef.attributes.Clone(); aiTree = ConvertToAIBase(pawnDef.behaviorTree); affiliation = pawnDef.affiliation; InitBody(pawnDef.drawingOrder); } public virtual void InitBody(DrawingOrderDef drawingOrder) { // 定义方向枚举和对应的 GetDrawingOrder 调用 Orientation[] orientations = { Orientation.Down, Orientation.Up, Orientation.Left, Orientation.Right }; foreach (var orientation in orientations) { currentOrientation = orientation; bodyAnimationNode[orientation] = new(); // 获取当前方向的绘图节点 var drawNode = drawingOrder.GetDrawingOrder(orientation); if (drawNode == null) continue; var directionRoot = new GameObject(orientation.ToString()); directionRoot.transform.SetParent(body.transform, false); InitBodyPart(drawNode, directionRoot); bodyNodes[orientation] = directionRoot; } currentOrientation = Orientation.Down; foreach (var bodyNode in bodyNodes) { bodyNode.Value.SetActive(false); } SetOrientation(Orientation.Down); } // 递归初始化单个绘图节点及其子节点 public virtual void InitBodyPart(DrawNodeDef drawNode, GameObject parent) { if(drawNode==null) return; GameObject nodeObject; switch (drawNode.drawNodeType) { case DrawNodeType.Image: nodeObject = Instantiate(imagePrefab.gameObject,parent.transform); break; case DrawNodeType.Animation: nodeObject = Instantiate(animatorPrefab.gameObject,parent.transform); ITick tick = nodeObject.GetComponent(); if (tick != null) bodyAnimationNode[currentOrientation].Add(tick); break; default: throw new ArgumentOutOfRangeException(); } nodeObject.transform.localPosition = drawNode.position; // 递归初始化子节点 foreach (var child in drawNode.children) { InitBodyPart(child, nodeObject); } } public void Tick() { if (_isPlayerControlled) { UpdatePlayerControls(); } else { AutoBehave(); } if (bodyAnimationNode.TryGetValue(currentOrientation, out var ticks)) { foreach (var tick in ticks) { tick.Tick(); } } } public virtual void TryAttck() { } public virtual void SetOrientation(Orientation orientation) { bodyNodes[currentOrientation]?.SetActive(false); currentOrientation = orientation; bodyNodes[orientation]?.SetActive(true); } /// /// 往对应朝向移动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(aiTree == null) return; 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 的子类"); } } }