diff --git a/Package/Documentation/Classes/Actions.md b/Package/Documentation/Classes/Actions.md index f0b1ab8a..0aab85f2 100644 --- a/Package/Documentation/Classes/Actions.md +++ b/Package/Documentation/Classes/Actions.md @@ -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 @@ -48,11 +61,20 @@ public class Data : IActionData ``` {% endcode %} -## Action class -An action always inherits from the `ActionBase` 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`, 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" %} diff --git a/Package/Documentation/Classes/AgentBehaviour.md b/Package/Documentation/Classes/AgentBehaviour.md index 322abe20..0ad3b493 100644 --- a/Package/Documentation/Classes/AgentBehaviour.md +++ b/Package/Documentation/Classes/AgentBehaviour.md @@ -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 @@ -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(bool endAction) where TGoal : IGoalBase; @@ -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. @@ -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 diff --git a/Package/Documentation/Classes/Goals.md b/Package/Documentation/Classes/Goals.md index df7af67b..34cb51fa 100644 --- a/Package/Documentation/Classes/Goals.md +++ b/Package/Documentation/Classes/Goals.md @@ -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" %} diff --git a/Package/Documentation/Classes/GoapSet.md b/Package/Documentation/Classes/GoapSet.md index b26e99b0..247bcdad 100644 --- a/Package/Documentation/Classes/GoapSet.md +++ b/Package/Documentation/Classes/GoapSet.md @@ -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. diff --git a/Package/Documentation/Classes/Sensors.md b/Package/Documentation/Classes/Sensors.md index 74d3b709..d51d42da 100644 --- a/Package/Documentation/Classes/Sensors.md +++ b/Package/Documentation/Classes/Sensors.md @@ -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. @@ -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. diff --git a/Package/Documentation/Classes/TargetKeys.md b/Package/Documentation/Classes/TargetKeys.md index 7c49ae74..94094f89 100644 --- a/Package/Documentation/Classes/TargetKeys.md +++ b/Package/Documentation/Classes/TargetKeys.md @@ -1,15 +1,21 @@ # TargetKeys -`TargetKeys` are used to determine the position for a given `TargetKey`. The TargetState is used by the `Planner` to determine distance between `Actions` and the position an `Agent` should move to before performing the action. -A `TargetKey` should be referenced by the `TargetSensor` that determines the position for the `TargetKey`. +`TargetKeys` play a pivotal role in the GOAP system by specifying positions or locations within the game environment. These keys help the `Planner` calculate the distance (and added cost) between `Actions` and the precise location an `Agent` needs to reach before executing a particular action. -## Creating a TargetKey using ScriptableObject -Right click on a folder in the editor and select `Create > Goap > TargetKey`. +Each `TargetKey` is associated with a `TargetSensor`. This sensor is responsible for determining and providing the exact position corresponding to the `TargetKey`. In essence, while the `TargetKey` acts as a label or identifier for a location, the `TargetSensor` ensures that this label is mapped to a valid and up-to-date position in the game world. -## Creating a TargetKey using Code -To create a new `TargetKey`, create a new class that inherits from the `TargetKeyBase` class. +## Creating a TargetKey -### Example +### Using ScriptableObject: + +1. In the Unity editor, right-click on a desired folder. +2. Navigate to `Create > Goap > TargetKey` to generate a new `TargetKey`. + +### Using Code: + +To programmatically create a new `TargetKey`, you'll need to define a new class that inherits from the `TargetKeyBase` class. + +#### Example: {% code title="WanderTarget.cs" lineNumbers="true" %} ```csharp diff --git a/Package/Documentation/Classes/WorldKeys.md b/Package/Documentation/Classes/WorldKeys.md index 0fc15164..9f4632fb 100644 --- a/Package/Documentation/Classes/WorldKeys.md +++ b/Package/Documentation/Classes/WorldKeys.md @@ -1,15 +1,21 @@ # WorldKeys -`WorldKeys` are used to reference to a specific state in the world. The WorldState is used by the `Planner` to determine which `Action` should be performed. -A `WorlKey` should be referenced by the `WorldSensor` that determines the state for the `WorldKey`. +`WorldKeys` are important in the GOAP system. They point to specific things or situations in the game. The `Planner` uses these keys to decide what `Action` an agent should do next. -## Creating a TargetKey using ScriptableObject -Right click on a folder in the editor and select `Create > Goap > WorldKey`. +Each `WorldKey` is connected to a `WorldSensor`. This sensor checks and gives the current value for its `WorldKey`. So, the `WorldKey` tells us what to look for, and the `WorldSensor` tells us the current value of that thing in the game. -## Creating a TargetKey using Code -To create a new `WorldKey`, create a new class that inherits from the `WorldKeyBase` class. +## Creating a WorldKey -### Example +### Using ScriptableObject: + +1. In the Unity editor, right-click on the folder you want. +2. Go to `Create > Goap > WorldKey` to make a new `WorldKey`. + +### Using Code: + +You can also make a new `WorldKey` by writing a class that uses the `WorldKeyBase` class. + +#### Example: {% code title="IsHungry.cs" lineNumbers="true" %} ```csharp diff --git a/Package/Documentation/General/ConditionsAndEffects.md b/Package/Documentation/General/ConditionsAndEffects.md index f0417216..cb7e42da 100644 --- a/Package/Documentation/General/ConditionsAndEffects.md +++ b/Package/Documentation/General/ConditionsAndEffects.md @@ -1,32 +1,60 @@ # Conditions and Effects ## Conditions -Conditions are used to determine what game states (WorldKey) are required for an `Action` to be performed. Based on the requirements of a `Condition` it is matched with `Effects` of other `Actions`. This is used to build the `Graph` that is used by the GOAP Planner. +Conditions are essentially the prerequisites or requirements that need to be met for an action to be executed. They are tied to the game's state, represented by `WorldKey`. -A condition exists of 3 values: -* `key` - The `WorldKey` that is being checked. -* `comparison` - The comparison that is used to check the `WorldKey` value. -* `value` - The value that is used in the comparison. +- **Key**: This is the `WorldKey` that the condition checks. Think of it as a variable or a state in the game world, like "PlayerHealth" or "HasAmmo." + +- **Comparison**: This is how the `WorldKey` is compared to a specific value to determine if the condition is met. The available comparisons are "SmallerThan," "SmallerThanOrEqual," "GreaterThan," and "GreaterThanOrEqual." + +- **Value**: This is the specific value that the `WorldKey` is compared against using the specified comparison. + +For example, a condition might be set up like this: +- **Key**: PlayerHealth +- **Comparison**: GreaterThan +- **Value**: 50 + +This condition checks if the player's health is greater than 50. ## Effects -Effects are used to determine what game states (WorldKey) are changed by an `Action`. Effects can be `positive` (make a value higher) or `negative` (lower a value). +Effects describe the changes that an action brings about in the game's state, again represented by `WorldKey`. -An effect exists of 2 values: -* `key` - The `WorldKey` that is being changed. -* `type` - Whether the value is increased or decreased. +- **Key**: This is the `WorldKey` that the effect modifies. For instance, "PlayerHealth" or "AmmoCount." + +- **Type**: This indicates whether the `WorldKey` value will increase or decrease as a result of the action. + +For instance, an effect might be: +- **Key**: AmmoCount +- **Type**: Decrease + +This effect would decrease the ammo count when the action is executed. ## Matching Conditions and Effects -The comparison enum consists of the following values: +The system matches conditions and effects to determine the sequence of actions that lead to a goal. Here's how the matching works based on the provided documentation: + +- **SmallerThan** and **SmallerThanOrEqual** comparisons in conditions look for actions with **negative effects**. This means if a condition requires a `WorldKey` to be less than a certain value, the system will look for actions that decrease that `WorldKey`. +- **GreaterThan** and **GreaterThanOrEqual** comparisons in conditions look for actions with **positive effects**. So, if a condition requires a `WorldKey` to be greater than a certain value, the system will search for actions that increase that `WorldKey`. + +For example, if there's a condition that checks if "AmmoCount" is `SmallerThan` 5, the system might look for an action with a negative effect on "AmmoCount" (like "ShootBullet"). Conversely, if the condition checks if "AmmoCount" is `GreaterThan` 10, the system might look for an action with a positive effect on "AmmoCount" (like "ReloadGun"). + +In essence, the GOAP system uses these conditions and effects to build a graph of possible actions and sequences, which is then used by the planner to determine the best course of action to achieve a goal. + +## Examples + +Setting conditions and effects through code. + +{% code title="Creat" lineNumbers="true" %} ```csharp -public enum Comparison -{ - SmallerThan, - SmallerThanOrEqual, - GreaterThan, - GreaterThanOrEqual -} +var builder = new GoapSetBuilder("GettingStartedSet"); + +builder.AddAction() + .AddCondition(Comparison.GreaterThanOrEqual, 1) + .AddEffect(false) ``` +{% endcode %} + +Setting conditions and effects through the inspector. -`SmallerThan` and `SmallerThanOrEqual` are matched with `negative` effects and `GreaterThan` and `GreaterThanOrEqual` are matched with `positive` effects. \ No newline at end of file +![action-config.png](../images/scriptable_action.png) \ No newline at end of file diff --git a/Package/Documentation/General/Injection.md b/Package/Documentation/General/Injection.md index e984f2f2..7b012e58 100644 --- a/Package/Documentation/General/Injection.md +++ b/Package/Documentation/General/Injection.md @@ -1,12 +1,23 @@ -# Injection +# Data Injection in GOAP -`Goals`, `Actions` and `Sensors` are all classes managed and created by the GOAP. Sometimes you want to inject data about a scene into these classes. This can be done by creating an injector. +**Data Injection** is a design pattern where an external system provides runtime data to another object or module. In the context of the Goal-Oriented Action Planning (GOAP) system, injection is used to provide specific scene data or dependencies to the core classes (`Goals`, `Actions`, and `Sensors`) managed by the GOAP system. -## Creating an injector -Create a `MonoBehaviour` class that implements the `IGoapInjector` interface. The methods of this class are called right after each class is created. You can use this to implement your own injection logic or implement third party injection libraries. +## Why is Data Injection Needed? -### Example -This is a simple example of an injector that is used in the complex example scene. It injects itself into Actions that implement the `IInjectable` interface. +1. **Decoupling**: GOAP classes are designed to be generic and reusable. By injecting specific data or dependencies from the scene or other systems, you can customize their behavior without modifying their core logic. This separation ensures that the GOAP system remains modular and maintainable. + +2. **Flexibility**: Different scenes or game scenarios might require different data or behaviors. Injection allows you to provide the necessary context to the GOAP classes, enabling them to adapt to various game situations. + +3. **Integration with Third-party Libraries**: By using injection, you can easily integrate third-party libraries or systems with the GOAP framework. For instance, the documentation mentions integrating Zenject, a popular dependency injection framework in Unity. + +## How Does It Work? + +1. **Creating an Injector**: You create a `MonoBehaviour` class that implements the `IGoapInjector` interface. This class will contain methods that are called right after each GOAP class (`Goal`, `Action`, or `Sensor`) is instantiated. Within these methods, you can provide the necessary data or dependencies to the GOAP classes. + +2. **Connecting the Injector**: To let the GOAP system know about your custom injector, you create a class extending `GoapConfigInitializerBase` and bind it to the `GoapRunnerBehaviour` component in the scene. This ensures that your injector is used instead of the default one. + +## Example +In the provided example, the `GoapInjector` class is an injector that provides specific scene data (`ItemFactory`, `ItemCollection`, and `InstanceHandler`). The `CreateItemAction` class is an example of a GOAP action that requires this scene data. The method of signaling the injector to provide the necessary data can vary, and the `IInjectable` interface is just one possible approach. {% code title="GoapInjector.cs" lang="csharp" %} ```csharp @@ -61,8 +72,35 @@ namespace Demos.Complex.Actions ``` {% endcode %} -### Zenject -It's very easy to use Zenject with the GOAP. The GOAP has a built in injector that can be used to inject Zenject dependencies into the GOAP classes. +## Connecting the injector +In order to let the GOAP know you'd like to overwrite one of it's core settings, the `IGoapInjector` in this case you need to create a class that extends `GoapConfigInitializerBase`. + +Add the script to the scene and bind it to the `GoapConfigInitializer` property of the `GoapRunnerBehaviour` component. + +![Goap Config Initializer](../images/goap_config_initializer.png) + +### Example + +{% code title="GoapConfigInitializer.cs" lang="csharp" %} +```csharp +using CrashKonijn.Goap.Behaviours; +using CrashKonijn.Goap.Classes; + +namespace Demos.Complex.Goap +{ + public class GoapConfigInitializer : GoapConfigInitializerBase + { + public override void InitConfig(GoapConfig config) + { + config.GoapInjector = this.GetComponent(); + } + } +} +``` +{% endcode %} + +## Zenject +It's very easy to use Zenject with the GOAP. The GOAP has a built-in injector that can be used to inject Zenject dependencies into the GOAP classes. {% code title="ZenjectGoapInjector.cs" lang="csharp" %} ```csharp @@ -102,30 +140,3 @@ public class ZenjectGoapInjector : MonoBehaviour, IGoapInjector } ``` {% endcode %} - -## Connecting the injector -In order to let the GOAP know you'd like to overwrite one of it's core settings, the `IGoapInjector` in this case you need to create a class that extends `GoapConfigInitializerBase`. - -Add the script to the scene and bind it to the `GoapConfigInitializer` property of the `GoapRunnerBehaviour` component. - -![Goap Config Initializer](../images/goap_config_initializer.png) - -### Example - -{% code title="GoapConfigInitializer.cs" lang="csharp" %} -```csharp -using CrashKonijn.Goap.Behaviours; -using CrashKonijn.Goap.Classes; - -namespace Demos.Complex.Goap -{ - public class GoapConfigInitializer : GoapConfigInitializerBase - { - public override void InitConfig(GoapConfig config) - { - config.GoapInjector = this.GetComponent(); - } - } -} -``` -{% endcode %} \ No newline at end of file diff --git a/Package/Documentation/General/WorldState.md b/Package/Documentation/General/WorldState.md new file mode 100644 index 00000000..7860540f --- /dev/null +++ b/Package/Documentation/General/WorldState.md @@ -0,0 +1,42 @@ +# WorldState + +{% hint style="warning" %} +**Don't use the GOAP WorldState as a source of truth!** In the GOAP system, sensors update the agent's WorldState only when deciding the next action. This means the WorldState can often be outdated. Additionally, using just integers for the WorldState can oversimplify complex situations. For better accuracy and real-time updates, agents should store their data in dedicated MonoBehaviours. +{% endhint %} + +## Enhanced GOAP with Integer Values: + +In traditional GOAP implementations, the world state is often represented using string keys paired with boolean values. This can lead to redundancy, as multiple keys might be needed to represent related states. By transitioning to integer values, the GOAP system becomes more compact, versatile, and expressive. + +### Conditions with Integer Values: + +Conditions, which are the prerequisites or requirements for an action to be executed, benefit immensely from this shift: + +- **Granular Checks**: Instead of binary checks like "Is the health low?", conditions can now evaluate a spectrum of values, such as: + - **Health**: `< 30` (Is the health below 30?) + - **Health**: `>= 70` (Is the health 70 or above?) + +- **Comparison Types**: Conditions utilize specific comparison types (like SmallerThan, GreaterThanOrEqual, etc.) to evaluate the integer values of the `WorldKeys`. This allows for diverse condition checks, enabling actions to be contingent on specific thresholds. + +- **Absence of "Equals" Comparison**: Notably, there isn't an "Equals" comparison in this system. The primary reason is that "Equals" doesn't indicate direction. In the GOAP system, especially with integer values, understanding the direction of change is crucial. For instance, knowing whether a value needs to increase or decrease to satisfy a condition is essential for planning actions. An "Equals" comparison would be ambiguous in this context, as it wouldn't provide clear guidance on which actions are needed to achieve the desired state. + +### Effects with Integer Values: + +Effects, which describe the changes an action brings about in the game's state, also gain enhanced expressiveness: + +- **Direct Modification**: Instead of toggling boolean states, actions can directly modify integer values. For instance, an action might: + - **Increase** the "Health" key, representing healing. + - **Decrease** the "AmmoCount" key, signifying using ammunition. + +- **Unified Representation**: Actions that have opposite effects on the same state can be represented using the same `WorldKey`. For example, both healing and taking damage modify the "Health" key, but in opposite directions. + +### Benefits: + +1. **Reduced Redundancy**: A single integer-based `WorldKey` can represent a range of states, eliminating the need for multiple boolean keys. +2. **Greater Expressiveness**: Conditions and effects can capture a spectrum of values, allowing for nuanced decision-making. +3. **Simplified Logic**: Evaluating conditions and predicting action outcomes become more straightforward with integer values and defined comparison/effect types. +4. **Consistency**: The risk of conflicting or ambiguous world states is reduced, ensuring a more reliable planning process. + +### In Summary: + +The shift to integer values in the GOAP system offers a more compact and versatile representation of world states, conditions, and effects. By combining integer values with specific comparison and effect types, and by deliberately omitting an "Equals" comparison, the system ensures clarity in action planning. This approach provides AI agents with a broader and more flexible decision-making framework, enabling more informed and context-aware behaviors. diff --git a/Package/package.json b/Package/package.json index 1af518f3..7e55d049 100644 --- a/Package/package.json +++ b/Package/package.json @@ -1,6 +1,6 @@ { "name": "com.crashkonijn.goap", - "version": "2.1.8", + "version": "2.1.11", "displayName": "Unity GOAP", "description": "An open source GOAP implementation for unity", "unity": "2022.2",