using Unity.XR.CoreUtils; namespace UnityEngine.XR.Interaction.Toolkit.Locomotion { /// /// Scriptable object that can perform constrained movement of an by using a /// that follows the user's body. Each time this object is about to call /// on the , it first ensures that the /// and are set such that the /// bottom of the capsule matches the position determined by /// and the height of the capsule matches . /// [CreateAssetMenu(fileName = "CharacterControllerBodyManipulator", menuName = "XR/Locomotion/Character Controller Body Manipulator")] [HelpURL(XRHelpURLConstants.k_CharacterControllerBodyManipulator)] public class CharacterControllerBodyManipulator : ScriptableConstrainedBodyManipulator { /// public override CollisionFlags lastCollisionFlags => characterController != null ? characterController.collisionFlags : CollisionFlags.None; /// public override bool isGrounded => characterController == null || characterController.isGrounded; /// /// The character controller attached to the of the /// . This is if /// is . /// public CharacterController characterController { get; private set; } /// public override void OnLinkedToBody(XRMovableBody body) { base.OnLinkedToBody(body); var xrOrigin = body.xrOrigin; var origin = xrOrigin.Origin; // Try on the Origin GameObject first, and then fallback to the XR Origin GameObject (if different) if (!origin.TryGetComponent(out CharacterController foundController) && origin != xrOrigin.gameObject) xrOrigin.TryGetComponent(out foundController); if (foundController != null) { characterController = foundController; return; } Debug.LogWarning($"No CharacterController found. Adding one to Origin GameObject '{origin.name}'.", this); characterController = origin.AddComponent(); } /// public override void OnUnlinkedFromBody() { base.OnUnlinkedFromBody(); characterController = null; } /// public override CollisionFlags MoveBody(Vector3 motion) { if (linkedBody == null || characterController == null) return CollisionFlags.None; var xrOrigin = linkedBody.xrOrigin; var bodyGroundPosition = linkedBody.GetBodyGroundLocalPosition(); var capsuleHeight = xrOrigin.CameraInOriginSpaceHeight - bodyGroundPosition.y; characterController.height = capsuleHeight; characterController.center = new Vector3(bodyGroundPosition.x, bodyGroundPosition.y + capsuleHeight * 0.5f + characterController.skinWidth, bodyGroundPosition.z); return characterController.Move(motion); } } }