I'm currently developing a GOAP system in Java. An explanation of GOAP can be found at http://web.media.mit.edu/~jorkin/goap.html. Essentially, it's using A* to plot between Actions that mutate the world state.

To provide a fair chance for all Actions and Goals to execute, I'm using a heuristic function to estimate the cost of doing something. What is the best way to estimate this cost so that it is comparable to all the other costs?

As an example, estimating the cost of running away from an enemy versus attacking it - how should the cost be calculated to be comparable?


To make all the costs comparable, you only need to use the same heuristic for all actions. For example, all actions have a list of potential outcomes and all outcomes have a certain value to the entity.

For example, there's a deep pool with water, and the entity is thirsty. So we look at an action the pool has available to satisfy that need:

First the entity priorities associated with these places, you could call these the modifiers. Some of these will change with time and depend on the entity. For example an ant might worry less about staying alive and more about colony concerns. Or if an entity has gone a while without drink, the satisfy thirst priority may override others.

Entity priorities:

Satisfy thirst: 40
Stay dry: 10
Stay alive: 100

Then what the location represents:

Location: Pool
Action: Collect water
*Potential outcomes: *:
Satisfy thirst - (-95)
Get wet - 10
Drown - 1

So we could calculate that action cost at: (40*-95) + (10*10) + (100*1) = -3600

Where collecting water from a raging river might look like:

Location: Raging river
Action: Collect water
*Potential outcomes: *:
Satisfy thirst - (-95)
Get wet - 90
Drown - 60

(40*-95) + (10*90) + (100*60) = 3100

So it's clearly a better choice to collect water from the pool. Maybe if the raging river was the only choice the entity would wait until its satisfy thirst priority went very high before trying the river.

You may want to keep things much simpler starting out. Just have a few variables that can apply more globally. Like staying alive, satisfy needs. In your fight or flight example, you'd need to give each entity a combat rating, so they could effectively rank themselves against the other entity for score purposes.

  • \$\begingroup\$ Thanks a lot! Predicating on all potential outcomes sounds like a better idea than what I had. \$\endgroup\$ – fullwall Dec 11 '12 at 2:36

I know, I know, it's been quite a while.

Indeed, in GOAP as implemented in 2005 by Jeff Orkin in F.E.A.R. (and reused in the sequels, extension and... Shadow Of Mordor), actions have fixed costs, ranging from 0.5 to 8. In general, the cost of attacking is much more expensive than the cost of defending. These costs can be accessed in the game database of the Free F.E.A.R. SDK (2008); here they are:

{{Animate, 1}, {Attack, 6}, {AttackBurstLimited, 5}, {AttackCrouch, 5}, {AttackFromAmbush, 4}, {AttackFromArmored, 4}, {AttackFromArmoredBounded, 4}, {AttackFromCover, 4}, {AttackFromVehicle, 1}, {AttackFromView, 4.5}, {AttackGrenadeFromCover, 2}, {AttackLunge3D, 1}, {AttackLungeMelee, 1}, {AttackLungeSuicide, 1}, {AttackLungeUncloaked, 1}, {AttackMelee, 3}, {AttackMeleeLong, 1}, {AttackMeleeUncloaked, 3}, {AttackReady, 7}, {AttackTurret, 6}, {AttackTurretCeiling, 6}, {BlindFireFromCover, 2}, {Charge, 1}, {DeathOnVehicle, 1}, {DismountNodeUncloaked, 1}, {DismountVehicle, 1}, {DodgeCovered, 1}, {DodgeOnVehicle, 1}, {DodgeRoll, 2}, {DodgeRollParanoid, 2}, {DodgeShuffle, 3}, {DrawWeapon, 1}, {EscapeDanger, 0.5}, {FaceNode, 1}, {FlushOutWithGrenade, 3}, {Follow, 3}, {FollowHeavyArmor, 2}, {FollowPlayer, 2}, {FollowPlayerFidget, 1.8}, {FollowWaitAtNode, 4}, {GetOutOfTheWay, 1}, {GotoNode, 1}, {GotoNode3D, 1}, {GotoNodeDirect, 1}, {GotoNodeOfType, 1}, {GotoTarget, 4}, {GotoTarget3D, 4}, {GotoTargetLost, 8}, {GotoValidPosition, 1}, {HolsterWeapon, 1}, {Idle, 2}, {IdleFidget, 1}, {IdleOnVehicle, 1}, {IdleTurret, 2}, {InspectDisturbance, 2}, {InstantDeath, 1}, {InstantDeathKnockDown, 1}, {KnockDownBullet, 2}, {KnockDownExplosive, 2}, {KnockDownMelee, 2}, {LongRecoilBullet, 3}, {LongRecoilExplosive, 3}, {LongRecoilHelmetPiercing, 3}, {LongRecoilMelee, 3}, {LookAtDisturbance, 1.5}, {LookAtDisturbanceFromView, 3}, {LopeToTargetUncloaked, 1}, {MountNodeUncloaked, 1}, {MountVehicle, 1}, {ReactToDanger, 1}, {Reload, 5}, {ReloadCovered, 1}, {ReloadCrouch, 5}, {ShortRecoilMelee, 4}, {Stunned, 1}, {SuppressionFire, 2}, {SuppressionFireFromCover, 1}, {SurveyArea, 1}, {TraverseBlockedDoor, 1}, {TraverseLink, 2}, {TraverseLinkUncloaked, 1}, {Uncover, 1}, {UseSmartObjectNode, 3}, {UseSmartObjectNodeMounted, 1}}

But it's not the case in all GOAP implementations and, for instance, the Tomb Raiders have variable costs (e.g. the distance for a Goto action).

Actions also have preconditions and some actions must be played despite the GOAP architecture (e.g. play a "stunned" animation in reaction rapidly decreasing health -- despite the "Kill Enemy" Goal and the plan that GOAP returns to satisfy that Goal). In your exemple, i.e. running away vs attacking, health level can be a precondition (and no need to have variable costs).

Or a Check_Costs() member function is executed before anything else, based on Michael's priorities, and returns the dynamic cost.

Now, please note that in Shadow Of Mordor game developers tried to play with the costs of the actions in order to influence what would be executed on screen. It turns out that it's not that easy and even cheap action don't show up so often: AI in a game supports the player; if the player doesn't do what is expected, the AI will just support that and... what will appear on screen won't be what game design expected.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.