Skip to content

Commit

Permalink
Merge pull request #86 from crashkonijn/feature/improve-docs
Browse files Browse the repository at this point in the history
Improved documentation
  • Loading branch information
crashkonijn authored Oct 10, 2023
2 parents df4cd1f + 9e65eec commit 2d068ed
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 142 deletions.
62 changes: 42 additions & 20 deletions Package/Documentation/Classes/Actions.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,53 @@
# Actions

An action is a single step an agent can take to reach a goal. An action has requirements and effects based on which actions are chained together.
In the GOAP system, an action represents a discrete step an agent can undertake to achieve a specific goal. Actions are defined by their requirements and effects, which guide the chaining of actions to form a plan.

An action consists of 3 parts:
- Config
- Action class
- Action data
## Components of an Action

## Action config
A config needs to be created. This config consists of a couple settings needed to run the action and connect it in the GOAP graph.
Actions are composed of three primary parts:

1. **Config**: Configuration settings for the action.
2. **Action Class**: The logic and behavior of the action.
3. **Action Data**: Temporary data storage for the action's state.

## Action Config

The configuration provides essential settings for the action, enabling its integration into the GOAP graph.

### Conditions
Conditions is a list of world states that need to be true in order to perform this action. Each condition references a world key, and whether the value should be true or false.

Conditions are a set of world states that must be met for the action to be executable. Each condition references a `WorldKey` and specifies whether its value should be true or false.

### Effects
Effects is a list of world states that will be true (or false) after performing this action. Each effect references a world key, and whether the resulting value will be true or false.

Effects describe the changes in world states that result from performing the action. Each effect references a `WorldKey` and indicates the expected outcome (true or false).

### BaseCost
The base cost of this action. This is the cost of the action itself, without any additional costs added by the planner (distance for example).

This represents the inherent cost of executing the action, excluding any additional costs (like distance) that the planner might add.

### Target
Each action has a target position. An agent will first move towards this position before performing the action (based on the `MoveMode`). A position is represented by a TargetKey. For example `ClosestApple` or `ClosestEnemy`.

Every action has an associated target position. Before executing the action, the agent will move towards this target, depending on the `MoveMode`. Targets are identified using `TargetKey`, such as `ClosestApple` or `ClosestEnemy`.

### InRange
If the agent is not in range of the target position, it will move towards it. This value determines how close the agent needs to be to the target position before performing the action.

This value specifies the proximity required between the agent and the target position before the action can commence.

## MoveMode
The move mode determines how the agent handles movement in combination with the action. There are 2 different modes:
- `MoveBeforePerforming`: The agent will move towards the target position before performing the action.
- `PerformWhileMoving`: The agent will move towards the target position and perform the action at the same time.

`MoveMode` determines how the action and movement are coordinated:

- **MoveBeforePerforming**: The agent moves to the target position before initiating the action.
- **PerformWhileMoving**: The agent concurrently moves to the target and executes the action.

## Action Data
The action data is used to store the state of the action for a single agent. This data is not persistent between agents or between multiple runs of the same action.

Action data provides temporary storage for the action's state for an individual agent. This data is not shared across agents or across multiple invocations of the same action.

### Action Data Injection
Often you need a reference to other classes on the agent. To do this you can use the `GetComponent` attribute. This will provide you with a cached instance of the component. This is useful for performance reasons, since the `GetComponent` method is quite expensive.

To reference other classes on the agent, use the `GetComponent` attribute. This provides a cached component instance, optimizing performance by avoiding frequent `GetComponent` calls.

{% code lineNumbers="true" %}
```csharp
Expand All @@ -48,11 +61,20 @@ public class Data : IActionData
```
{% endcode %}

## Action class
An action always inherits from the `ActionBase<TData>` class. The generic type is the action data class. The action data class is used to store the state of the action. The action class itself should be stateless, since only one instance is used to perform the same action on multiple agents.
## Action Class

The action class defines the behavior of the action. It should be stateless since a single instance might be used to execute the same action on different agents. The class inherits from `ActionBase<TData>`, where `TData` is the action data class.

### ActionRunState
The `ActionRunState` is an enum that determines the state of the action. It can be one of the following values: `Continue` or `Stop`. Stop will stop the action and return to the planner. Continue will continue the action and perform it again next frame.

This enum indicates the action's current state:

- **Continue**: The action will persist and be re-evaluated in the next frame.
- **Stop**: The action will terminate, and control will revert to the planner.

### Examples

The provided examples illustrate how to implement specific functionalities within the action class and action data. They've been retained in their original form for clarity.

### Examples
{% code title="WanderAction.cs" lineNumbers="true" %}
Expand Down
33 changes: 21 additions & 12 deletions Package/Documentation/Classes/AgentBehaviour.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
# AgentBehaviour
The `AgentBehaviour` needs to be present on every agent that uses GOAP to determine it's next action. An agent belongs to a `GoapSet`. This set contains the config of all available `Goals` and `Actions`.

The AgentBehaviour contains it's current `Goal` and it's currently active `Action`. The action is determined by the planner based on the current goal and the gamestate (`WorldData`).
The `AgentBehaviour` is a crucial component that must be attached to every agent leveraging the GOAP system to decide its subsequent actions. It links an agent to a specific `GoapSet`, which encompasses the configuration of all potential `Goals` and `Actions` the agent can undertake.

## Overview

- **Current Goal**: The objective the agent is currently trying to achieve.
- **Active Action**: The action the agent is currently executing to meet its goal.
- **WorldData**: Represents the game's current state, which the planner uses to decide the best action for the agent.

## Movement
Each action has a target. This target provides a position that the agent should move to before performing the action. Movement is very game specific and therefore not implemented in this package. The agent events contain a couple of events that can be used to determine when an agent should be moved.

It is also possible to make an action perform while moving, see the `MoveMode` on the `ActionConfig`.
Actions often have associated targets, indicating a position the agent should reach before executing the action. Since movement mechanics can vary based on the game's design, this package doesn't prescribe a specific movement implementation. However, it provides events to help developers determine when an agent should move.

### MoveMode

### Distance multiplier
In general the best actions to perform are the fastest way to reach a goal. In that case the cost of an action is probably equal to the time for it to complete. If that's the case than the distance value used in the heuristics should be divided by the move speed of an agent as well.
Some actions might need the agent to perform tasks while moving. The `MoveMode` in the `ActionConfig` allows for such configurations.

If you use `SetDistanceMultiplierSpeed(float speed)` to set the (max / average) speed of an agent, the planner will more accurately determine the best action to perform.
### Distance Multiplier

## Distance
By default the agent will use the `Vector3.Distance` between the agent and the target as it's distance. You can overwrite this distance by assigning your own implementation of `IAgentDistanceObserver` to the `agent.DistanceObserver` variable. This is useful if you want to use the `navMeshAgent.remainingDistance` for example.
The primary objective of actions is to achieve goals swiftly. If the action's cost equates to its completion time, then the heuristic's distance value should be divided by the agent's movement speed. Using `SetDistanceMultiplierSpeed(float speed)` sets the agent's (max/average) speed, enabling the planner to more precisely ascertain the optimal action.

### Custom Distance Calculation

By default, the agent calculates distance using `Vector3.Distance`. However, for more complex scenarios, like using a nav mesh, you can override this by assigning your custom `IAgentDistanceObserver` to the `agent.DistanceObserver`.

### Example

Expand Down Expand Up @@ -52,7 +60,8 @@ public class NavMeshDistanceObserver : MonoBehaviour, IAgentDistanceObserver
## Methods

### SetGoal
This method can be used to change the current goal of the agent. The `endAction` parameter determines if the current action should be ended before the new goal is set. If this is set to `false` the current action will be continued until it is finished.
This method allows for the modification of the agent's current goal. The `endAction` parameter decides if the ongoing action should terminate before setting the new goal.

{% code lineNumbers="true" %}
```csharp
public void SetGoal<TGoal>(bool endAction) where TGoal : IGoalBase;
Expand All @@ -61,7 +70,7 @@ public void SetGoal(IGoalBase goal, bool endAction);
{% endcode %}

## Determining the Goal
Determining the best `Goal` is very game specific. As such this package does not provide a way to determine the best goal.
Choosing the best `Goal` is game-specific, and this package doesn't dictate a method. However, an example is provided below to illustrate how one might determine a goal based on an agent's hunger level.

### Example
This is an example of how to determine the best goal. In this example the agent will wander around until it's hunger is above 80. When it's hunger is above 80 it will try to fix it's hunger. When it's hunger is below 20 it will wander around again.
Expand Down Expand Up @@ -105,7 +114,7 @@ namespace Demos.Behaviours
{% endcode %}

## Events
The `AgentBehaviour` contains a few events that can be used to get notified when the agent changes it's goal or action.
`AgentBehaviour` offers several events that notify developers when the agent alters its goal or action. These events can be instrumental in managing agent behaviors and responses.

### Example

Expand Down
29 changes: 21 additions & 8 deletions Package/Documentation/Classes/Goals.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
# Goals
Goals are used as entry points in the `Planner`. A `Goal` is used to determine the best `Action` that should be performed in order to achieve the `Goal`.

In the GOAP system, `Goals` represent the desired outcomes or objectives that an agent aims to achieve. They serve as the starting points for the `Planner`, guiding it in determining the most suitable `Action` to take in order to fulfill a particular `Goal`.

## Goal Config
`GoalConfig` is used to configure a `Goal`. It contains the following properties:

### classType
The `classType` is the type of the `Goal` that should be used.
The `GoalConfig` provides the necessary settings to define and shape a `Goal`. It encompasses several properties:

### 1. Class Type

**Description**: This property specifies the exact type or category of the `Goal`. It helps in identifying and categorizing different goals within the system.

### 2. Conditions

**Description**: Conditions are a set of criteria based on `WorldKeys` that must be met for the `Goal` to be considered achieved. These conditions guide the `Planner` in its decision-making process, helping it select the best `Action` that aligns with the desired outcome.

For instance, if a `Goal` is to "Stay Safe", conditions might include `WorldKeys` like "IsHealthHigh" or "IsInSafeZone".

## Goal Class

The `Goal` class serves as the blueprint for creating specific goals. Key points about the `Goal` class:

- **Inheritance**: Every `Goal` class is derived from the foundational `GoalBase` class. This ensures that all goals share some basic properties and behaviors.

### conditions
The `conditions` is a list of `WorldKeys` that need to be true or false in order to achieve the `Goal`. Based on these conditions the `Planner` will determine the best `Action` to perform.
- **Statelessness**: A `Goal` class doesn't maintain any internal state. Its primary role is to provide criteria to the `Planner`, which then uses this information to decide on the most appropriate `Action` to execute.

## Goal class
A `Goal` class always inherits from the `GoalBase` class. A `Goal` doesn't contain any state, since it is only used by the `Planner` to determine the best `Action` to perform.
By understanding and configuring `Goals` appropriately, game developers can guide agents towards desired behaviors, ensuring they act in ways that enhance the gameplay experience.

## Example
{% code title="FixHungerGoal.cs" lineNumbers="true" %}
Expand Down
40 changes: 29 additions & 11 deletions Package/Documentation/Classes/GoapSet.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
# GoapSet
The `GoapSet` contains all available `Goals` and `Actions` that an agent can use. Different agents can use different `GoapSets`. This allows for different agents to have different `Goals` and `Actions`.

![Screenshot of GoapSetConfig](../images/goap-set.png)
A `GoapSet` is a collection of all possible `Goals` and `Actions` that an agent can utilize. By using different `GoapSets`, you can customize the behavior of various agents, allowing each to have its unique set of `Goals` and `Actions`.

![GoapSet Configuration Screenshot](../images/goap-set.png)

## GoapSet Config
The `GoapSetConfig` is used to configure a `GoapSet`. It contains the following properties:

### goals
The `goals` is a list of `GoalConfigs` that are available to the `Agent`.
The `GoapSetConfig` is the tool used to define and organize a `GoapSet`. It comprises several properties that detail the available configurations for an agent:

### 1. Goals

**Description**: Goals represent the objectives or desires of an agent. They define what the agent wants to achieve.

This property holds a list of `GoalConfigs`, detailing the various objectives an agent can pursue.

### 2. Actions

**Description**: Actions are the tasks or behaviors an agent can perform. They are the means by which an agent tries to achieve its goals.

This property contains a list of `ActionConfigs`, outlining the set of actions available for the agent to execute.

### 3. Target Sensors

**Description**: Target Sensors help the agent identify and locate important positions or objects in the game world. They can point to static locations or dynamic entities that might move.

This is a list of `TargetSensorConfigs`, assisting the agent in determining key positions or targets it should be aware of.

### 4. World Sensors

**Description**: World Sensors allow the agent to perceive and understand various states or situations in the game. They provide the agent with information about the environment, helping it make informed decisions.

### actions
The `actions` is a list of `ActionConfigs` that are available to the `Agent`.
This property holds a list of `WorldSensorConfigs`, enabling the agent to gather data about the game's current state.

### targetSensors
The `targetSensors` is a list of `TargetSensorConfigs` that are available to the `Agent`.
By configuring the `GoapSetConfig` appropriately, you can tailor the behavior and capabilities of agents, ensuring they act and react in ways that suit the game's requirements.

### worldSensors
The `worldSensors` is a list of `WorldSensorConfigs` that are available to the `Agent`.
---

## Agent Debugger Class
By defining an agent debugger class you can customize the data show in the node viewer in the `Agent data` box. The agent debugger class must inherit from `IAgentDebugger` and be assigned to the property.
Expand Down
39 changes: 16 additions & 23 deletions Package/Documentation/Classes/Sensors.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
# Sensors
Sensors are classes that can determine the state that your game is in.

There are two types of sensors: `WorldSensor` and `TargetSensor`.
Sensors help the GOAP system understand the current game situation.

## Global vs Local
Each sensor operates either in `Local` or `Global` mode.
There are two main types of sensors: `WorldSensor` and `TargetSensor`.

### Global
Global sensors are run each frame. They are used to determine a state for all agents. For example, the `IsDaytimeSensor` determines whether it is daytime or not. This state is shared between all agents.
## Global vs. Local Sensors

### Local
Local sensors are run before the `Planner` is run. They are used to determine a state for a single agent. For example, the `ClosestAppleSensor` determines the position of the closest apple to a specific `Agent`.
Sensors can work in two modes: `Global` or `Local`.

- **Global**: These sensors give information for all agents. For instance, `IsDaytimeSensor` checks if it's day or night for everyone.
- **Local**: These sensors check only when the `Planner` runs. They give information for just one agent. For example, `ClosestAppleSensor` finds the nearest apple for a specific agent.

## WorldSensor
A `WorldSensor` is used to determine the state of the world for an `Agent`. Each state is represented by a `WorldKey`. The WorldState is used by the `Planner` to determine the best `Action` for the current `Goal`.

For example:
- The `IsHungrySensor` determines the `IsHungry` state of the `Agent`.
- The `HasAppleSensor` determines the `HasApple` state of the `Agent`.
`WorldSensor` checks the game's situation for an agent. It uses `WorldKey` to show each situation. The `Planner` uses this to pick the best action.

Examples:
- `IsHungrySensor` checks if the agent is hungry.
- `HasAppleSensor` checks if the agent has an apple.

### Example
To create a new `WorldSensor`, create a new class that inherits from `LocalWorldSensorBase` or `GlobalWorldSensorBase` and implement its `Sense` method.
Expand Down Expand Up @@ -58,20 +58,13 @@ namespace Demos.Simple.Sensors.World
{% endcode %}

## TargetSensor
A `TargetSensor` is used to determine the position for a given `TargetKey`. The TargetState is used by the `Planner` to determine distance between `Actions`.

For example:
- The `ClosestAppleSensor` determines the position of the closest apple.
- The `ClosestTreeSensor` determines the position of the closest tree.

### TransformTarget vs PositionTarget
There are two types of `Target`: `TransformTarget` and `PositionTarget`.
`TargetSensor` finds a position for a `TargetKey`. The `Planner` uses this to know how far actions are.

#### TransformTarget
`TransformTarget` is used when you want to move to a specific `Transform` that may change position over time. For example, the `ClosestEnemySensor` returns a `TransformTarget` because the enemy may move.
There are two kinds of `Target`: `TransformTarget` and `PositionTarget`.

#### PositionTarget
`PositionTarget` is used when you want to move to a specific position that will not change. For example, the `WanderTargetSensor` returns a `PositionTarget` because the position is randomly generated and doesn't change.
- **TransformTarget**: Use this when the target can move. For example, `ClosestEnemySensor` finds a moving enemy.
- **PositionTarget**: Use this for a fixed spot. Like, `WanderTargetSensor` finds a random spot that doesn't move.

### Example
To create a new `TargetSensor`, create a new class that inherits from `LocalTargetSensorBase` or `GlobalTargetSensorBase` and implement its `Sense` method.
Expand Down
Loading

0 comments on commit 2d068ed

Please sign in to comment.