WIP AGV Introduction
DES stands for Discrete Event System and is a way to discretely move objects over time.
How does it work
DES works by moving an object (called an actor) over splines using a motion called a motiontensor. This spline contains what is called cues to signal when the actor hits it. When a cue is hit, it will call the connected Instructor that will contain the code that needs to be executed when that cue is hit.
This is an example of how a cube moves across a spline. Here the cube is the DESActor
. The pink polygons signify the DESCues
. When the DESActor
hits the DESCue
an action will be executed. This action can be defined in a DESInstructor
and is then connected to the DESCue
. The cube in the following image will move across the spline and execute an action when it starts (CUE_1) and when it ends (CUE_2).
How to generate a spline
A motion has to move across a spline, so the first step is to generate one. This can be done by generating it from shots. Shots are positions (positions and rotation) that the actor needs to move across on the splines. The positions that are defined by the shots will become the splinepoints on the spline.
Generating a spline from shots
Generating a spline from shots is a way to generate a spline from moments in time. This can be generated by going to PREscripted > Scenario > Actor Route Creator
The following window will open:
In the “SimulationController” field, select the DESController
in the scene. The DESController
is what controls the simulation and all DES components should always be children of the DESController
. If you do not have a DESController yet, create a new gameobject in the scene and add the DESController
script.
Selecting the DESController will show the following options that can be adjusted when generating the spline.
Route topic → Signifies the name that the parent of the spline will have when generated
Spline Generator Mode → Selects the mode of spline generation.
“STRAIGHT” generates direct lines.
“CONTINUOUS“ generates a smooth line.
“UNIT_CIRCLE“ generates an exact circle.
Spline Pathing Mode → The Spline Pathing mode selects the kind of transformation that will be executed.
“TRAVERSAL_PATH“ uses the position and rotation over the spline to move the object.
“LOOK_AT_PATH“ looks at the current position on the spline as it translates across it.
“ORIENTED_TRAVERSAL_PATH“ should not be used. This has been replaced by the TRAVERSAL_PATH.
Spline Up direction Mode → The spline up direction mode defines how the up direction is used across the spline. When using DES “Free” should always be selected as it uses the up direction defined by the shots.
“Free“ uses the exact up direction defined by the shots. The forward is not used to calculate the up direction
“Spline“, “Local“ and “Global“ should only be used when using prismatic joints.
The Spline, Local and Global always use the spline to set the forward direction and then calculates the closest possible up direction.
“Spline“ calculates the up direction by getting three points on the spline and calculate their average up direction.
“Local“ calculates the up direction by combining the forward and the local defined up direction.
“Global“ calculates the up direction by combining the forward and the global defined up direction.
Next create the objects that need to be moved across the spline. We have created three cubes to generate the spline. These are what we call shots (a position and rotation in the world), the spline will be created from these shots.
Select the cubes in the Hierarchy tab and click the “Generate Shots Based on Selection“ in the Actor Route Creator
window. Please note that the order in the hierarchy will also be the order on the spline.
To add a cue to the point of the shot, go to the shot and select “FREE_CUE“ in the default instruction. This will add a cue on that position on the spline.
Then click “Generate Spline Based on Shots“ and it will generate the spline from the shots. As can be seen we’ve added a free cue to all our shots/spline points.
Adding a motion
There are multiple ways of adding a motion to an actor. In the following code we define a MotionTensorView and generate a MotionTensor from it on startup. By defining the movement in the editor we’ll be able to move the cube.
BasicMotionActor
using System.Collections;
using System.Collections.Generic;
using u040.prespective.prescripted.des;
using UnityEngine;
namespace u040
{
/// <summary>
/// Basic actor that has a movement that will be started at the beginning of the simulation
/// </summary>
public class BasicMotionActor : DESActor
{
public MotionTensorView motionTensorView;
private MotionTensor motionTensor;
public override void OnSimulationStart(ref List<DESEvent> _resultingEvents, ref List<DESRecord> _resultRecords)
{
motionTensorView.GenerateMotionTensor(this, out motionTensor);
this.AddActivity(motionTensor);
base.OnSimulationStart(ref _resultingEvents, ref _resultRecords);
}
}
}
Create a cube beneath the DESController and add the BasicMotionActor
to the cube. Then add a Tensor component by copying the following example.
Start by setting the Tensor Components field to 1 to add a Tensor component. Then set the following parameters:
Spline → The path the movement uses
Thickness → How much room on the spline the object uses
Velocity Curve → The velocity over time
Component Motion Mode → Whether the movement should be absolute or relative
Component Motion Type → What type of movement the spline describes
Weight curve → Balances how much it moves on this spline, only relevant when using multiple splines. When there are multiple motion tensors it describes how strongly it should prefer one over the other.
Spline start mode → Where the actor should start
Start perc override → Override where the motion starts on the spline
Look offset → The object on the spline will use a point slightly ahead of it to change the look direction. This defines how far ahead it is of the object.
When started the the cube will move over the spline we’ve created.
Using Cues
At certain points on the spline we would like to execute an action like pausing, switching splines, etc. This can be accomplished by using cues. When a cue is hit, the corresponding Instructor is called to execute a piece of code.
Create a cue
A cue can be created on a spline. They can be either created when generating the spline as has been noted when creating a spline with the Actor route creator or it can be done manually. Go to the spline you created and create a new empty gameobject as a child. Then add the DESCue
script and set the position by setting the Percentual Position
between 0 and 1.
Creating an Instructor
Next we want it to execute some code when the cue is hit. This code can be defined in a DESInstructor
. The following is a debug instructor that logs every time it is called. Note that the ApplyInstruction
expects a return boolean, the return value indicates if there has been any changes that need recalculations. These are changes that change the motion in the scene like the changing of velocity, changing of spline or parenting changes. If it interacts with the DES system, it needs to return true. In the DebugInstructor
we simply log a message, we don’t interact with the DES system and can return false. Returning false improves performance because no recalculations are triggered, if you’re not sure if a recalculation should be triggered return true to prevent errors.
DebugInstructor
using u040.prespective.prescripted.des;
using UnityEngine;
namespace u040
{
/// <summary>
/// Debug instructor, calls a debug log when hit
/// </summary>
public class DebugInstructor : DESInstructor
{
public override bool ApplyInstruction(ADESActor actor, ADESCue _cue, ActorCueIntersectionEvent _intersectionEvent)
{
Debug.Log("Debug instructor called on " + _cue.gameObject.name);
return false;
}
}
}
Create a new gameobject and attach the DebugInstructor
. Then go to the cue that needs to be connected to it and set the Cue Instructor
field to the DebugInstructor
.
One of the things to note is that this will call the instructor three times (on enter, on center and on exit).
To fix this the following code can be added in the beginning of the apply instruction in the instructor to only work on the center event.
if (_intersectionEvent.IntersectionType != ActorCueIntersectionEvent.CueIntersectionType.CENTER)
{
return false;
}
Prespective Documentation