Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
quick:design [2018/11/15 10:39] – [In Behavior Bricks efficiency matters] pedroquick:design [2023/11/16 19:50] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +<markdown>
 # Quick Start Guide # Quick Start Guide
  
Line 26: Line 27:
 - Create the _navitation mesh_ that will be used by both the enemy and the player for pathfinding. Select the floor, go to Window - Navigation and press the _Bake_ button. If you have not yet saved your scene, Unity will ask you to do so now. - Create the _navitation mesh_ that will be used by both the enemy and the player for pathfinding. Select the floor, go to Window - Navigation and press the _Bake_ button. If you have not yet saved your scene, Unity will ask you to do so now.
  
-{{ :images:design:BakeNavigationMesh.png }}+![]( :images:design:BakeNavigationMesh.png )
  
 The scene should be set up now. The scene should be set up now.
  
-{{ :images:design:InitialScene.png }}+![]( :images:design:InitialScene.png )
  
 ## Wander: the first enemy behavior ## Wander: the first enemy behavior
Line 38: Line 39:
 The first step is to create a new behavior tree by writing its name in the text field at the upper part of the `Collection` tab and cliking the `Create new behavior` button. Although it is not important for this tutorial, you can create a hierarchy using `/` in the name (for example `Basic/Wander`). Also you can notice that the name used in the Inspector and the asset name are independent, although in this example we have chosen to make it the same, as shown in the figure. The first step is to create a new behavior tree by writing its name in the text field at the upper part of the `Collection` tab and cliking the `Create new behavior` button. Although it is not important for this tutorial, you can create a hierarchy using `/` in the name (for example `Basic/Wander`). Also you can notice that the name used in the Inspector and the asset name are independent, although in this example we have chosen to make it the same, as shown in the figure.
  
-{{ :images:design:CreateNewBehavior.png }}+![]( :images:design:CreateNewBehavior.png )
  
 Once the new behavior asset has been saved it will appear in the `Behaviors` list and will be opened as a new tab in the behavior graphical editor, showing an initially empty canvas. In order to add a new node to the behavior you just need to right-click on any empty point of the canvas and choose one from the drop-down menu. In order to simplify the search, a text field is available for filtering the elements by name in the menu. Browse the hierarchy to have an idea about the built-in actions, conditions, behaviors and composite nodes. Once the new behavior asset has been saved it will appear in the `Behaviors` list and will be opened as a new tab in the behavior graphical editor, showing an initially empty canvas. In order to add a new node to the behavior you just need to right-click on any empty point of the canvas and choose one from the drop-down menu. In order to simplify the search, a text field is available for filtering the elements by name in the menu. Browse the hierarchy to have an idea about the built-in actions, conditions, behaviors and composite nodes.
  
-{{ :images:design:BBEditor.png }}+![]( :images:design:BBEditor.png )
  
 Our first step will be to make the enemy go to a fixed position, in (-20, 0.5, 20), moving parallel to the upper floor edge. Our first step will be to make the enemy go to a fixed position, in (-20, 0.5, 20), moving parallel to the upper floor edge.
Line 49: Line 50:
 - Click on the new node to select it (a yellow border appears when selected) and click on the `Node` tab in the Behavior Bricks inspector. This tab shows the propoerties of the selected node in the canvas. In this case you will find the _input parameters_, that constitute the information the action needs to know how to proceed. `MoveToPosition` needs the target position, a `Vector3`. Set the values to (-20, 0.5, 20). - Click on the new node to select it (a yellow border appears when selected) and click on the `Node` tab in the Behavior Bricks inspector. This tab shows the propoerties of the selected node in the canvas. In this case you will find the _input parameters_, that constitute the information the action needs to know how to proceed. `MoveToPosition` needs the target position, a `Vector3`. Set the values to (-20, 0.5, 20).
  
-{{ :images:design:WanderFirstSteps.png }}+![]( :images:design:WanderFirstSteps.png )
  
 - All changes are automatically saved in your project so, once done, you can close the Behavior Bricks editor. - All changes are automatically saved in your project so, once done, you can close the Behavior Bricks editor.
Line 56: Line 57:
 At runtime, behaviors are executed by the _behavior executor_, a component that must be added to any game object that would be controlled by Behavior Bricks. Select the `Enemy` and add the component Behavior Bricks - Behavior Executor. At runtime, behaviors are executed by the _behavior executor_, a component that must be added to any game object that would be controlled by Behavior Bricks. Select the `Enemy` and add the component Behavior Bricks - Behavior Executor.
  
-{{ :images:design:AddingTheExecutorComponent.png }}+![]( :images:design:AddingTheExecutorComponent.png )
  
 The new component shown in the Inspector provides a place to drop the behavior to execute. From the asset folders, look for the 'Wander' behavior, and drop it in the Behavior variable. Launch your project and you will see the `Enemy` moving to his left. Be aware of the Unity warning "_The Enemy game object does not have a Nav Mesh Agent component to navigate. One with default values has been added_". This is due to a missing component in the `Enemy`. Specifically, `MoveToPosition` action uses the scene nav mesh, which requires a nav mesh agent component. Unity automatically adds it on runtime when missing, and warns about that. You can avoid the warning adding that component beforehand yourself. The new component shown in the Inspector provides a place to drop the behavior to execute. From the asset folders, look for the 'Wander' behavior, and drop it in the Behavior variable. Launch your project and you will see the `Enemy` moving to his left. Be aware of the Unity warning "_The Enemy game object does not have a Nav Mesh Agent component to navigate. One with default values has been added_". This is due to a missing component in the `Enemy`. Specifically, `MoveToPosition` action uses the scene nav mesh, which requires a nav mesh agent component. Unity automatically adds it on runtime when missing, and warns about that. You can avoid the warning adding that component beforehand yourself.
Line 71: Line 72:
 - Now in the `Blackboard` tab of the BB Inspector we can find the new _behavior input parameter_ with that name. You can change the value for the parameter there. - Now in the `Blackboard` tab of the BB Inspector we can find the new _behavior input parameter_ with that name. You can change the value for the parameter there.
  
-{{ :images:design:FirstBlackboardParameter.png }}+![]( :images:design:FirstBlackboardParameter.png )
  
 As seen, the value for the new blackboard field can be globally changed in the behavior properties. But, more interesting, it can also be changed in the behavior executor component properties: As seen, the value for the new blackboard field can be globally changed in the behavior properties. But, more interesting, it can also be changed in the behavior executor component properties:
Line 80: Line 81:
 - Change the value to (-20, 0.5, 20) in order to mimic the initial configuration. - Change the value to (-20, 0.5, 20) in order to mimic the initial configuration.
  
-{{ :images:design:blackboardParameterInTheComponent.png }}+![]( :images:design:blackboardParameterInTheComponent.png )
  
  
Line 95: Line 96:
 - Select the previous `wanderTarget` as the blackboard parameter where the action will write the selected position.  - Select the previous `wanderTarget` as the blackboard parameter where the action will write the selected position. 
  
-{{ :images:design:GetRandomInAreaProperties.png }} +![]( :images:design:GetRandomInAreaProperties.png )
  
 The key point here is that the actions `GetRandomInArea` and `MoveToPosition` are now connected through the `wanderTarget` blackboard parameter. The key point here is that the actions `GetRandomInArea` and `MoveToPosition` are now connected through the `wanderTarget` blackboard parameter.
Line 102: Line 103:
 - Note the behavior executor component. Now it has _two_ parameters, the old `wanderTarget` and the new one `wanderArea`. - Note the behavior executor component. Now it has _two_ parameters, the old `wanderTarget` and the new one `wanderArea`.
  
-{{ :images:design:WanderParametersInComponent.png }}+![]( :images:design:WanderParametersInComponent.png )
  
 - `wanderTarget` is actually an _internal_ value that should not be manipulated from the outside. It is something like _temporal information_ that the behavior needs, but that is unimportant when using the behavior in a game object. - `wanderTarget` is actually an _internal_ value that should not be manipulated from the outside. It is something like _temporal information_ that the behavior needs, but that is unimportant when using the behavior in a game object.
Line 109: Line 110:
 - Change the type of the `wanderTarget` parameter to "`LOCAL`". - Change the type of the `wanderTarget` parameter to "`LOCAL`".
  
-{{ :images:design:ChangingBlackboardParamType.png }}+![]( :images:design:ChangingBlackboardParamType.png )
  
 - Note that now the `wanderTarget` parameter has disappeared from the behavior executor component in the `Enemy`. - Note that now the `wanderTarget` parameter has disappeared from the behavior executor component in the `Enemy`.
Line 115: Line 116:
 In this moment we have two actions in our behavior but what of them will be executed earlier? Obviously, we want the `GetRandomInArea` to be executed before `MoveToPosition`, but if you observe both actions, you will notice the `R` in the upper-right corner of one of the nodes. In this moment we have two actions in our behavior but what of them will be executed earlier? Obviously, we want the `GetRandomInArea` to be executed before `MoveToPosition`, but if you observe both actions, you will notice the `R` in the upper-right corner of one of the nodes.
  
-{{ :images:design:TwoActionsWithNoParent.png }}+![]( :images:design:TwoActionsWithNoParent.png )
  
 The action marked with an _R_ (`MoveToPosition`) is the root of the behavior tree and will be executed in the first place. In fact, `GetRandomInArea` will _not be_ executed at all. In order to create a behavior with _two_ actions, we need to _compose them_. The action marked with an _R_ (`MoveToPosition`) is the root of the behavior tree and will be executed in the first place. In fact, `GetRandomInArea` will _not be_ executed at all. In order to create a behavior with _two_ actions, we need to _compose them_.
Line 121: Line 122:
 - Right click on the canvas an add a composite `Sequence Node`. The concrete position is unimportant: you can move it afterwards. Arrange the nodes in a way similar to the figure. A `Sequence` is a composite node that executes _its children_ in order. - Right click on the canvas an add a composite `Sequence Node`. The concrete position is unimportant: you can move it afterwards. Arrange the nodes in a way similar to the figure. A `Sequence` is a composite node that executes _its children_ in order.
  
-{{ :images:design:AddingASequence.png }}+![]( :images:design:AddingASequence.png )
  
 - Click on the bottom _handle_ in the `Sequence` and then click on top handle of the `GetRandomInArea` node. This will create a _connection_ relating both _nodes_. A connection can be easily removed by right clicking on it and selecting `Remove connection` in the drop-down menu. - Click on the bottom _handle_ in the `Sequence` and then click on top handle of the `GetRandomInArea` node. This will create a _connection_ relating both _nodes_. A connection can be easily removed by right clicking on it and selecting `Remove connection` in the drop-down menu.
 - Create a new connection from the `Sequence` into `MoveToPosition`. Observe that the `R` marking the root moves to the `Sequence` node. Our behavior _is now a valid tree_. The executor will start with the sequence, that will, in turn, execute the `GetRandomInArea` action and then the `MoveToPosition` one, following a left-to-right order. The order is marked by numbers in the top right corner of the node, and can be altered just by dragging the nodes. For example, by dragging the `MoveToPosition` node to the left of the `GetRandomInArea` node we can alter the order of execution of the sequence children. - Create a new connection from the `Sequence` into `MoveToPosition`. Observe that the `R` marking the root moves to the `Sequence` node. Our behavior _is now a valid tree_. The executor will start with the sequence, that will, in turn, execute the `GetRandomInArea` action and then the `MoveToPosition` one, following a left-to-right order. The order is marked by numbers in the top right corner of the node, and can be altered just by dragging the nodes. For example, by dragging the `MoveToPosition` node to the left of the `GetRandomInArea` node we can alter the order of execution of the sequence children.
  
-{{ :images:design:CreatingASequence.png }}+![]( :images:design:CreatingASequence.png )
  
 - The sequence executes its children _once_. We want the enemy to continually wander around, so when it reaches the random position, another one should be selected and the enemy should go there. - The sequence executes its children _once_. We want the enemy to continually wander around, so when it reaches the random position, another one should be selected and the enemy should go there.
Line 132: Line 133:
 - Create a connection from the `Repeat` node to the `Sequence`. Observe how the  `R` mark readjusts itself. - Create a connection from the `Repeat` node to the `Sequence`. Observe how the  `R` mark readjusts itself.
  
-{{ :images:design:WanderBehavior.png }}+![]( :images:design:WanderBehavior.png )
  
 - Close the editor. Remember that behaviors are automatically saved. - Close the editor. Remember that behaviors are automatically saved.
-- Select, if needed, the `Enemy` game object and observe the behavior executor parameters. Remember that the `wanderArea` is still unestablished so the `GetRandomInArea` does not know the area where the position should be chosen from. Specifically, `GetRandomInArea` requires a game object _with a box or sphere collider_.+ 
 +If neededor if you haven't used the "InitialScene": 
 + 
 +- Select, the `Enemy` game object and observe the behavior executor parameters. Remember that the `wanderArea` is still unestablished so the `GetRandomInArea` does not know the area where the position should be chosen from. Specifically, `GetRandomInArea` requires a game object _with a box or sphere collider_.
 - Select the `Floor` game object, and add it a Box collider. Set (10, 0, 10) as its size. - Select the `Floor` game object, and add it a Box collider. Set (10, 0, 10) as its size.
 - Select the `Enemy` game object, and drag and drop the `Floor` into the `wanderArea` parameter. - Select the `Enemy` game object, and drag and drop the `Floor` into the `wanderArea` parameter.
Line 157: Line 161:
  
 Conditions are nodes that, when reached, end immediately and inform their parent nodes whether they were evaluated as `true` or `false`. In behavior jargon, when a node returns `false` it is said to _fail_, and to _succeed_ if returns `true`. The distinctive feature of the internal composite nodes (`Sequence`'s and `Repeat' `s are the only ones we have used so far) is how they react to the values returned by their children conditions (if they _fail_ or _succeed_). Conditions are nodes that, when reached, end immediately and inform their parent nodes whether they were evaluated as `true` or `false`. In behavior jargon, when a node returns `false` it is said to _fail_, and to _succeed_ if returns `true`. The distinctive feature of the internal composite nodes (`Sequence`'s and `Repeat' `s are the only ones we have used so far) is how they react to the values returned by their children conditions (if they _fail_ or _succeed_).
- 
-<!-- 
-In a behavior, any node can prematurely end and _fail_. Imagine a situation where a buggy behavior asks an NPC to move to an unreachable area. In that case, the `MoveToPosition` action will not be able to locomete the game object to that position and just ends and _fails_. 
- 
-Ideally, behaviors should not be buggy and actions will never fail. Instead, this feature is used for _conditions_, that "sense" the environment and end with success or failure depending on that perception. 
- 
-Keep in mind that, from the behavior point of view, actions and conditions are _exactly the same_. But, when creating behaviors it is clarifying think about them as different concepts. Behavior Bricks uses in fact different colors for actions and conditions, and the Collection keeps them in different branches. As a rule of the thumb: 
- 
-- __Actions__: 
-    - Change the environment. 
-    - Usually last more than one game loop. 
-    - Hardly fail. 
-- __Conditions__: 
-    - Perceive the environment. 
-    - Usually last just one loop. 
-    - End with success or failure depending on the environment state. 
---> 
  
 In this section we will use the built-in `CheckMouseButton` condition that test if the user has just pressed one of the mouse buttons and ends with success in that case. In this section we will use the built-in `CheckMouseButton` condition that test if the user has just pressed one of the mouse buttons and ends with success in that case.
Line 190: Line 177:
 - Add a `Repeat` node so the sequence loops again and again and the user can move around to different positions. - Add a `Repeat` node so the sequence loops again and again and the user can move around to different positions.
  
-{{ :images:design:ClickAndGo.png }}+![]( :images:design:ClickAndGo.png )
  
 - Close the editor and add a Behavior executor component in the `Player` game object. Attach to it the `ClickAndGo` behavior. - Close the editor and add a Behavior executor component in the `Player` game object. Attach to it the `ClickAndGo` behavior.
Line 237: Line 224:
 - Create a connection from the `Priority` to the `MoveToGameObject`. Note the yellow node that appears on top of the `MoveToGameObject` action. Every child of a priority must be a guarded node composed of a condition plus an action (or behavior). Therefore when a `Priority` node is connected to a `MoveToGameObject` node, a default `AlwaysTrue` condition is automatically added to guard the `MoveToGameObject` action node. - Create a connection from the `Priority` to the `MoveToGameObject`. Note the yellow node that appears on top of the `MoveToGameObject` action. Every child of a priority must be a guarded node composed of a condition plus an action (or behavior). Therefore when a `Priority` node is connected to a `MoveToGameObject` node, a default `AlwaysTrue` condition is automatically added to guard the `MoveToGameObject` action node.
  
-{{ :images:design:DefaultPriorityCondition.png }}+![]( :images:design:DefaultPriorityCondition.png )
  
 - Select the `AlwaysTrue` node, right-click on it and select `Replace with ...` in the drop-down menu, and finally select `IsTargetClose` in the list of available conditions. - Select the `AlwaysTrue` node, right-click on it and select `Replace with ...` in the drop-down menu, and finally select `IsTargetClose` in the list of available conditions.
  
-{{ :images:design:ChangingPriorityCondition.png }}+![]( :images:design:ChangingPriorityCondition.png )
  
 - `IsTargetClose` has two parameters: - `IsTargetClose` has two parameters:
Line 249: Line 236:
 - Add a new `MoveToPosition` node and make it the second child of the priority, becoming the fall-back behavior. This time instead of first creating the action and then connecting it to the priority, click on the bottom connection area of the priority, then click on an empty point in the canvas, and finally select `MoveToPosition` in the drop-down menu. Set the `MoveToPosition` `target` parameter to the constant value (-20, 0.5, 0). - Add a new `MoveToPosition` node and make it the second child of the priority, becoming the fall-back behavior. This time instead of first creating the action and then connecting it to the priority, click on the bottom connection area of the priority, then click on an empty point in the canvas, and finally select `MoveToPosition` in the drop-down menu. Set the `MoveToPosition` `target` parameter to the constant value (-20, 0.5, 0).
  
-{{ :images:design:PursueOrGoHome.png }}+![]( :images:design:PursueOrGoHome.png )
  
 - Close the editor and set the new behavior to the enemy, substituting the previous one, `Wander`. Note that the old one will not be removed from your behavior Collection. - Close the editor and set the new behavior to the enemy, substituting the previous one, `Wander`. Note that the old one will not be removed from your behavior Collection.
Line 271: Line 258:
 - Make the `Wander` node the fall-back (`AlwaysTrue`) child of the `Priority`. - Make the `Wander` node the fall-back (`AlwaysTrue`) child of the `Priority`.
  
-{{ :images:design:ReusingABehavior.png }}+![]( :images:design:ReusingABehavior.png )
  
 - Remember to assign the Floor GameObject to the wanderArea parameter in the Unity Inspector. - Remember to assign the Floor GameObject to the wanderArea parameter in the Unity Inspector.
Line 287: Line 274:
 - Open it into your preferred editor and substitute the default code with: - Open it into your preferred editor and substitute the default code with:
  
-<code csharp>+```csharp
     using UnityEngine;     using UnityEngine;
  
Line 310: Line 297:
      }      }
     }     }
-</code>+```
  
  
Line 320: Line 307:
 - In the `Player` field drag the `Player` object from the scene - In the `Player` field drag the `Player` object from the scene
  
-{{ :images:design:SpawnParameters.png }}+![]( :images:design:SpawnParameters.png )
  
-{{ :images:design:SpawnScene.png }}+![]( :images:design:SpawnScene.png )
  
 Now play the scene and everything should work as before. Now play the scene and everything should work as before.
Line 335: Line 322:
 - Open it into your preferred editor and substitute the default code with: - Open it into your preferred editor and substitute the default code with:
  
-<code csharp>+```csharp
     using UnityEngine;     using UnityEngine;
     using System.Collections;     using System.Collections;
Line 411: Line 398:
         }         }
     }     }
-</code>+```csharp 
  
 - Add the `MassSpawner` component to the `Spawn` object - Add the `MassSpawner` component to the `Spawn` object
Line 418: Line 406:
 - in the `Spawns` field you can specify the numher of enemies to spawn - in the `Spawns` field you can specify the numher of enemies to spawn
  
-{{ :images:design:MassSpawnerParameters.png }}+![]( :images:design:MassSpawnerParameters.png )
  
 Once the enemies have been spawn you can check the scene stats, by pressing the `Stats` button in the `Game` pannel, and see how many frames per second (FPS) are you getting, 50 in the example shown in the figure. Once the enemies have been spawn you can check the scene stats, by pressing the `Stats` button in the `Game` pannel, and see how many frames per second (FPS) are you getting, 50 in the example shown in the figure.
  
-{{ :images:design:PerformanceTest1.png }}+![]( :images:design:PerformanceTest1.png )
  
 One way to increase the performance without decreasing the number of spawns or making modifications to the behavior tree is to modify the field `Max Task Per Tick` of the `Behavior Executor` component of the `Enemy prefab`, by default its value is 500. Set it to `1`, play the scene again and see how it affects performance. In this case our frame rate increases up to 65 FPS without apparently affecting the observed behavior of the enemies. One way to increase the performance without decreasing the number of spawns or making modifications to the behavior tree is to modify the field `Max Task Per Tick` of the `Behavior Executor` component of the `Enemy prefab`, by default its value is 500. Set it to `1`, play the scene again and see how it affects performance. In this case our frame rate increases up to 65 FPS without apparently affecting the observed behavior of the enemies.
  
-{{ :images:design:PerformanceTest2.png }}+![]( :images:design:PerformanceTest2.png )
  
 ## What's next? ## What's next?
  
 Congratulations! You've just finished the first Behavior Bricks tutorial. You have learned the basics of the editor, and the main concepts: actions, conditions, blackboard, internal nodes, and reusability. If you want to test your newly acquired knowledge, you can, for example, improve the player behavior. Currently, once a position has been selected, it cannot be changed until the player avatar has reached it. It would be great if the player could select a different position using the mouse to overwrite the previous one. Using a priority selector it is easier that it sounds! And it you need some inspiration, you can always have a look at the behavior in the Collection. Finally, remember if you have had any problem following this tutorial, you have available the final scene in the `Samples\QuickStartGuide\Done` folder of the Behavior Bricks package. Congratulations! You've just finished the first Behavior Bricks tutorial. You have learned the basics of the editor, and the main concepts: actions, conditions, blackboard, internal nodes, and reusability. If you want to test your newly acquired knowledge, you can, for example, improve the player behavior. Currently, once a position has been selected, it cannot be changed until the player avatar has reached it. It would be great if the player could select a different position using the mouse to overwrite the previous one. Using a priority selector it is easier that it sounds! And it you need some inspiration, you can always have a look at the behavior in the Collection. Finally, remember if you have had any problem following this tutorial, you have available the final scene in the `Samples\QuickStartGuide\Done` folder of the Behavior Bricks package.
 +
 +</markdown>