Instantiating Prefa...
Clear all

Instantiating Prefab and then adding controller and information to it at runtime.

4 Posts
2 Users
New Member
Topic starter

I plan to have it so the player can shapeshift to other characters and the quantity of those appearances can grow so I do not want to create a prefab that has been pre-setup for every possibility.   As such I am making a script called WOR_SetAppearance().   The WOR is reference to the project.   This will reside on a game object that is not the character but will keep track of the character.  In fact, it will set the character as it's parent if desired until appearance changes during which time it will shift away from the character.

I have gradually gotten it to setup the Camera, and various things properly.   Though I noticed it was not moving.  I plan on using the Adventure setup and by default I plan to have Jumping, Climb Obstacles, Climb Ladders, and Sneak.  I am working with those first though I do have the Sword Shield, Bow, Swimming, and Spell Casting packs which I plan to use as well.

It currently does not actually result in a character that animates.   When I look into it that appears to be due to no Motion Layers being setup.   What is the best way to set those up within our own code?


I thought I'd add. I am using Camera Controller, and Easy Input at the moment as well.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MEC;

public class WOR_SetAppearance : MonoBehaviour
[Tooltip("If this is a number it will load the information it needs from the saved information about the specified creature.")]
public int LoadFromCreatureID = -1;
[Tooltip("This prefab should preferably be assigned by script so you can reuse the same prefab for controllers over and over without needing to make many different controller prefabs, and to facilitate shape changinge, etc. It can be assigned here if need be for testing or if it is never going to change.")]
public GameObject AppearancePrefabToUse=null;
[Tooltip("This is the controller to use for animating and moving this creature. It can be overriden by script but a default should always be here.")]
public Animator AnimatorToUse=null;
[Tooltip("If this is set then it will make certain the motion controller is added to the instantiated character. NOTE: It will add the Actor Controller even if it is not. This will not happen until it has spawned an appearance.")]
public bool IsControllable = false;
[Tooltip("Set this to true if you do not want it to add the Actor Controller to this object.")]
public bool DoNotAddActorController = false;
public bool ActorControllerCollideWithObjects = true;
public bool ActorControllerWalkOnWalls = false;
public float ActorControllerHeight = 2.0f;
public float ActorControllerWidthRadius = 0.35f;
public float ActorControllerMass = 2.0f;
public bool ActorControllerIsGravityEnabled = true;
public bool ActorControllerIsCollisionEnabled = true;
public float CameraControllerHeight = 1.5f;
public RuntimeAnimatorController AnimationController = null;
[Tooltip("If this exists it will instantiate this and parent it to the character. This will be used to implement AIs.")]
public GameObject AIPrefab = null;
[Tooltip("If this is set to true then it will set the instantiated character to be the parent of this object, and it will only unparent if the appearance is changed. It will do so long enough to destroy the old, spawn a new, and then parent itself to the new one.")]
public bool NestBelowCharacter = true;
[Tooltip("If this is a playable character then this should contain a reference to the camera that is following the character.")]
public GameObject CameraToObserve = null;
private GameObject SpawnedAppearance; // used to cache the appearance added in case it is replaced later.
public com.ootii.Actors.ActorController actorController = null;
public com.ootii.Actors.AnimationControllers.MotionController motionController = null;

void Start()
{ // Start()-----------
if (AppearancePrefabToUse == null)
{ // AppearancePrefab is not there
} // AppearancePrefab is not there
{ // the appearance is already present
SetAppearance(AppearancePrefabToUse, AnimationController);
} // the appearance is already present
} // Start()-----------

public GameObject GetAppearance() { return SpawnedAppearance; }

IEnumerator<float> _WaitToApplyAppearance()
{ // PURPOSE: Wait until ReadyToApply is set to true before setting appearance
while (AppearancePrefabToUse == null&&LoadFromCreatureID<0)
{ // wait
yield return 0f;
} // wait
if (LoadFromCreatureID > -1)
{ // load appearance from saved creature info

} // load appearance from saved creature info
{ // from prefab
SetAppearance(AppearancePrefabToUse, AnimationController);
} // from prefab
yield return 0f;
} // _WaitToApplyAppearance()

public void SetAppearance(GameObject PrefabAppearance,RuntimeAnimatorController ControllerToUse=null)
{ // PURPOSE: Set the appearance
GameObject NewAppearance = null;
if (SpawnedAppearance!=null)
{ // there is already an appearance
if (transform.parent.gameObject == SpawnedAppearance) transform.parent = null; // get out from the appearance
NewAppearance = Instantiate(PrefabAppearance) as GameObject;
NewAppearance.transform.position = SpawnedAppearance.transform.position;
NewAppearance.transform.rotation = SpawnedAppearance.transform.rotation;
} // there is already an appearance
{ // new
NewAppearance = Instantiate(PrefabAppearance) as GameObject;
NewAppearance.transform.position = transform.position;
NewAppearance.transform.rotation = transform.rotation;
} // new
if (NewAppearance!=null)
{ // successfully intanstiated
if (NestBelowCharacter) { transform.parent = NewAppearance.transform; transform.localPosition = new Vector3(0, 0, 0); transform.localEulerAngles = new Vector3(0, 0, 0); } // nest under character
if (!DoNotAddActorController||IsControllable)
{ // add the actor controller
actorController = NewAppearance.GetComponent<com.ootii.Actors.ActorController>();
if (ActorControllerCollideWithObjects) actorController.EditorCollideWithObjects = true;
if (ActorControllerWalkOnWalls) actorController.EditorWalkOnWalls = true;
actorController.Height = ActorControllerHeight;
actorController.Radius = ActorControllerWidthRadius;
actorController.Mass = ActorControllerMass;
actorController.IsGravityEnabled = ActorControllerIsGravityEnabled;
actorController._IsCollisionEnabled = ActorControllerIsCollisionEnabled;
if (IsControllable)
{ // add the motion controller
motionController = NewAppearance.GetComponent<com.ootii.Actors.AnimationControllers.MotionController>();
com.ootii.Actors.AnimationControllers.MotionControllerLayer motionLayer = null;
com.ootii.Cameras.CameraController cameraController = null;
if (CameraToObserve==null)
{ // find camera
int nLength = Camera.allCameras.Length;
GameObject Found = null;
int nC = 0;
{ // find the object with the CameraController
GameObject Parent = Camera.allCameras[nC].gameObject;
if (Parent.transform.parent != null) Parent = Parent.transform.parent.gameObject;
if (Parent.GetComponent<com.ootii.Cameras.CameraController>() != null) Found = Parent;
} // find the object with the CameraController
if (Found)
{ // found it
CameraToObserve = Found;
cameraController = CameraToObserve.GetComponent<com.ootii.Cameras.CameraController>();
} // found it
} // find camera
{ // get camera controller
cameraController = CameraToObserve.GetComponent<com.ootii.Cameras.CameraController>();
} // get camera controller
if (cameraController!=null)
{ // camera controller was found
cameraController.AnchorOffset = new Vector3(0, CameraControllerHeight, 0);
cameraController.Anchor = NewAppearance.transform;
} // camera controller was found
{ // error
Debug.LogError("SetAppearance() CameraController was not found. A GameObject with a camera attached to it must be in the scene and have the Ootii Camera Controller component added to it.");
} // error
if (NewAppearance != null && SpawnedAppearance != null) GameObject.Destroy(SpawnedAppearance);
SpawnedAppearance = NewAppearance;
} // add the motion controller
} // add the actor controller
if (AIPrefab!=null)
{ // add AI Prefab
GameObject AI = Instantiate(AIPrefab) as GameObject;
AI.transform.parent = NewAppearance.transform;
AI.transform.localPosition = new Vector3(0, 0, 0);
AI.transform.localEulerAngles = new Vector3(0, 0, 0);
} // add AI prefab
if (ControllerToUse != null) AnimationController = ControllerToUse;
if (AnimationController != null && NewAppearance.GetComponent<Animator>() != null) NewAppearance.GetComponent<Animator>().runtimeAnimatorController = AnimationController;
} // successfully instantiated
{ // error
Debug.LogError("Failed to intantiate the prefab using SetAppearance.");
} // error
} // SetTheAppearance()

public void SetLocation(Vector3 position, Vector3 rotation)
{ // PURPOSE: Set Location
SpawnedAppearance.transform.position = position;
SpawnedAppearance.transform.localEulerAngles = rotation;
} // SetLocation()


This topic was modified 2 years ago 2 times by dwinblood
Posted : 01/02/2021 2:23 am
New Member
Topic starter

I suspect I may need to replicate what you do in the MotionController.cs script.


// Load the animator and grab all the state info
if (_Animator == null) { _Animator = gameObject.GetComponent<Animator>(); }
if (_Animator == null) { _Animator = gameObject.GetComponentInChildren<Animator>(); }

for (int i = 0; i < _Animator.parameters.Length; i++)
if (_Animator.parameters[i].name == MotionController.MOTION_STYLE_NAMES[0])
mUseMotionForms = true;

if (_Animator.parameters[i].name == MotionController.MOTION_STATE_TIME[0])
mUseMotionStateTimes = true;

// Build the list of available layers
if (_Animator != null)
State.AnimatorStates = new AnimatorLayerState[_Animator.layerCount];
PrevState.AnimatorStates = new AnimatorLayerState[_Animator.layerCount];

// Initialize our objects with each of the animator layers
for (int i = 0; i < State.AnimatorStates.Length; i++)
State.AnimatorStates[i] = new AnimatorLayerState();
PrevState.AnimatorStates[i] = new AnimatorLayerState();

// Ensure the layers and motions know about the controller
for (int i = 0; i < MotionLayers.Count; i++)
MotionLayers[i].MotionController = this;

// Load the animator state and transition hash IDs

/// <summary>
/// Load the animator state and transition IDs
/// </summary>
private void LoadAnimatorData()
// Set the actual state names
AddAnimatorName("Any State");

// Allow the motion layers to set the names
for (int i = 0; i < MotionLayers.Count; i++)
This post was modified 2 years ago by dwinblood
Posted : 01/02/2021 2:35 am
New Member
Topic starter

I may have found an answer.  I went to the asset store to find a link to the documentation (Don't see links to documentation on the website just various specific articles).

Anyway... this section of the documentation may get me headed in the correct direction.


Adding Motions at Runtime


Activating Motions

I will see what I can get it to do by following those steps.


This post was modified 2 years ago by dwinblood
Posted : 01/02/2021 2:47 am
Tim reacted
Member Admin

Hey @dwinblood ,

The best resource for you is probably MotionControllerEditor.cs (and MotionController.cs as you found).

MotionControllerEditor.cs is what powers the MC's inspector. So, all the things you can do in the inspector... add layers, add motions, set motion parameters can be done in code as you swap bodies.

So, using the SetAppearance(...) should work just fine. The only thing that could be different is your Unity Avatar and Animator as your animations may change based on the player's new body. But even that can be changed in code.


I hope that helps,



Posted : 01/02/2021 7:14 am