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
Next revisionBoth sides next revision
quick:program [2018/05/18 21:27] pedroquick:program [2020/09/03 09:16] pedro
Line 1: Line 1:
 +<markdown>
 # Programmers Quick Start Guide # Programmers Quick Start Guide
  
Line 16: Line 17:
  
  
-{{ :images:program:StartingPointBehaviors.png }}+![](:images:program:StartingPointBehaviors.png)
  
 If you play that scene, you may have noticed that if the `Enemy` reaches the player, he keeps joined to him and slowly orbitating. This is not, surely enough, a nice behavior for a frightening enemy. We would want our enemy to stop moving and shoot the player when the distance between them reaches a threshold. We will do that adding a new child behavior to the priority selector but we need the `Shoot` action in the first place. If you play that scene, you may have noticed that if the `Enemy` reaches the player, he keeps joined to him and slowly orbitating. This is not, surely enough, a nice behavior for a frightening enemy. We would want our enemy to stop moving and shoot the player when the distance between them reaches a threshold. We will do that adding a new child behavior to the priority selector but we need the `Shoot` action in the first place.
Line 35: Line 36:
 - The class _must have_ an `Action` attribute that determines the name the action will have in the editor. This disconnects the class name and that one shown in the action collection within BB editor, allowing even hierarchical names in a similar way as Unity allows for the shader assets. - The class _must have_ an `Action` attribute that determines the name the action will have in the editor. This disconnects the class name and that one shown in the action collection within BB editor, allowing even hierarchical names in a similar way as Unity allows for the shader assets.
 - The class _could have_ a `Help` attribute with an action description that will be shown in the editor. - The class _could have_ a `Help` attribute with an action description that will be shown in the editor.
-- The class attributes (or properties) that should be available as action parameters in the editor _must have_ an `InParam` attribute, specifying the visible name. This allows you both to use even private attributes as editor parameters, and to specify editor names with characters that would be invalid for a C# identifier (such as spaces). Optionally, when the attribute has a basic type, a default value can also be set.+- The class attributes (or properties) that should be available as action parameters in the editor _must have_ an `InParam` attribute, specifying the visible name. This allows you both to use even private attributes as editor parameters, and to specify editor names with characters that would be invalid for a C# identifier (such as spaces). Optionally, when the attribute has a basic type, a default value can also be set. `Setting a default value by code does not work in some Unity versions, so maybe you will have to set the value in the editor`.
  
 Please note the name difference between the Behavior Bricks `OnUpdate()` method and the common `MonoBehavior::Update()`: this difference is deliberate. In fact, the class `BasePrimitiveAction` _does not_ inherit from `MonoBehavior` at all. `OnUpdate()` must, also, return a `TaskStatus` value. This will inform the execution engine if the action has finished its execution or should still be invoked in the next game loop. Please note the name difference between the Behavior Bricks `OnUpdate()` method and the common `MonoBehavior::Update()`: this difference is deliberate. In fact, the class `BasePrimitiveAction` _does not_ inherit from `MonoBehavior` at all. `OnUpdate()` must, also, return a `TaskStatus` value. This will inform the execution engine if the action has finished its execution or should still be invoked in the next game loop.
Line 104: Line 105:
 - Create a new node in the canvas for the `ShootOnce` action. Note the action parameters in the inspector and, specifically, the default value for the `velocity` parameter. - Create a new node in the canvas for the `ShootOnce` action. Note the action parameters in the inspector and, specifically, the default value for the `velocity` parameter.
  
-{{ :images:program:FirstActionInTheCollection.png }}+![]( :images:program:FirstActionInTheCollection.png )
  
 - We want the shooting parameters to be available in the inspector of those game objects that use the behavior. Select _blackboard_ for all the three input parameters, and create a new field for each one. Use the default names except for `velocity`, where something like `bulletVelocity` is preferred to avoid confusion. - We want the shooting parameters to be available in the inspector of those game objects that use the behavior. Select _blackboard_ for all the three input parameters, and create a new field for each one. Use the default names except for `velocity`, where something like `bulletVelocity` is preferred to avoid confusion.
 - The `velocity` default value has vanished. Keep in mind that it is only used when the parameter is set _using a constant_ in the editor. When using a blackboard parameter, the default value specified in the code attribute is discarded. Fortunately, we can still provide a default value in the behavior. In the `Blackboard` tab see the blackboard parameters just created, and since `bulletVelocity` has a primitive type, you can provide the 30 again. - The `velocity` default value has vanished. Keep in mind that it is only used when the parameter is set _using a constant_ in the editor. When using a blackboard parameter, the default value specified in the code attribute is discarded. Fortunately, we can still provide a default value in the behavior. In the `Blackboard` tab see the blackboard parameters just created, and since `bulletVelocity` has a primitive type, you can provide the 30 again.
  
-{{ :images:program:ShootOnceBlackboardParameters.png }}+![]( :images:program:ShootOnceBlackboardParameters.png )
  
 - Connect the priority selector and the `ShootOnce` action so that shooting is the first child to be considered (higher priority). - Connect the priority selector and the `ShootOnce` action so that shooting is the first child to be considered (higher priority).
 - Right click on the default guard `AlwaysTrue` of the `ShootOnce` node, select `Replace with ...` and choose `Perception/IsTargetClose` from the condition list. Configure the condition with the `Player` as `target`, and 7 as `closeDistance`. As you might remember, the condition for the `MoveToGameObject` action (pursue the player) is exactly the same but the `closeDistance` is set to 15. - Right click on the default guard `AlwaysTrue` of the `ShootOnce` node, select `Replace with ...` and choose `Perception/IsTargetClose` from the condition list. Configure the condition with the `Player` as `target`, and 7 as `closeDistance`. As you might remember, the condition for the `MoveToGameObject` action (pursue the player) is exactly the same but the `closeDistance` is set to 15.
  
-{{ :images:program:BBUsingShootOnce.png }}+![]( :images:program:BBUsingShootOnce.png )
  
 - Close the editor. We will now create the bullet prefab that will be cloned each time the enemy shoots: - Close the editor. We will now create the bullet prefab that will be cloned each time the enemy shoots:
Line 180: Line 181:
 Although our action just shoots a bullet, if you have played the scene you will have noticed that the enemy shoots a high-frequency stream of bullets. Although our action just shoots a bullet, if you have played the scene you will have noticed that the enemy shoots a high-frequency stream of bullets.
  
-{{ :images:program:ShootOnceFinalyBT.png }}+![]( :images:program:ShootOnceFinalyBT.png )
  
 Our `ShootOnce` action ends immediately after instantiating the bullet. That causes _the end of the parent_ priority selector. Fortunately, the root node is a `Repeat` that relaunches the behavior again in the next game loop. Usually, the condition that determines whether the player is near enough to be shot will still be true and the enemy shoots again, repeating the complete cycle. The bullet stream becomes maximum, because the enemy is shooting as fast as possible. Our `ShootOnce` action ends immediately after instantiating the bullet. That causes _the end of the parent_ priority selector. Fortunately, the root node is a `Repeat` that relaunches the behavior again in the next game loop. Usually, the condition that determines whether the player is near enough to be shot will still be true and the enemy shoots again, repeating the complete cycle. The bullet stream becomes maximum, because the enemy is shooting as fast as possible.
Line 386: Line 387:
 - Select the `Directional light` again, and label it with a new tag called `MainLight`. The condition will look for the light by that tag. Please note that a real game will had a better thought out implementation, using some kind of game state manager, for example. But, for shortness sake, we will get along with this one. - Select the `Directional light` again, and label it with a new tag called `MainLight`. The condition will look for the light by that tag. Please note that a real game will had a better thought out implementation, using some kind of game state manager, for example. But, for shortness sake, we will get along with this one.
  
-{{ :images:program:AddTag.png }}+![]( :images:program:AddTag.png )
  
 In Behavior Bricks, conditions are implemented creating a new subclass of `ConditionBase` of the `Pada1.BBCore.Framework` package. It is essentially equal to the known `BasePrimitiveAction` with the exception of some key points: In Behavior Bricks, conditions are implemented creating a new subclass of `ConditionBase` of the `Pada1.BBCore.Framework` package. It is essentially equal to the known `BasePrimitiveAction` with the exception of some key points:
Line 434: Line 435:
 - Set the condition for this new branch to `IsNightCondition`. As soon as night arrives, the condition will be true and the `SleepForever` action, with higher priority, will be chosen. - Set the condition for this new branch to `IsNightCondition`. As soon as night arrives, the condition will be true and the `SleepForever` action, with higher priority, will be chosen.
  
-{{ :images:program:FinalEnemyBehavior.png }}+![]( :images:program:FinalEnemyBehavior.png )
  
 - Play the scene. Note that the enemy stops whatever was doing when the light is nearly off. - Play the scene. Note that the enemy stops whatever was doing when the light is nearly off.
Line 449: Line 450:
 But when a condition is used in a priority selector or a guard decorator, something unpleasant occurs: the execution engine could need to continually call to its `Check()` method to monitor its state. That will happen with higher priority conditions that are currently false, or with the first condition that is currently true. In our example, imagine the light is on (it is daytime), and the enemy is near enough to the player, so it is shooting at him. The state is summarized in the figure, where the `Shoot` action is highlighted as the current action. But when a condition is used in a priority selector or a guard decorator, something unpleasant occurs: the execution engine could need to continually call to its `Check()` method to monitor its state. That will happen with higher priority conditions that are currently false, or with the first condition that is currently true. In our example, imagine the light is on (it is daytime), and the enemy is near enough to the player, so it is shooting at him. The state is summarized in the figure, where the `Shoot` action is highlighted as the current action.
  
-{{ :images:program:PriroityExecutionExample.png }}+![]( :images:program:PriroityExecutionExample.png )
  
 In this situation, the execution state must guarantee _each cycle_ that the night has not yet fallen (`A` condition is still false) _and_ the player is still near enough to be shot (`B` condition is still true). As far as we currently know, that requires the execution engine to invoke `Check()` in both conditions. In general, if a priority selector is executing its n-th child, then _n_ conditions must be checked. When night has fallen, our `SleepForever` does not require CPU at all; but the `IsNightCondition` is checked every frame in order to know if the sleeping `SleepForever` should be still used. In this situation, the execution state must guarantee _each cycle_ that the night has not yet fallen (`A` condition is still false) _and_ the player is still near enough to be shot (`B` condition is still true). As far as we currently know, that requires the execution engine to invoke `Check()` in both conditions. In general, if a priority selector is executing its n-th child, then _n_ conditions must be checked. When night has fallen, our `SleepForever` does not require CPU at all; but the `IsNightCondition` is checked every frame in order to know if the sleeping `SleepForever` should be still used.
Line 485: Line 486:
  
  
-    Now, any object can receive notifications from the light using:+Now, any object can receive notifications from the light using:
  
 <code csharp> <code csharp>
Line 730: Line 731:
  
 --> -->
 +
 +</markdown>