Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Goal: Learn how to create a MotionWeb for a Crane using the ActorMotionPathGraph MotionMap tool

Video Tutorial: https://www.youtube.com/watch?v=1ois7rwUZ3Q

Tip: Watch the video on YouTube in FullScreen mode and use HD quality (settings) to read the script clearly!

...

Introduction

This tutorial explains how you can create an ActorMotionPathGraph MotionMap to control a crane where the Horizontal, Vertical and Rotator actors are dependent on each other. This ActorMotionPathGraph MotionMap will be used in the next tutorial called “CranePickupAndDropoff” (https://unit040.atlassian.net/wiki/spaces/PAD/pages/2099216385)

Scene

The scene hierarchy consists of the following components:

  • DES Controller: Controls the simulation and therefore has to be at the top of the hierarchy

  • CraneInstructor: Controls the three crane actors according to the sequence in the CraneInstructor script and is of type MotionWebInstructor.

  • CraneRotatorActor: The top part of the crane that will rotate (vertical tower and horizontal boom) and that sits on the base. It has two children, the CraneVerticalActor and CraneHorizontalActor and is of type MotionWebActor.

  • CraneVerticalActor: The fixed horizontal boom with its child the CraneHorizontalActor. This child is the moving telescopic horizontal boom. Is of type MotionWebActor.

  • CraneHorizontalActor: The moving telescopic horizontal boom with its child the VacuumGripper. Is of type MotionWebActor.

  • MotionWebHorizontal: Spline web with cues that the CraneHorizontalActor can move over. Created by the ActorMotionPathGraph.

  • MotionWebVertical: Spline web with cues that the CraneVerticalActor can move over. Created by the ActorMotionPathGraph.

  • MotionWebRotator: Spline web with cues that the CraneRotatorActor can move over. Created by the ActorMotionPathGraph.

...

...

The following ActorMotionPathGraph is used for this tutorial.

...

Setup steps

  1. Create a new Scene.

  2. Drag the DESControllerUnrigged prefab into the scene and unpack it.

  3. Ensure the scene hierarchy looks as follows (DESController>CraneInstructor>CraneRotatorActor>CraneVerticalActor>CraneHorizontalActor):

    Image Added

  4. Add a DESController script to the DESController GameObject, and similarly add the scripts in the Scripts folder to the correspondingly named GameObjects.

  5. While still in the Scripts folder, right-click in the Asset Explorer. This will open a menu.

  6. Navigate to Create > DES > New Actor Motion Path Graph and click on it to create a new MotionMap

    Image Added

  7. With the new MotionMap selected, click on Open Motion Path Graph Editor within the Inspector. This will open a new window.

    Image Added

  8. In this window, right click in the empty space. This will open the following menu:

    Image Added

  9. Click on New > Node > Actor Node

  10. Click on the newly created Node to select it. It should look like this:

    Image Added

  11. Drag one of the Actors in the hierarchy to the Actor Transform field.

  12. Enter a name for the motion web in the Motion Web Name field.

  13. Repeat this for the other 2 remaining Actors.

  14. The result should look like this:

    Image Added

  15. Connect the Actors according to their hierarchy by click and dragging between Child and Parent ports:

    Image Added

  16. Open the creation menu again by right clicking in the empty space, and select New > Node> Path Node. Repeat this twice so you have 3 new Path Nodes.

  17. Connect each path to one of the actors using the Paths port on the Actor Nodes and the Owner Actor ports on the Path Nodes. The result should look like this:

    Image Added

  18. Select the Path Node connected to the CraneHorizontalActor.

  19. Enter a name in the Spline Name field.

  20. Ensure Spline Type is set to STRAIGHT and Path type set to TRAVERSAL_PATH.

  21. Ensure there are 2 shots in the Shots container.

  22. Unfold both shots and rename them to HorizontalIn and HorizontalOut. If not named correctly, the simulation will not work!

  23. Set the Type to LINKED_CUE for both shots.

  24. In the Linked Instructor field, select the CraneInstructor for both shots.

  25. With the HorizontalActor in its default position (as it was in the prefab), click on Record Shot for the HorizontalIn shot. See below for the default position:

    Image Added

  26. Move the HorizontalActor to its extended position and click on Record Shot for the HorizontalOut shot. See below:

    Image Added

  27. You can check if the shots were correctly recorded by clicking on Move Actor to Shot on either shot.

  28. Select the CraneHorizontalActor Node in the MotionMap.

  29. Click on Generate Motion Web.

  30. A Spline with two Cues should now be generated in the scene:

    Image Added

  31. Select the Path Node connected to the CraneVerticalActor.

  32. Enter a name in the Spline Name field.

  33. Ensure Spline Type is set to STRAIGHT and Path type set to TRAVERSAL_PATH.

  34. Ensure there are 2 shots in the Shots container.

  35. Unfold both shots and rename them to VerticalTop and VerticalBottom. If not named correctly, the simulation will not work!

  36. Set the Type to LINKED_CUE for both shots.

  37. In the Linked Instructor field, select the CraneInstructor for both shots.

  38. With the VerticalActor in its default position (as it was in the prefab), click on Record Shot for the VerticalTop shot.

  39. Move the VerticalActor to its bottom position and click on Record Shot for the VerticalBottom shot. See below:

    Image Added

  40. You can check if the shots were correctly recorded by clicking on Move Actor to Shot on either shot.

  41. Select the CraneVerticalActor Node in the MotionMap.

  42. Click on Generate Motion Web.

  43. A Spline with two Cues should now be generated in the scene:

    Image Added

  44. Select the Path Node connected to the CraneRotatorActor.

  45. Enter a name in the Spline Name field.

  46. Ensure Spline Type is set to UNIT_CIRCLE and Path type set to LOOK_AT_PATH.

  47. Ensure there are 2 shots in the Shots container.

  48. Click on Add Shot in the Node and ensure there are now 3 shots.

  49. Unfold all shots and rename them to RotatePickup, RotateMid and RotateDropoff. If not named correctly, the simulation will not work!

  50. Set the Type to LINKED_CUE for both shots.

  51. In the Linked Instructor field, select the CraneInstructor for both shots.

  52. With the RotatorActor in its default position (as it was in the prefab), click on Record Shot for the RotatePickup shot.

    Image Added
  53. Rotate the RotatorActor to its middle position (set the Y-rotation of the transform to 90) and click on Record Shot for the RotateMid shot.

    Image Added

  54. Rotate the RotatorActor to its end position (set the Y-rotation of the transform to 180) and click on Record Shot for the RotateDropoff shot.

    Image Added
  55. You can check if the shots were correctly recorded by clicking on Move Actor to Shot on either shot.

  56. Select the CraneVerticalActor Node in the MotionMap.

  57. Click on Generate Motion Web.

  58. A Circular Spline with 3 Cues should now be generated in the scene:

    Image Added

  59. Save the MotionMap by clicking on Save Motion Map in the top left corner of the window.

  60. Select the CraneInstructor in the Scene Hierarchy.

  61. Click on Re-Index Motion Web From Selection.

  62. Select the CraneRotatorActor in the Scene Hierarchy.

  63. Set Motion Mode on Motion Web to Absolute.

  64. Set Motion Type on Motion Web to Look Rotation (and ensure that any other type is NOT selected!).

  65. Ensure that Teleport Actor to Closest Node is NOT selected.

  66. Press Play.

MotionMap

The following MotionMap was created in this tutorial:

...

Image Added

Image Added

Image Added

Scripts

CraneInstructor Script

Script 1 The CraneInstructor script that controls the actors in the MotionWeb

Code Block
breakoutModefull-width
languagec#
using System.Collections.Generic;
using u040.prespective.prescripted.des;
using u040.prespective.prescripted.des.events;
using u040.prespective.prescripted.des.motionweb;
using UnityEngine;

namespace u040.prespective.demos.actorMotionPathGraph
{
    //Define as MotionWebInstructor to use the ActorMotionPathGraph
    public class CraneInstructor : MotionWebInstructor
    {
        //Used to start the sequence only once
        bool started = false;

        //Function that runs every frame
        public override void OnSimulationFrameUpdate(double _passedFrameTime, double _totalFrameTime, long _frameID, int _framePass, ref List<DESEvent> _resultingEvents, ref List<DESRecord> _resultRecords)
        {
            //Exit if simulator is not running or sequence has already started
            if (_framePass <= 0 || started)
            {
                return;
            }

            //Make sure sequence is only started once
            started = true;

            //Look up MotionWebActors in the scene
            CraneRotatorActor _rotator = this.GetMotionWebActorsByType<CraneRotatorActor>()[0];
            CraneVerticalActor _vertical = this.GetMotionWebActorsByType<CraneVerticalActor>()[0];
            CraneHorizontalActor _horizontal = this.GetMotionWebActorsByType<CraneHorizontalActor>()[0];

            Debug.Log("START STATEMACHINE");

            //Statemachine Sequence
            MotionWebInstructionSequence _sequence = new MotionWebInstructionSequence()
            {
                SequenceID = "CraneSequence",
                OnSequenceComplete = null,
                Verbose = false,
                InstructionSteps = new List<MotionWebInstructionStep>()
                {
                    //1: To VerticalTop
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "1_VerticalTop",                                         //Name
                        .1d,                                                     //Velocity
                        _vertical,                                               //Actor
                        "CUE_VerticalTop"                                        //Target cue
                        ),

                    //2: To HorizontalIn
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "2_HorizontalIn",                                         //Name
                        .1d,                                                      //Velocity
                        _horizontal,                                              //Actor
                        "CUE_HorizontalIn",                                       //Target cue
                        new List<string>(){ "1_VerticalTop" }                     //Previous step
                        ),

                    //3: To RotationPickup
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "3_RotateToPickup",                                        //Name
                        .5d,                                                       //Velocity
                        _rotator,                                                  //Actor
                        "CUE_RotatePickup",                                        //Target cue
                        new List<string>(){ "2_HorizontalIn" }                     //Previous step
                        ),

                    //4: To HorizontalOut
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "4_HorizontalOut",                                         //Name
                        .1d,                                                       //Velocity
                        _horizontal,                                               //Actor
                        "CUE_HorizontalOut",                                       //Target cue
                        new List<string>(){ "3_RotateToPickup" }                   //Previous step
                        ),

                    //5: To VerticalBottom (PICKUP)
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "5_VerticalBottom",                                        //Name
                        .1d,                                                       //Velocity
                        _vertical,                                                 //Actor
                        "CUE_VerticalBottom",                                      //Target cue
                        new List<string>(){ "4_HorizontalOut" }                    //Previous step
                        ),

                    //6: To VerticalTop
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "6_VerticalTop",                                           //Name
                        .1d,                                                       //Velocity
                        _vertical,                                                 //Actor
                        "CUE_VerticalTop",                                         //Target cue
                        new List<string>(){ "5_VerticalBottom" }                   //Previous step
                        ),

                    //7: To HorizontalIn
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "7_HorizontalIn",                                          //Name
                        .1d,                                                       //Velocity
                        _horizontal,                                               //Actor
                        "CUE_HorizontalIn",                                        //Target cue
                        new List<string>(){ "6_VerticalTop" }                      //Previous step
                        ),

                    //8: To RotationDropoff
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "8_RotateToDropoff",                                       //Name
                        .5d,                                                       //Velocity
                        _rotator,                                                  //Actor
                        "CUE_RotateDropoff",                                       //Target cue (one exit)
                        new List<string>(){ "7_HorizontalIn" }                     //Previous step
                        ),

                    //9: To HorizontalOut
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "9_HorizontalOut",                                          //Name
                        .1d,                                                        //Velocity
                        _horizontal,                                                //Actor
                        "CUE_HorizontalOut",                                        //Target cue
                        new List<string>(){ "8_RotateToDropoff" }                   //Previous step
                        ),

                    //10: To VerticalBottom (DROPOFF)
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "10_VerticalBottom",                                        //Name
                        .1d,                                                        //Velocity
                        _vertical,                                                  //Actor
                        "CUE_VerticalBottom",                                       //Target cue
                        new List<string>(){ "9_HorizontalOut" }                     //Previous step
                        ),

                    //11: To VerticalTop
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "11_VerticalTop",                                           //Name
                        .1d,                                                        //Velocity
                        _vertical,                                                  //Actor
                        "CUE_VerticalTop",                                          //Target cue
                        new List<string>(){ "10_VerticalBottom" }                   //Previous step
                        ),

                    //12: To HorizontalIn
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "12_HorizontalIn",                                          //Name
                        .1d,                                                        //Velocity
                        _horizontal,                                                //Actor
                        "CUE_HorizontalIn",                                         //Target cue
                        new List<string>(){ "11_VerticalTop" }                      //Previous step
                        ),

                    //13: To RotationPickup
                    MotionWebInstructionStep.GetStepWithMotionVelocity(
                        "13_RotateToPickup",                                       //Name
                        .5d,                                                       //Velocity
                        _rotator,                                                  //Actor
                        "CUE_RotatePickup",                                        //Target cue
                        new List<string>(){ "12_HorizontalIn" }                    //Previous step
                        )
                } //InstructionSteps
            }; //Sequence

            //Register the sequence
            InstructionSequences.Add(_sequence);

            //Start the sequence
            _sequence.StartSequence(this, _passedFrameTime);

            //NOT NEEDED
            //base.OnSimulationFrameUpdate(_passedFrameTime, _totalFrameTime, _frameID, _framePass, ref _resultingEvents, ref _resultRecords);

        } //OnSimulationFrameUpdate
    } //class
} //namespace

CraneRotatorActor Script

Script 2 The CraneRotatorActor script that defines this actor to be a MotionWebActor so it can move around in the MotionWeb

Code Block
languagec#
using u040.prespective.prescripted.des.motionweb;

namespace u040.prespective.demos.actorMotionPathGraph
{
    //Must be of MotionWebActor class to be used in the ActorMotionPathGraph
    public class CraneRotatorActor : MotionWebActor
    {

    }
}

CraneVerticalActor Script

Script 3 The CraneVerticalActor script that defines this actor to be a MotionWebActor so it can move around in the MotionWeb

Code Block
languagec#
using u040.prespective.prescripted.des.motionweb;

namespace u040.prespective.demos.actorMotionPathGraph
{
    //Must be of MotionWebActor class to be used in the ActorMotionPathGraph
    public class CraneVerticalActor : MotionWebActor
    {

    }
}

CraneHorizontalActor Script

Script 4 The CraneHorizontalActor script that defines this actor to be a MotionWebActor so it can move around in the MotionWeb

Code Block
languagec#
using u040.prespective.prescripted.des.motionweb;

namespace u040.prespective.demos.actorMotionPathGraph
{
    //Must be of MotionWebActor class to be used in the ActorMotionPathGraph
    public class CraneHorizontalActor : MotionWebActor
    {

    }
}

...

Playmode

Watch the video above to see what happens when we press play. The CraneInstructor starts moving the three crane actors according the statemachine sequence and stops at the end of the sequence.