How to add platform motion to player controller without parenting? - Mostly working code

Hi! I am currently playing around with character controllers in unity and I wanted to try make a 3d platformer. Everything is going well except I am struggling with the code for adding a platforms velocity to the players movement.

On another post I found this code here, which is apparently from an old unity tutorial that no longer exists:

void GetEnvInfluence()
    {
            if (activePlatform != null )
            {
                newPlayerGlobalPosition = activePlatform.TransformPoint(playerLocalPosition);
                envVelocity = (newPlayerGlobalPosition - playerGlobalPosition);

                if (envVelocity != Vector3.zero)
                {
                    playerController.Move(envVelocity);
                }
                    
                previousPlatformVelocity = (newPlayerGlobalPosition - playerGlobalPosition) / Time.deltaTime;

                newGlobalPlatformRotation = activePlatform.rotation * activeLocalPlatformRotation;
                rotationDiff = newGlobalPlatformRotation * Quaternion.Inverse(activeGlobalPlatformRotation);

                rotationDiff = Quaternion.FromToRotation(rotationDiff * transform.up, transform.up) * rotationDiff;
                transform.rotation = rotationDiff * transform.rotation;
            }

            else
            {
                previousPlatformVelocity = Vector3.zero;
            }

            activePlatform = null;

            Move();
          
            if (activePlatform != null)
            {
                playerGlobalPosition = transform.position;
                playerLocalPosition = activePlatform.InverseTransformPoint(transform.position);

                activeGlobalPlatformRotation = transform.rotation;
                activeLocalPlatformRotation = Quaternion.Inverse(activePlatform.rotation) * transform.rotation;
            }
    }

I have managed to get this code working within my own script, and everything is working pretty great! I only have two issues that I am stuck on.

  1. Currently this code uses the “onControllerColliderHit” function to determine the platform transform. This is fine, but I am using my own spherecast for other ground detection systems and I would like to use it in this case too. For some reason, everything works fine when using the controller collision, but using the raycast to determine the platform transform leads to the character flying off. Using the collision isnt that big of a deal, but it would be preffered if I could use my raycast too.
    .
  2. My other problem is when the platform changes direction, the player does not register this for at least one frame, causing the player to move a small increment in the old direction of the platform after it has already changed direction, causing these little slips each time this happens.

Is this code just outdated? Is there a better solution to this now? I would not like to use the parenting method as I think this way will be better for my game. Any help would be greatly appreciated :slight_smile:

This is an unfortunately pretty complex subject.


Parenting is often the best option for a physics-based character (using a non-kinematic rigidbody). Simply set the parent on collision enter, and leave on collision exit. This breaks the “don’t have rigidbodies as parents to each other” rule, but it’s a pretty outdated rule.


For kinematic rigidbodies and character controllers, the best way is to modify your Platform script. Simply use your Raycast to detect if the player is on a collider, and if it is, use GetComponent to obtain the Platform script. You may want to use RaycastAll if you want to be able to be pulled by the platform if you’re only partially on it.

Your Platform script should run first (use the script order tool), and always store the difference between the next position and the previous position. When you detect if your character is on the ground, try to get that difference, and add it to your movement script offset.


Do note that both the platform script and the player script need to run on FixedUpdate, otherwise just make the the platform store its last velocity in a frame-agnostic manner (divide the delta post by fixedDeltaTime).