• We are looking for a content creator to help market our assets and a future unannounced project. More details are on this page.

Ladder Rotation Brakes charachter

Gol-de-chef

New member
Im having trouble to make the ladder work with a vehicle. Right now on a flat surface it works fine but as it will be changing position and rotation the ladder does not work as i hoped it would be. Also tried something with a simple automatic Animation with a modified Climb script, but also doesnt like the rotation and i get the camera stuck in a fixed rotation. I looked in to how the Drive ability handle the charachter on Exit but could not get to work. Im out of ideas, any help would be aprecheated.

The Opsive ladder bug:

The small ladder problem:

This script i use for the the Smaller ladder
C#:
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------

namespace Opsive.UltimateCharacterController.AddOns.Climbing
{
    using Opsive.Shared.Events;
    using Opsive.Shared.Game;
    using Opsive.Shared.Utility;
    using Opsive.UltimateCharacterController.Game;
    using Opsive.UltimateCharacterController.AddOns.Climbing.Objects;
    using Opsive.UltimateCharacterController.Character.Abilities;
    using Opsive.UltimateCharacterController.Objects.CharacterAssist;
    using Opsive.UltimateCharacterController.Utility;
    using UnityEngine;

    /// <summary>
    /// The Tank Enter ability allows the character to climb inside the tank.
    /// </summary>
    [DefaultStartType(AbilityStartType.ButtonDown)]
    [DefaultStopType(AbilityStopType.Manual)]
    [DefaultInputName("Action")]
    [DefaultState("ShortClimb")]
    [DefaultAbilityIndex(601)]
    [DefaultAllowRotationalInput(false)]
    [DefaultUseGravity(AbilityBoolOverride.False)]
    [DefaultUseRootMotionPosition(AbilityBoolOverride.True)]
    [DefaultDetectHorizontalCollisions(AbilityBoolOverride.False)]
    [DefaultDetectVerticalCollisions(AbilityBoolOverride.False)]
    [DefaultEquippedSlots(0)]
    [DefaultCastOffset(0, 0, 0)]
    [Group("Climbing Pack")]

    public class TankEnterClimb : DetectObjectAbilityBase
    {
        private GameObject m_Ladder;

        [Tooltip("The speed at which the character rotates towards the location.")]
        [SerializeField] protected float m_RotationSpeed = 2f;

        public float RotationSpeed { get => m_RotationSpeed; set => m_RotationSpeed = value; }

        [Tooltip("The maximum height of the object that the character can climb over.")]
        [SerializeField] protected float m_MaxHeight = 2f;
        public float MaxHeight { get { return m_MaxHeight; } set { m_MaxHeight = value; } }
        private float m_Height;
        public override float AbilityFloatData => m_Height;

        /// <summary>
        /// Called when the ablity is tried to be started. If false is returned then the ability will not be started.
        /// </summary>
        /// <returns>True if the ability can be started.</returns>
        public override bool CanStartAbility()
        {
            if (!m_CharacterLocomotion.Grounded || !base.CanStartAbility()) {
                return false;
            }

            var position = m_Transform.InverseTransformPoint(m_RaycastResult.point);
            position.y = 0;
            position = m_Transform.TransformPoint(position);
            // There must be space for the character to climb.   
            RaycastHit hit;
            if (Physics.Raycast(position + m_CharacterLocomotion.Up * m_MaxHeight + m_RaycastResult.normal * m_CharacterLocomotion.Radius, m_Transform.forward, out hit,
                m_CharacterLocomotion.Radius * 3, m_CharacterLayerManager.SolidObjectLayers, QueryTriggerInteraction.Ignore))
            {
                return false;
            }
            // The top of the detected object must be beneath the max height.   
            if (!Physics.Raycast(position + m_CharacterLocomotion.Up * m_MaxHeight - m_RaycastResult.normal * 0.1f, -m_CharacterLocomotion.Up, out hit,
                m_MaxHeight, m_CharacterLayerManager.SolidObjectLayers, QueryTriggerInteraction.Ignore))
            {
                return false;
            }
            m_Height = m_Transform.InverseTransformPoint(hit.point).y;
            return true;

        }
        
        /// <summary>
        /// Returns the possible MoveTowardsLocations that the character can move towards.
        /// </summary>
        /// <returns>The possible MoveTowardsLocations that the character can move towards.</returns>
        public override MoveTowardsLocation[] GetMoveTowardsLocations()
        {
            if (m_DetectedObject == null)
            {
                return null;
            }

            var moveTowardsLocations = m_DetectedObject.GetCachedComponents<MoveTowardsLocation>();
            if (moveTowardsLocations != null) {
                var rotation = Quaternion.LookRotation(m_RaycastResult.normal, m_CharacterLocomotion.Up);
                var invRotation = Quaternion.LookRotation(-m_RaycastResult.normal, m_CharacterLocomotion.Up);
                // The start location should be modified to be directly in front of the climb object raycast position.
                for (int i = 0; i < moveTowardsLocations.Length; ++i) {
                    var startPosition = MathUtility.TransformPoint(m_RaycastResult.point, rotation, moveTowardsLocations[i].StartOffset);
                    moveTowardsLocations[i].Offset = moveTowardsLocations[i].transform.InverseTransformPoint(startPosition);
                    var yawOffset = MathUtility.InverseTransformQuaternion(moveTowardsLocations[i].transform.rotation, invRotation).eulerAngles.y;
                    moveTowardsLocations[i].YawOffset = MathUtility.ClampAngle(yawOffset + moveTowardsLocations[i].StartYawOffset);
                }
            }
            return moveTowardsLocations;
        }
        
        /// <summary>
        /// The ability has started.
        /// </summary>
        protected override void AbilityStarted()
        {
            base.AbilityStarted();

            m_CharacterLocomotion.UpdateLocation = KinematicObjectManager.UpdateLocation.FixedUpdate;
            m_CharacterLocomotion.ResetRotationPosition();


            m_CharacterLocomotion.AlignToGravity = true;
            EventHandler.RegisterEvent(m_GameObject, "OnAnimatorLadderClimbComplete", OnTankEnterComplete);
        }

        /// <summary>
        /// Update the controller's rotation values.
        /// </summary>
        public override void UpdateRotation()
        {
            m_Ladder = m_DetectedObject;


            m_CharacterLocomotion.Torque = Quaternion.identity;
            m_CharacterLocomotion.transform.rotation = m_Ladder.transform.rotation;
        }


        /// <summary>
        /// Update the ability's Animator parameters. Called before the rotation and position values are applied.
        /// </summary>
        public override void UpdateAnimator()
        {
            // Set the input vector to zero so the animator transitions faster out of the movement blend tree.
            // If the movement blend tree is not active this line will not change anything.
            //m_CharacterLocomotion.InputVector = Vector3.zero;

        }


        /// <summary>
        /// The Tank Enter ability has completed - stop the ability.
        /// </summary>
        private void OnTankEnterComplete()
        {
            m_CharacterLocomotion.AbilityMotor = Vector3.zero;


            m_CharacterLocomotion.AlignToGravity = false;
            m_CharacterLocomotion.transform.rotation = Quaternion.identity;
            m_CharacterLocomotion.ResetRotationPosition();
            StopAbility();
        }

        /// <summary>
        /// The ability has stopped running.
        /// </summary>
        /// <param name="force">Was the ability force stopped?</param>
        protected override void AbilityStopped(bool force)
        {
            base.AbilityStopped(force);
            EventHandler.UnregisterEvent(m_GameObject, "OnAnimatorLadderClimbComplete", OnTankEnterComplete);
        }

    }

}
 

Justin

Administrator
Staff member
Rotated ladders similar to that are not currently supported. Without debugging the code with breakpoints it's really hard to say what is going on.

In terms of vehicles, in the demo scene there is an example where the character moves with a moving platform. Have you tried comparing?
 

Gol-de-chef

New member
Rotated ladders similar to that are not currently supported. Without debugging the code with breakpoints it's really hard to say what is going on.

In terms of vehicles, in the demo scene there is an example where the character moves with a moving platform. Have you tried comparing?
Thank you for the reply. The vehicle part works fine , the only part what bugs me is that the ladder does not like rotation :/
 

Gol-de-chef

New member
Ok i changed the ladder scrip, im not sure if it still brakes something but at least i can use a slope and rotated ladder now. However Enabled Move with Object, does still make the camera rotate.


Code:
/// <summary>
        /// The ability has stopped running.
        /// </summary>
        /// <param name="force">Was the ability force stopped?</param>
        protected override void AbilityStopped(bool force)
        {
            base.AbilityStopped(force);

            m_ClimbState = ClimbState.BottomMount; // Reset for next start.


            var forward = Vector3.ProjectOnPlane(m_CharacterLocomotion.LookSource.Transform.forward, -m_CharacterLocomotion.GravityDirection);
            m_CharacterLocomotion.SetPositionAndRotation(m_CharacterLocomotion.transform.position, Quaternion.LookRotation(forward, -m_CharacterLocomotion.GravityDirection), true, false);

            if (m_JumpInput != null) {
                m_Handler.UnregisterInputEvent(m_JumpInput);
                GenericObjectPool.Return(m_JumpInput);
                EventHandler.UnregisterEvent(m_GameObject, "OnJumpInput", OnJumpInput);
            }

            //m_CharacterLocomotion.transform.rotation = Quaternion.identity;

            EventHandler.UnregisterEvent(m_GameObject, "OnAnimatorLadderClimbStartInPosition", OnLadderClimbStartInPosition);
            EventHandler.UnregisterEvent(m_GameObject, "OnAnimatorLadderClimbComplete", OnLadderClimbComplete);
        }

assdss.PNG
 
Top