Files
zeling_v2/Assets/_Game/Scripts/Enemies/AI/BD_CanUseAbility.cs
Joywayer a1b4e629aa feat: Implement Room Streaming System
- Add RoomStreamingManager to manage room loading and unloading based on player proximity.
- Create StreamingBudgetConfigSO for memory and performance budgeting of the streaming system.
- Introduce TransitionDirector to handle seamless and atmospheric fade transitions between rooms.
- Develop WorldGraph to represent room connectivity and facilitate neighbor queries and distance calculations.
- Implement RoomNode and RoomEdge classes to structure room data and connections.
2026-05-23 19:10:29 +08:00

72 lines
3.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.
#if GRAPH_DESIGNER
using UnityEngine;
using Opsive.BehaviorDesigner.Runtime.Tasks;
using Opsive.BehaviorDesigner.Runtime.Tasks.Conditionals;
using BaseGames.Enemies.Abilities;
namespace BaseGames.Enemies.AI
{
/// <summary>
/// 条件abilityId 当前可用(冷却完毕且未在运行)。
/// 可选开启范围、视线、脚踏地面等调度提示检查;
/// 仅当所有启用的条件均满足时才返回 Success。
/// </summary>
[TaskName("Can Use Ability?")]
[TaskCategory("BaseGames/Enemy/Combat")]
[TaskDescription("检查能力是否存在且冷却就绪,支持范围/视线/地面等调度提示检查")]
public sealed class BD_CanUseAbility : Conditional
{
[Tooltip("能力 ScriptableObject优先级高于下方字符串 ID")]
[SerializeField] private EnemyAbilitySO m_AbilitySO;
[Tooltip("能力 ID当 AbilitySO 未赋值时使用)")]
[SerializeField] private string m_AbilityId = "";
[Header("调度提示(可选)")]
[Tooltip("启用后,检查玩家是否在 AbilitySO.preferredRange 范围内")]
[SerializeField] private bool m_CheckRange = false;
[Tooltip("启用后,检查 AbilitySO.requiresLineOfSight 是否满足视线条件")]
[SerializeField] private bool m_CheckLineOfSight = false;
[Tooltip("启用后,检查 AbilitySO.requiresGrounded 是否满足落地条件")]
[SerializeField] private bool m_CheckGrounded = false;
private EnemyBase _enemy;
public override void OnAwake() => _enemy = gameObject.GetComponent<EnemyBase>();
public override TaskStatus OnUpdate()
{
if (_enemy == null) return TaskStatus.Failure;
string id = m_AbilitySO != null ? m_AbilitySO.abilityId : m_AbilityId;
var ab = _enemy.Abilities.Get(id);
if (ab == null || !ab.CanUse) return TaskStatus.Failure;
// ── 调度提示检查(均可在 Inspector 独立开关)──────────────────────────
var config = ab.Config;
if (config != null)
{
if (m_CheckGrounded && config.requiresGrounded && !(_enemy.Movement?.IsGrounded ?? false))
return TaskStatus.Failure;
if (m_CheckLineOfSight && config.requiresLineOfSight && !_enemy.IsPlayerVisible())
return TaskStatus.Failure;
if (m_CheckRange && _enemy.Stats != null)
{
float sqrDist = _enemy.Stats.SqrDistanceToPlayer;
float minSqr = config.preferredMinRange * config.preferredMinRange;
float maxSqr = config.preferredMaxRange * config.preferredMaxRange;
if (sqrDist < minSqr || sqrDist > maxSqr)
return TaskStatus.Failure;
}
}
return TaskStatus.Success;
}
}
}
#endif