Class AICombatDecision
The single combat decision shared by every attacking state.
public static class AICombatDecision
- Inheritance
-
AICombatDecision
- Inherited Members
Remarks
Melee, ranged, caster, healer, defender and rogue states previously each carried their own
near-identical TryAttack override — five copies of "am I too close? can I cast? do I
walk in?" that drifted apart from one another and could only be verified by playing the
game. They now all funnel through Plan(in AICombatContext) and differ purely in the numbers they
feed it and in what they do with the resulting intent.
Because this is a pure function over plain floats, an archetype asset's behaviour is
directly assertable in an EditMode test — see AICombatDecisionTests and
AIArchetypeAssetTests.
Fields
ENGAGE_SLACK
Multiplier applied to the engagement distance before the NPC bothers closing in. Without the slack the NPC oscillates between "one centimetre too far" and "stop".
public const float ENGAGE_SLACK = 1.1
Field Value
RANGE_APPROACH_FACTOR
Fraction of an ability's range the NPC actually walks to. Stopping exactly at maximum range means the first step the target takes puts the NPC out of range again.
public const float RANGE_APPROACH_FACTOR = 0.9
Field Value
RANGE_HYSTERESIS
How far past its ability range a target may drift before an already-attacking NPC gives up and closes again.
public const float RANGE_HYSTERESIS = 1.1
Field Value
Remarks
Without this the decision at the range boundary is a bare distance <= range,
and a target strafing around that boundary flips the NPC between Attack and
CloseDistance on alternating ticks. Each flip toggles NavMeshAgent.isStopped, and
because the agent has acceleration and braking it never reaches speed in either
direction — the NPC visibly shudders in place instead of either fighting or chasing.
Ten percent is enough to absorb a strafing player without letting the NPC attack from meaningfully outside its stated range.
Methods
Plan(in AICombatContext)
Decides what the NPC should do about its target this tick.
public static AICombatPlan Plan(in AICombatContext context)
Parameters
contextAICombatContextThe measured combat situation.
Returns
- AICombatPlan
The intent plus the distance the movement intents should aim for.
ResolveApproachDistance(in AICombatContext, float)
Where to stop when walking an out-of-range ability into range.
public static float ResolveApproachDistance(in AICombatContext context, float engageDistance)
Parameters
contextAICombatContextThe measured combat situation.
engageDistancefloatThe archetype's engagement distance.
Returns
- float
The distance from the target at which to stop moving.
Remarks
Approaches to a fraction of the ability's range so a moving target does not immediately step back out, but never closer than the archetype's engagement distance — a caster with a 30 m nuke and a 20 m preferred distance stops at 20, not at 27. A melee archetype (no preferred distance) is allowed to close all the way.
ResolveEngageDistance(in AICombatContext)
public static float ResolveEngageDistance(in AICombatContext context)
Parameters
contextAICombatContext
Returns
ResolveSpacing(float, float, float, out float, out float)
The distance this archetype wants to sit at: its preferred distance, or melee reach when it has none.
public static void ResolveSpacing(float preferredDistance, float minComfortDistance, float maxOffensiveReach, out float effectivePreferred, out float effectiveComfort)
Parameters
preferredDistancefloatThe state's preferred distance.
minComfortDistancefloatThe state's comfort distance.
maxOffensiveReachfloatThe NPC's longest offensive reach, 0 if none.
effectivePreferredfloatThe preferred distance to plan with.
effectiveComfortfloatThe comfort distance to plan with.
Remarks
The spacing on a state asset is a hope, not a fact: the Caster archetype prefers 22 m and backs away inside 10 m, and the orc mage that uses it knows one ability that reaches 1.25 m. Taken literally that spacing produced an NPC which kept its distance forever and never attacked — the "constantly retreats to cast range" report.
The preferred distance is capped at the longest offensive reach, and a comfort distance the NPC cannot attack from is dropped: backing away to a range you cannot hit from is not kiting. An NPC that knows no abilities keeps its spacing as authored.