Character Controller & Moving platform changing direction problem.

Hi, First post in a while… How goes it?

So let me jump right in to it… I’ve been trying to implement a platform that moves up and down. The moving platform will also move the player object which uses a Character Controller component.

Now for the most part it is working fine. The problem is that right at the point the platform changes direction (from upwards to downwards or vise versa) the player gets nudged either upwards or downwards… I think this is because the velocity is being calculated by the “current position” and “last position” and then being applied to CharacterController.Move(). Where as I pretty much need it all to happen at the same time because at the moment I think the player object is a frame behind.

The platform its self is being moved like so:

float step = speed * Time.deltaTime;
platform.position = Vector3.MoveTowards(platform.position, targetPoint.position, step);

When the target position is reached the target position changes.

The code that moves the player while on the platform is basically as follows:

platformCurrentPos = transform.position;

Vector3 velocity = (platformCurrentPos - platformPreviousPos) / Time.deltaTime;
playerController.externalMovement = velocity;

platformPreviousPos = transform.position;

The problem with this is that the platform has to move a small amount first before the velocity can be calculated and then sent to the CharacterController which results in a “delay” or “nudge” when the platform changes direction.

CharacterController.Move(OTHERSTUFF + externalMovement);

So I somehow need to get the new velocity of the platform at the time it happens rather than after it’s happened. Currently the following relies on the direction change happening first which isn’t working:

platformCurrentPos = transform.position;
XXXXX
XXXXX
platformPreviousPos = transform.position;

Is there by any chance a way to somehow “convert” the following:
float step = speed * Time.deltaTime; directly in to a “velocity” value i can send to “externalMovement” vector in CharacterController.Move(OTHERSTUFF + externalMovement)?

I really don’t want to make the player object a child of the platform as it will get in the way of other mechanics for example if the platform is rotating while the player is standing on it.

Orr if there’s another way…

Thanks!

One way is with script execution order settings to ensure one moves before the other, but I don’t like this approach because it exists outside of the visible code.

Another approach is to have the platforms and player all driven with custom Update() methods, and then control the order yourself.

When I do this I rename the Update method in platform and player to be instead public void MyUpDate()

Every platform would subscribe to the “platform update” facility and the player would subscribe himself to the player update facility.

The main updater, the only one actually listening for the real Update() method coming from Unity, would in turn call all platform MyUpdate() calls, then the player MyUpdate() call (or reverse, whatever works for you).

Hi, Thanks for the quick response.
I don’t think is the order of execution im having trouble with… though I could be wrong with my limited knowledge.
But the player object needs to know which direction to move in before it can move in that direction.

In order to get the velocity of the moving platform the platform first needs to move a tiny bit in a what ever direction before the player object can react to it… and by that time the platform has already moved.

Unless I’m misunderstanding you which is totally possible… probable… But if the player object tries to move before it knows the direction in which to move in then it won’t have much luck.

But I’m thinking the platform knows which direction it’s moving in already, so If I could for example say take this:
float step = speed * Time.deltaTime; //Controls platform movement
and make it usable with the following in the same frame it could work.
CharacterController.Move()
But I don’t know how to get a velocity/vector value from that without subtracting its current position from its last position… If thats even possible?

Like I say I’m probably having trouble understanding the execution order.

Thanks

I was just throwing out some possibilities.

It sounds as though your issue is the platform reversing direction but the player still using the previous frame’s motion and thus nudging a bit.

The solution will be something that in one frame, from start to finish:

start frame

  • decide where the platform moves, including reversal
  • gets that information to the player (obviously conditional on him being ON the platform)
  • the player acts on that information
    end frame

If it turns out your problem is something else, well, perhaps implementing something like the above would give you more insight into what is going wrong. Alternately use lots of Debug.Log() output to print movement values each frame.

:stuck_out_tongue: Yeah thats basically the issue. The player object is still a frame behind when the platform changes direction. So until the player object knows that the platform has changed direction it keeps going in that same direction for a single frame. This is what i’m trying to fix.

So thats my query. How do I achieve this in 1 frame rather than 2 frames which is my current solution?

How can I use the following which is what moves the platform:

    float step = speed * Time.deltaTime;
    platform.position = Vector3.MoveTowards(platform.position, targetPoint.position, step);

and in a single frame feed it in to the following which is what moves the player where “externalMoveSpeed” is just a Vector3:

Vector3 externalMovement = externalMoveSpeed * Time.deltaTime;
CharacterController.Move(externalMovement);

Is there some way of converting this: Vector3.MoveTowards(currentPos,TargetPos, distanceDelta) in to just a vector3 * delta.time which can then be used by CharacterController.Move(vector3 * deltaTime)

Thanks

I’e been trying to figure this out for some time and my brain is now mush :frowning:

You can just keep the before and the after and subtract the Vector3s… that will tell you how much it moved this frame and you can tell your player to move that much too, in addition to his actual controlled movement.

This is the method I’ve been using and was explained in the first post. Which is why the player object is a frame behind.

This is the code that gets the velocity and sends it to the controller.

    Vector3 previous = new Vector3();
    Vector3 current = new Vector3();
    void Update()
    {
        currentPos = transform.position;
        if (player != null)
        {
            if (playerController.isGrounded)
            {
                Vector3 velocity = (currentPos - previousPos) / Time.deltaTime;
                playerController.externalMoveSpeed = velocity;
            }
        }
        previousPos = transform.position;
    }

But like I say the direction change needs to happen FIRST in order for the currentPos - previousPos Vector to capture that.

And the player object doesn’t know which direction to move until that vector has been captured… which happens AFTER the platform changes direction.

I’m stuck