Unity_BN1puEa9kj

1. Preparing GameObject based AssetStore assets

Start by getting the asset from the AssetStore. In this case, we are using the "Robot Kyle | URP" asset from the AssetStore.

Now, look through the asset and build a rough* plan of Managed behaviors you want to build interop for. (or already have) E.g. this project:

Supported Unsupported
- Animator
- Animation Events
- Input System (C# generated)
- Cinemachine
- UI
- Input System (Input Action on MB)

Also look out for any simplifications you can make to the asset. Make it just do what you need it to do. Nothing more.

To fulfill this first step, the following changes were made to the project:

2. Building Animation interop

When building any GameObject to Entities interop, you need to consider which case you're dealing with:

  • A. Your Managed Behaviour is heavily tied to a specific object (e.g. Animator)
  • B. Your Managed Behaviour is heavily tied to the scene (e.g. Input System or UI)

Applies to both:

I generally recommend having your ECS Systems be the owner of the behavior. This means that the system is responsible for updating the behavior (like activating an Animation), and the behavior is only partly responsible for providing the data the system needs to act on.

When pulling Managed data from an ECS System, you need the managed reference first. This is the main crux of the problem. And where the approach differs between A and B.

Now, I won't be covering B this time, but generally static's or ECS Singletons work well for this. (See Episode 3 for an example of this in action.)

Applies to A:

A is a bit more complex than B, as you need to consider how you're going to handle tying an Entity to a GameObject. Luckily, Entities has managed components. Not only are IComponentData on a class a managed component, but so is any Unity Object that inherits from UnityEngine.Object. This means that you can have any GameObject component on an Entity.

That said, you still need to get the GameObject to the Entity in the first place. Now, SubScenes can only store entities in the SubScene hierarchy. This is a problem, because you can't have a GameObject in a SubScene, and you can't store a reference outside of the SubScene. One exception to this rule is UnityObjectRef<T> which is a unmanaged reference to a managed UnityEngine.Object that can be stored in a SubScene. Importantly for us, it can store a reference to a GameObject prefab.

So, here's the plan:

  1. Create a GameObject prefab that contains the Animator component, along with the mesh it affects.
  2. Create an empty object that gets baked in the SubScene that will contain a UnityObjectRef<GameObject> that references the prefab.
  3. Create a PlayMode System that will GameObject.Instantiate the prefab, and attach the Animator to the Entity that the system is working on.
  4. Sync the game object's transform to the entity's transform.
  5. Use a cleanup component to destroy the GameObject when the entity is destroyed.
  6. Realize edit mode has no visual representation of the GameObject prefab.
  7. Create an EditMode System (for more detail Episode 7) that will create an entity representation of the GameObject prefab.
  8. Realize the EditMode visualization is not the same as the PlayMode visualization. He's laying down, but he should be standing up.
  9. Create a shader that supports Entities Graphics drawing SkinnedMeshes correctly. Put it on Kyle.

Result of all this, let's you write code like this:

var animator = SystemAPI.ManagedAPI.GetComponent<Animator>(characterData.AnimationEntity);
animator.SetBool(AnimIDJump, characterInput.Jump);

Set aside the animation interop for now, and focus on the character controller. Start by importing the package. And the sample files. Then, the samples simply give a small example implementing the package. So let's look at the sample files and see what you can do to make it work, and start moving. In this case, we need to:

  1. Use all the prefabs found in /Samples/Character Controller/1.1.0-exp.10/Standard Characters/ThirdPerson/Prefabs, by putting them in the subscene.
  2. Assign the ThirdPersonCharacter prefab to the matching field on ThirdPersonPlayer prefab.
  3. Assign the OrbitCamera prefab to the matching field on ThirdPersonPlayer prefab.
  4. Sync the Main Camera to the OrbitCamera prefab. By adding the component MainGameObjectCamera to the camera, and MainEntityCameraAuthor ig to the OrbitCamera prefab.
  5. Press play and see the character controller in action.

The result of following those steps can be seen here.

For this project I also chose to clean up the project a bit more to make it easier to follow along with the stream. This includes:

All of the above changes don't change the functionality of the project, but make it easier to follow along with the stream.

4. Merging the two projects

Now that we have both the character controller and the animation interop working, we can start merging the two projects. First, made a few tweaks to the character controller to build confidence in how the character controller works:

  1. Locked the mouse cursor and hid it.
  2. Implemented sprint and changed to use the C# generated input system.
  3. Made orbit camera ignores the pole.

Then, I started merging the two projects by:

  1. Deleting the capsule from the ThirdPersonCharacter prefab.
  2. Moving the empty game object that contains the UnityObjectRef<GameObject> to the ThirdPersonCharacter prefab.
  3. Voila! The character controller is now moving the character with the model, that has an Animator attached to it.

Implementing animation is then as simple as this commit.

Connecting animation events is as simple as this commit.

Written by: Dani K Andersen (@dani485b)