Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question CharacterController movement with platform

Discussion in 'Physics' started by mancj, Oct 3, 2023.

  1. mancj

    mancj

    Joined:
    Aug 2, 2015
    Posts:
    1
    Hello everyone.
    I'm using asset library for character's movement. It uses Character Controller component for the player movement.
    Now i want to add to my game some moving platforms, so that player will be able to jump to that platforms and move.
    I tried two approaches
    The first one is to make player's game object child of moving platform, but it doesn't work, i guess it's because Character Controller's position is changing in Update method.
    The second approach is to add platform's velocity to the Character Controller's calculated velocity, but now it moves faster than platform. I know that there are some conditions related to the calculation logic, but my knowledge of mathematics is not enough to fix this.
    Please help me to understand how to properly calculate and mix that two velocities, so the player will move along with the platform


    This is the code, that reads user input and calculates movement velocity:
    Code (CSharp):
    1.  public void Move(Vector2 moveInput, float targetSpeed, Quaternion cameraRotation, bool rotateCharacter = true)
    2.         {
    3.             // note: Vector2's == operator uses approximation so is not floating point error prone, and is cheaper than magnitude
    4.             // if there is no input, set the target speed to 0
    5.             if (moveInput == Vector2.zero) targetSpeed = 0.0f;
    6.  
    7.             // a reference to the players current horizontal velocity
    8.             float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
    9.  
    10.             float speedOffset = 0.1f;
    11.             float inputMagnitude = moveInput.magnitude; // _input.analogMovement ? _input.move.magnitude : 1f;
    12.  
    13.             if (inputMagnitude > 1)
    14.                 inputMagnitude = 1f;
    15.  
    16.             // accelerate or decelerate to target speed
    17.             if (currentHorizontalSpeed < targetSpeed - speedOffset ||
    18.                 currentHorizontalSpeed > targetSpeed + speedOffset)
    19.             {
    20.                 // creates curved result rather than a linear one giving a more organic speed change
    21.                 // note T in Lerp is clamped, so we don't need to clamp our speed
    22.                 _speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude,
    23.                     Time.deltaTime * SpeedChangeRate);
    24.  
    25.                 // round speed to 3 decimal places
    26.                 _speed = Mathf.Round(_speed * 1000f) / 1000f;
    27.             }
    28.             else
    29.             {
    30.                 _speed = targetSpeed * inputMagnitude;
    31.             }
    32.  
    33.             _animationBlend = Mathf.Lerp(_animationBlend, targetSpeed * inputMagnitude,
    34.                 Time.deltaTime * SpeedChangeRate);
    35.  
    36.             // normalise input direction
    37.             Vector3 inputDirection = new Vector3(moveInput.x, 0.0f, moveInput.y).normalized;
    38.  
    39.             // note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
    40.             // if there is a move input rotate player when the player is moving
    41.             if (moveInput != Vector2.zero)
    42.             {
    43.                 _targetRotation = Mathf.Atan2(inputDirection.x, inputDirection.z) * Mathf.Rad2Deg +
    44.                                   (_useCameraOrientation ? cameraRotation.eulerAngles.y : 0);
    45.                 float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, _targetRotation, ref _rotationVelocity,
    46.                     RotationSmoothTime);
    47.  
    48.                 // rotate to face input direction relative to camera position
    49.                 if (rotateCharacter)
    50.                     transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
    51.             }
    52.  
    53.             // update animator if using character
    54.             if (_hasAnimator)
    55.             {
    56.                 _animator.SetFloat(_animIDSpeed, _animationBlend);
    57.                 _animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
    58.             }
    59.  
    60.             Vector3 targetDirection = Quaternion.Euler(0.0f, _targetRotation, 0.0f) * Vector3.forward;
    61.             _velocity = targetDirection.normalized * _speed + new Vector3(0.0f, _velocity.y, 0.0f);
    62.             _timeoutToResetVars = 0.5f;
    63.         }
    64.  
    This is Update function:
    Code (CSharp):
    1. private void Update()
    2.         {
    3.             GravityControl();
    4.             GroundedCheck();
    5.  
    6.             if (_timeoutToResetVars <= 0)
    7.             {
    8.                 _speed = 0;
    9.                 _animationBlend = 0;
    10.                 _animator.SetFloat(_animIDSpeed, 0);
    11.                 _timeoutToResetVars = 0;
    12.             }
    13.             else
    14.                 _timeoutToResetVars -= Time.deltaTime;
    15.  
    16.             if (_useRootMotion)
    17.                 return;
    18.  
    19.             if (!_controller.enabled) return;
    20.  
    21.             _controller.Move(_velocity * Time.deltaTime);
    22.         }
     
  2. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    758
    I've not tried in 2D but simulating platforms in 3D with a character controller can be very problematic. You may have a much easier time using a rigibody for your character. The physics engine will then take care of everything for you.