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

295 lines
8.4 KiB
C#

using System.Collections.Generic;
using Base;
using Prefab;
using Unity.VisualScripting;
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 TrackPlayerJob : JobBase
{
private EntityPrefab currentTarget; // 当前追踪的目标玩家
private List<EntityPrefab> players; // 玩家实体列表
public override void StartJob(Entity.Entity target)
{
base.StartJob(target);
UpdateTarget();
}
protected override void UpdateJob()
{
if (currentTarget == null || currentTarget.entity.IsDead)
{
// 如果当前目标无效,则重新查找最近的玩家
UpdateTarget();
}
if (currentTarget != null)
{
var targetPosition = new Vector3(currentTarget.Position.x, currentTarget.Position.y, 0);
entity.SetTarget(targetPosition);
entity.TryMove();
}
}
private void UpdateTarget()
{
players = Managers.EntityManage.Instance.FindEntitiesByFaction("Player");
if (players == null || players.Count == 0)
{
currentTarget = null;
StopJob();
return;
}
currentTarget = GetNearestPlayer(players);
}
private EntityPrefab GetNearestPlayer(List<EntityPrefab> players)
{
EntityPrefab nearestPlayer = null;
float minDistance = float.MaxValue;
foreach (var player in players)
{
if (player.entity.IsDead) continue; // 跳过无效玩家
float distance = Vector3.Distance(
new Vector3(player.Position.x, player.Position.y, 0),
new Vector3(entity.Position.x, entity.Position.y, 0)
);
if (distance < minDistance)
{
minDistance = distance;
nearestPlayer = player;
}
}
return nearestPlayer;
}
}
public class AttackPlayerJob : JobBase
{
private EntityPrefab player;
protected override void UpdateJob()
{
if (player == null || !IsPlayerInRange())
{
StopJob(); // 如果玩家不在范围内,停止攻击工作
return;
}
entity.TryAttack();
}
private bool IsPlayerInRange()
{
float distance = Vector3.Distance(
new Vector3(player.Position.x, player.Position.y, 0),
new Vector3(entity.Position.x, entity.Position.y, 0)
);
return distance <= entity.attributes.attackRange;
}
public override void StartJob(Entity.Entity target)
{
base.StartJob(target);
// 查找最近的玩家作为目标
List<EntityPrefab> players = Managers.EntityManage.Instance.FindEntitiesByFaction("Player");
player = GetNearestPlayer(players);
}
private EntityPrefab GetNearestPlayer(List<EntityPrefab> players)
{
EntityPrefab nearestPlayer = null;
float minDistance = float.MaxValue;
foreach (var player in players)
{
if (!IsPlayerValid(player)) continue;
float distance = Vector3.Distance(
new Vector3(player.Position.x, player.Position.y, 0),
new Vector3(entity.Position.x, entity.Position.y, 0)
);
if (distance < minDistance)
{
minDistance = distance;
nearestPlayer = player;
}
}
return nearestPlayer;
}
private bool IsPlayerValid(EntityPrefab player)
{
return player != null && !player.entity.IsDead;
}
}
public class RangedAttackJob : JobBase
{
private EntityPrefab player;
protected override void UpdateJob()
{
if (player == null || !IsPlayerValid(player))
{
StopJob(); // 如果当前目标无效,停止工作
return;
}
float distance = Vector3.Distance(
new Vector3(player.Position.x, player.Position.y, 0),
new Vector3(entity.Position.x, entity.Position.y, 0)
);
if (distance <= entity.attributes.attackRange)
{
// 如果在攻击范围内,进行攻击
entity.TryAttack();
}
else if (distance > entity.attributes.attackRange && distance < MaxTrackDistance)
{
// 如果距离过远,靠近目标
MoveTowardsPlayer();
}
else if (distance < entity.attributes.attackRange)
{
// 如果距离过近,远离目标
MoveAwayFromPlayer();
}
}
private void MoveTowardsPlayer()
{
Vector3 targetPosition = new Vector3(player.Position.x, player.Position.y, 0);
entity.SetTarget(targetPosition);
entity.TryMove();
}
private void MoveAwayFromPlayer()
{
Vector3 direction = entity.Position - player.Position;
direction.Normalize();
Vector3 targetPosition = entity.Position + direction * RetreatDistance;
entity.SetTarget(targetPosition);
entity.TryMove();
}
public override void StartJob(Entity.Entity target)
{
base.StartJob(target);
// 查找最近的玩家作为目标
List<EntityPrefab> players = Managers.EntityManage.Instance.FindEntitiesByFaction("Player");
player = GetNearestPlayer(players);
}
private EntityPrefab GetNearestPlayer(List<EntityPrefab> players)
{
EntityPrefab nearestPlayer = null;
float minDistance = float.MaxValue;
foreach (var player in players)
{
if (!IsPlayerValid(player)) continue;
float distance = Vector3.Distance(
new Vector3(player.Position.x, player.Position.y, 0),
new Vector3(entity.Position.x, entity.Position.y, 0)
);
if (distance < minDistance)
{
minDistance = distance;
nearestPlayer = player;
}
}
return nearestPlayer;
}
private bool IsPlayerValid(EntityPrefab player)
{
return player != null && !player.entity.IsDead;
}
private const float MaxTrackDistance = 20f; // 最大追踪距离
private const float RetreatDistance = 3f; // 后退距离
}
}