Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/AI/JobBase.cs

280 lines
8.9 KiB
C#
Raw Normal View History

using Data;
using Managers;
using UnityEngine;
namespace AI
{
public abstract class JobBase
{
public Entity.Entity entity;
protected int timeoutTicks = 300;
public bool Running => timeoutTicks > 0;
protected abstract void UpdateJob();
public virtual void StartJob(Entity.Entity target)
{
entity = target;
}
public bool Update()
{
if (!Running)
return false;
UpdateJob();
timeoutTicks--;
return true;
}
public virtual void StopJob()
{
timeoutTicks = 0;
}
}
public class WanderJob : JobBase
{
public override void StartJob(Entity.Entity target)
{
base.StartJob(target);
Vector3 move = new(Random.Range(-10, 10), Random.Range(-10, 10));
var targetPosition = entity.transform.position + move;
entity.SetTarget(targetPosition);
entity.IsChase = false;
}
protected override void UpdateJob()
{
entity.TryMove();
}
override public void StopJob()
{
base.StopJob();
entity.IsChase = true;
}
}
public class IdleJob : JobBase
{
override public void StartJob(Entity.Entity target)
{
base.StartJob(target);
timeoutTicks = 500;
}
protected override void UpdateJob()
{
}
}
public class MoveJob : JobBase
{
protected override void UpdateJob()
{
entity.TryMove();
}
}
public class AttackJob : JobBase
{
private Entity.Entity attackTarget;
// StartJob 方法:用于初始化任务,寻找初始攻击目标
override public void StartJob(Entity.Entity performerEntityContext) // 参数名更明确,通常是发起任务的实体
{
base.StartJob(performerEntityContext);
// 1. 任务执行者自身有效性检查
if (entity == null)
{
StopJob(); // 调用StopJob来结束任务
return;
}
attackTarget = FindNewHostileTarget();
if (attackTarget == null)
{
StopJob(); // 调用StopJob来结束任务
}
}
protected override void UpdateJob()
{
// 1. 任务执行者的基本检查
if (entity == null || entity.IsDead)
{
StopJob();
return;
}
if (attackTarget == null || attackTarget.IsDead)
{
attackTarget = FindNewHostileTarget(); // 尝试寻找新的攻击目标
if (attackTarget == null)
{
StopJob();
return;
}
}
var weapon = entity.GetCurrentWeapon();
var attackRange = 0f;
if (weapon != null)
{
attackRange = weapon.Attributes.attackRange;
}
var distanceSq = (entity.Position - attackTarget.Position).sqrMagnitude;
var effectiveAttackRangeSq = attackRange * attackRange; // 将攻击范围也平方
entity.SetTarget(attackTarget.Position);
if (weapon != null && distanceSq <= effectiveAttackRangeSq)
{
entity.TryAttack();
}
else
{
entity.TryMove();
}
}
/// <summary>
/// 查找执行实体最近的敌对目标。
/// </summary>
/// <returns>找到的敌对实体如果没有则返回null。</returns>
private Entity.Entity FindNewHostileTarget()
{
if (!entity) return null;
return EntityManage.Instance.FindNearestEntityByRelation(
entity.currentDimensionId, // 搜索维度ID
entity.entityPrefab, // 执行实体的Prefab ID用于关系判断
Relation.Hostile)?.entity; // 寻找敌对关系的目标
}
}
public class AdvancedAttackJob : JobBase
{
private Entity.Entity attackTarget;
// 常量用于配置远程AI行为的风筝参数
private const float KITING_THRESHOLD_MULTIPLIER = 0.5f; // 当目标距离小于 (攻击范围 * 此乘数) 时,远程单位开始尝试远离
private const float KITING_BUFFER_DISTANCE = 5.0f; // 当远程单位远离时,目标点会是当前位置向反方向偏移此距离
// StartJob 方法:用于初始化任务,寻找初始攻击目标
override public void StartJob(Entity.Entity performerEntityContext)
{
base.StartJob(performerEntityContext);
if (entity == null)
{
StopJob();
return;
}
attackTarget = FindNewHostileTarget();
if (attackTarget == null)
{
StopJob();
}
}
protected override void UpdateJob()
{
// 1. 任务执行者的基本检查
if (entity == null || entity.IsDead)
{
StopJob();
return;
}
// 2. 攻击目标检查
if (attackTarget == null || attackTarget.IsDead)
{
attackTarget = FindNewHostileTarget(); // 尝试寻找新的攻击目标
if (attackTarget == null)
{
StopJob();
return;
}
}
// 获取武器和其属性
var weapon = entity.GetCurrentWeapon();
var attackRange = 0f;
var isRangedWeapon = false; // 标识是否为远程武器
if (weapon != null)
{
if (weapon.Attributes != null)
{
attackRange = weapon.Attributes.attackRange;
}
// 使用 WeaponType 来判断武器类型,更明确
isRangedWeapon = weapon.Type == WeaponType.Ranged;
}
var distanceSq = (entity.Position - attackTarget.Position).sqrMagnitude;
var effectiveAttackRangeSq = attackRange * attackRange; // 将攻击范围平方
// ---- 核心AI行为决策 ( AdvancedAttackJob 的智能之处) ----
if (isRangedWeapon)
{
// 远程单位的风筝Kiting逻辑
var kitingDistance = attackRange * KITING_THRESHOLD_MULTIPLIER;
var kitingThresholdSq = kitingDistance * kitingDistance; // 过近距离的平方
// 1. 如果目标过于接近 (小于风筝阈值),尝试远离
if (distanceSq < kitingThresholdSq)
{
// 计算一个远离目标的点作为移动目标
var directionAway = (entity.Position - attackTarget.Position).normalized;
var fleePosition = entity.Position + directionAway * KITING_BUFFER_DISTANCE;
entity.SetTarget(fleePosition); // 设置远离点为新的移动目标
entity.TryMove(); // 优先执行移动操作以拉开距离
// 在此状态下不进行攻击,专注于 reposition
}
// 2. 如果目标在最佳攻击范围内 (即在风筝阈值和有效攻击范围之间),则停止移动并攻击
else if (distanceSq <= effectiveAttackRangeSq)
{
entity.SetTarget(entity.Position); // 设定目标为当前位置,使其停止移动,专注于攻击
entity.TryAttack();
}
// 3. 如果目标太远 (超出有效攻击范围),则移动靠近目标
else
{
entity.SetTarget(attackTarget.Position); // 设置目标位置为移动目标
entity.TryMove();
}
}
else // 近战单位或没有武器的单位
{
entity.SetTarget(attackTarget.Position);
if (weapon != null && distanceSq <= effectiveAttackRangeSq)
{
entity.TryAttack();
}
else
{
entity.TryMove();
}
}
}
/// <summary>
/// 查找执行实体最近的敌对目标。
/// </summary>
/// <returns>找到的敌对实体如果没有则返回null。</returns>
private Entity.Entity FindNewHostileTarget()
{
if (!entity) return null;
return EntityManage.Instance.FindNearestEntityByRelation(
entity.currentDimensionId,
entity.entityPrefab,
Relation.Hostile)?.entity;
}
}
}