Player falling through the ground sometimes when I re-center with my world streamer

Hi there! I’m creating a world streamer for my open world 3D game and I’m having an issue.

My setup is that I have a player character and a world map made up of chunks. Each chunk right now is just a cube with its own box collider. When the player moves from one chunk to another, both the player and the mapa re re-centered. This is to avoid issues with floating point precision in large worlds.

So, if the World Streamer detects player transitions to a new chunk, the player is teleported to the center position, and the world map is shifted (in that order) in order to form a seamless transition, such that the player doesn’t know this is happening in the background.

The issue is that, sometimes, the player falls right through. I assume it has to do with how often the physics VS positions are checked, but I don’t know how to remedy this.

I was trying to reproduce the issue but it doesn’t happen a ton.

Any thoughts or help with this would be really great.

Interesting. If you’re relying on Physics, I think you would need to do this update in FixedUpdate(), for one.

Also, when you move any object with a Rigidbody, such as the player, you probably want to move him to his new re-centered position in two ways, one right after the other:

  1. do a transform.Translate() (or set transform.position directly)

  2. execute a Rigidbody.MovePosition() with that same exact position.

I think this second step will cause the physics system to reconsider the consequences of any penetrations into the ground, even if it was just a little bit.

There’s a possibility that #2 will try and drag the player through the world from where he WAS before #1 executed. There may be additional tweaks you can do with this between the two above steps:

@Kurt-Dekker

Thanks for the reply, I was not using the Rigidbody.MovePosition() so maybe that’s part of the issue. I’ll experiment with that and report back tomorrow.

Do you think it matters whether I move the player or the world first? As I stated in the OP I’m currently moving the player then the world, not sure the order should really make a difference here, but I thought I’d ask in case moving the world first makes more sense.

It may matter but I have no way of reasoning about your setup.

I imagine if you move everything WITHOUT a rigidbody, then move all the rigidbodies the way I suggest above, that would result in the highest chance of success. It might be worth always doing that sync as well…

1 Like

So actually I’m using a CharacterController component on my player instead of a Rigidbody.

The ground chunks just have a regular box collider on them.

I am updating my player movement in Update though, so maybe I’ll try changing that to FixedUpdate.

I was under the impression that FixedUpdate was not needed for the CharacterController component, and was more for the Rigidbody but I’ll give it a shot

This is actually correct. Definitely do NOT use FixedUpdate() unless you’re using Physics. I just assumed you were.

There may be an analogy to my suggestion of using .MovePosition() on a Rigidbody: you may want to try using the .Move() method on the CharacterController, either alone or after a transform position change, because I think that will give it a chance to do its ground check and collisions and whatnot.

I’m honestly not sure how to use the CharacterController.Move method as a teleport. It’s what I’m using to move/control the player character, but for teleporting around the way you do with transform.position, I’m not sure.

Right now I’m testing out just turning the CharacterController off, teleporting, and turning it on again and seeing if that works. I’ll report back if I have any issues, sometimes it goes for a long time without clipping through the world haha

Code:

characterController.enabled = false;
transform.localPosition = newPosition;
characterController.enabled = true;

Nope!

Still having the same issue when I turn the CharacterController on and off.

I’ll keep experimenting with the CharacterController.Move method.

If anyone gets other ideas let me know!

I would try CC.Move() in two possible places:

  • between line 2 and 3 in your previous post

or

  • after line 3 in your previous post

And I would try either Vector3.zero for the motion argument, or else maybe Vector3.up * 0.01f or something tiny.

So I tried some stuff, still no luck.

@Kurt-Dekker

I tried both the zero vector and the up vector with no luck after characterController.enabled = true;. I tried it right before too, but it still didn’t work and I got warning about the CharacterController not being on but using the Move method.

I also tried a coroutine:

characterController.enabled = false;
transform.localPosition = newPosition;
yield return new WaitForSeconds(teleportWait);
characterController.enabled = true;

I tried it with WaitForEndOfFrame(), with WaitForFixedUpdate(), and with WaitForSeconds(). I thought for sure this would work, but nope! still falling through transitions occasionally.

Next I’m gonna try extending the colliders of the ground chunks so that they overlap, maybe the player is literally falling through the cracks?

I’m almost out of ideas though haha I’m not turning any of these colliders or GameObjects on and off at any point during this teleport process, all I’m doing is moving the GameObjects.

I tried extending the collider bounds so that there were no cracks anywhere and I’m still having the same issue.

I have no more ideas on how to handle this with CharacterController.

I could try switching my player to using a RigidBody with conitnuous collision detection and seeing how that works I guess? Not sure if it would be better but it might be worth a try.

that’s pretty intrusive…

have you tried spherecasting at the ground after the relocation happens, then lift the player a bunch, like 1 world unit, and let him fall.

if it STILL falls through the ground something really weird is going on.

if it works, you can dial that lift distance downwards until it is (hopefully) barely noticeable.

This was a good idea, a little similar to what I was trying before with the Vector3.up * 0.01f. However, I think the difference is the timing.

I did some Debug.Log() and found that the player’s Y value is consistent after the teleport, and after the coroutine is done. meaning the fall is happening after everything has shifted. Still no clue why it would happen after everything is in place though.

So what I did was put a trigger collider underneath the ground chunks, right below the surface, and if the player hits it, a method gets called with the line characterController.Move(Vector3.up * teleportYOffset);

This seems to be working consistently with a teleportYOffset value of 0.25 or above. Anything below that and the player still falls through.

It is a bit noticeable, though not game breaking I think. I think the reason it’s so noticeable is because I have an animation that plays when the player becomes grounded, so I need to stop that animation in this particular instance.

Also, the trigger collider is not perfect since it really only works for super flat surfaces, a spherecast does sound like a better solution long term. Still can’t help but feel like this is a duct tape solution for this issue haha

I’ll report back another day if I have any more issues with this.

Also, I want to try doing the world shift/teleport at the center of each chunk, rather than on the boundary between chunks, I wonder if that would work better since the player would only be near 1 collider rather than 2-4 ground chunk colliders. Might be worth trying out.

Anyway! Thanks for all the help, I’ll keep experimenting next week and see if I can polish this solution (assuming it keeps working!).

1 Like

Since you’re not using Rigidbodies, I wonder what would happen if you created a new GameObject, parented all the GameObjects you intended to move to that new GO, moved only the new GO by the “wrap” or “offset” amount (making all the children move with it), then deparented all the children? It might not end up changing anything, but I wonder…

So I’m experimenting with this, it’s actually one of the ideas I also had to try to resolve this, but I’m running into an issue.

So the whole point of wanting to use this world streaming system is to avoid issues with floating point precision as the player moves further and further from the origin of the scene.

However, I’m noticing that if I don’t reset the player’s position at all, if all I do is move the parent object, the player’s local position just keeps increasing in magnitude. So even though the player’s scene position is near the origin, the local position numbers get bigger and bigger.

Not really sure what kind of effect this could have frankly. I suspect I have to reset the player’s local position at some point.

Of course not. But if you parent everything to a GameObject, move that GameObject, then unparent everything, it will be in a new position, assuming you use the .SetParent() call without the second optional argument.

1 Like

I see what you’re saying, I hadn’t thought about what it would mean to parent/unparent the player rather than just keeping it parented the whole time.

Unfortunately, moving the parent object with the world chunks and the player as children and then unparenting has the exact same results as before in terms of occasionally falling through.

Now I’m gonna try a sort of moving boundary. The issue seems to at least be more common when continuously moving through the chunk boundaries (I’m testing it by spinning in circles around the four corners to cause a lot of shifts) so my idea is to make it so that when the shift happens, the boundaries after the shift are not right next to the player, this would hopefully make it so the player can’t really quickly shift back and forth maybe making the occurance less likely?

Not 100% how to do this but yeah it’s my next thing to tackle haha

Ok so I got the world streaming working in such a way where when the player reaches a certain distance, the player becomes a child of a GameObject that also holds the world chunks.

After that, the parent of said objects gets moved, and the player then removes itself from that parent.

The difference now is that the shift that happens positions everything in such a way so that no immediate shifts can happen again, until the player moves a certain distance. Before, they were these sort of set boundaries so you could keep moving back and forth between them, and I thought maybe that was what was causing issues. Basically I thought if I increased the time between these world shifts it might fix the issue.

Additionally the shift always happens away from the chunk edges, I thought maybe the edges where the chunks meet could be causing issues so I made the shift occur in the middle of a chunk, where no other chunks are present to avoid weird collider behavior.

Still having the issue! Though now it just takes longer to reproduce since the shift happens less often.

I do have some new, interesting information though so I wanted to do an update.

I was testing this by running around and in spite of all the changes, my player fell through the world, however, I managed to stop input immediately as it happened or right before (not sure), and this lead to some interesting behavior.

I used the transform tool in scene view to move the player up above the world after the fall, and whiteout any world shifts happening, as the player falls, it goes through the world again.

This is strange to me, the player isn’t moving super fast in the Y axis as I am clamping vertical speed to a maximum. The colliders for the player and for the particular chunk are on (as I mentioned before, I’m never turning any off).

So what’s going on?! haha

Here’s a gif:

7678423--959638--Player falling through world 1.gif