Files
Gen_Hack-and-Slash-Roguelit…/Client/Assets/Scripts/Entity/Entity.cs
2025-07-23 18:53:14 +08:00

210 lines
7.0 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;
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()
{
}
/// <summary>
/// 往对应朝向移动moveSpeed*deltaTime的距离
/// </summary>
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 的子类");
}
}
}