I've created elevator that moves with acceleration. The problem is that all physical objects start to bounce during movement. Changing some thresholds helps a bit, but CharacterController is still bouncing (when moving down). Slowing elevator down doesn't help much either. Code (CSharp): void Awake() { rb = GetComponent<Rigidbody>(); } public void MoveToFloor(Floors floor) { if (!IsMoving && floor != currentFloor) { currentFloor = floor; StartCoroutine(MoveElevator(floor)); } } IEnumerator MoveElevator(Floors floor) { IsMoving = true; float speed = 0, target = floors[floor]; bool up = target - transform.position.y > 0; while (true) { // Moving up. if (up) { if (MoveElevator(ref speed, target, Vector3.up, up)) break; } // Moving down. else { if (MoveElevator(ref speed, target, Vector3.down, up)) break; } yield return null; } IsMoving = false; } bool MoveElevator(ref float speed, float target, Vector3 dir, bool up) { float t = speed / acceleration; float brakingDistance = acceleration * t * t / 2; // Decelerating. if (brakingDistance >= Mathf.Abs(target - transform.position.y)) speed -= acceleration * Time.deltaTime; // Accelerating. else if (speed < maxSpeed) { speed += acceleration * Time.deltaTime; // Max speed is reached. if (speed >= maxSpeed) speed = maxSpeed; } // New position. Vector3 pos = transform.position + dir * speed * Time.deltaTime; if (up ? target - pos.y > 0 : pos.y - target > 0) { rb.MovePosition(pos); return false; } // Target is reached. else { rb.MovePosition(transform.position.SetY(target)); return true; } } (Don't mind visual glitch on moving objects.)
I think you can get around it with parenting the objects in the lift to the lift. something like a trigger occupying the inner space of the lift and OnTriggerEnter -> parent and OnTriggerExit -> make them like batman(de-parented )
Forgot to mention that parenting doesn't work either. Why would it? Those are all physical objects and they don't care about parenting at all.
I thought about that but it sounds like some hack, cheap trick. I would use it if there is no better solution...
Hello, forget about parenting, it will cause you a lot of troubles. that's exactly how every good platform controller works,...or the other way, i mean that every object inside moves along with the ground (that's what i do in my asset), it depends, in this case i would say go with the option A, the elevator should apply "something" to the objects. IMO the safest way is going kinematic, you can put every object inside the elevator as kinematics, that way the objects wont bounce, but also wont move/rotate/etc nothing, you gonna have to move them in some way (Rigidbody.position or MovePosition) with the deltaPosition of the elevator. Also you can instead modify the mass and drag of every object while the elevator is moving, it could work. In any case the elevator will have to know the objects inside, so the array or list is a good start. And for the character controller the same (I assume you are using a "Character Controller" component, is far better that having a dynamic rigidbody, unless you want to make one of that funny games when you don't have control over your player ... otherwise go with the character controller.) You will have to move the character controller just like the other rigidbodies.
The character controller isn't great to be honest. I fight this problem constantly as well. There's an asset somewhere that's meant to be a bit better and handling this sort of stuff, maybe give that a go if you haven't got too far into dev yet. https://assetstore.unity.com/packages/tools/physics/kinematic-character-controller-99131 Disclaimer, I haven't used this myself, but I kinda wish i had... It claims to solve all the issues I have with the default character controller. Another issue with the default character controller is that it allocates memory every frame.
Also, just moving the platform up with a line of code like 'transform.position += Vector3.up' is also a "cheap trick", why don't you simulate a rope attached to it and a motor on the other side, and so on and so on.. the point i'm trying to make is if the end result is the same for the user, don't throw away a good solution just because it's "a cheap trick". *not saying my solution is good, just a general piece of advise, altough I think it may do the "trick" as you say
Well, the character controller by itself won't do a thing about that specific problem, you will have to do a spherecast (or whatever) in order to probe the ground, and if the test is successful force the character to the ground (via Move(Vector3.down ...) ), that is called "ground clamping". But, this technique is not a definitive solution (to this problem), because the elevator could be moving too fast, so, just move the character and everything else along with the platform, and problem solve. I didn't know the Character Controller allocates memory, mmm i'm going to do some measures.
I think "isGrounded" become true only when the vertical deltaPosition (y component of the input of the Move method) is negative and the character hits the ground. If the component is zero nothing happens, that's why isGrounded keep showing as true. what ground clamping does is simply probe the ground with a fixed vertical magnitud (independent of the vertical movement) even if the character Y component is negative or not. Of course it depends on the implementation, that's what i do in my asset (while the character is grounded).
I've just built an elevator that's similar in behavior to yours. That is, it moves up and down via Rigidbody.MovePosition. For a while, I was having a similar issue as you: While moving down, any dynamic rigidbodies on the lift would bound a bit. I've gotten that sorted out now, and "passengers" on the lift move smoothly. The big issue I was having was multiple kinematic rigidbodies in my elevator. Do you only have a single rigidbody making up your elevator? For a while, I had more than one, due to my perception that I needed two, for some reason. But it only caused problems. So, first thing, make 100% sure you only have a single kinematic rigidbody making up your elevator. The other observation I have is that we both use a Coroutine to move the platform, and we both move it via MovePosition. However, you're calling MovePosition every frame (as your coroutine uses `yield return null`) while I use `yield return new WaitForFixedUpdate` so that it only calls MovePosition on physics updates. Maybe you can try that?
Yeah, I'm not 100% sure but looking at this: https://docs.unity3d.com/Manual/ExecutionOrder.html I think the yield return null; will make it run every Update rather than every FixedUpdate, and anything where you move Rigidbodies should be done every FixedUpdate or you will get a jittery movement. I might also try making the elevator kinematic and moving it using an Animator rather than a coroutine?
So yeah, yield return new WaitForFixedUpdate(); helped with boxes and stuff, but player was still bouncing. Then I started to move it with elevator. Player's script: Code (CSharp): ... public Transform Elevator { get; set; } = null; public Vector3 ElevatorDelta { get; set; } = Vector3.zero; void FixedUpdate() { // If player is in elevator. if (Elevator) { cc.Move(ElevatorDelta); Elevator = null; } } ... And elevator with a box trigger. I pass traveled distance by elevator to the player: Code (CSharp): void Awake() { rb = GetComponent<Rigidbody>(); } void OnTriggerStay(Collider other) { if (other is CharacterController) { PlayerControls pc = other.GetComponent<PlayerControls>(); if (pc) pc.Elevator = transform; } } public void MoveToFloor(Floors floor) { if (!IsMoving && floor != currentFloor) { currentFloor = floor; StartCoroutine(MoveElevator(floor)); } } IEnumerator MoveElevator(Floors floor) { IsMoving = true; float speed = 0, target = floors[floor]; bool up = target - transform.position.y > 0; while (true) { if (MoveElevator(ref speed, target, up ? Vector3.up : Vector3.down, up)) break; yield return new WaitForFixedUpdate(); } IsMoving = false; } bool MoveElevator(ref float speed, float target, Vector3 dir, bool up) { float t = speed / acceleration; float brakingDistance = acceleration * t * t / 2; // Decelerating. if (brakingDistance >= Mathf.Abs(target - transform.position.y)) speed -= acceleration * Time.deltaTime; // Accelerating. else if (speed < maxSpeed) { speed += acceleration * Time.deltaTime; // Max speed is reached. if (speed >= maxSpeed) speed = maxSpeed; } // New position. Vector3 newPos = transform.position + dir * speed * Time.deltaTime; if (up ? target - newPos.y > 0 : newPos.y - target > 0) { rb.MovePosition(newPos); GameManager._.playerControls.ElevatorDelta = newPos - transform.position; return false; } // Target is reached. else { rb.MovePosition(transform.position.SetY(target)); GameManager._.playerControls.ElevatorDelta = transform.position.SetY(target) - transform.position; return true; } } The only problem left is when elevator moves down, player is slightly jittering:
I fixed jittering by replacing cc.Move(ElevatorDelta); with transform.position += ElevatorDelta;. It seems Move() method is delayed.
Does cc.Move ultimately call Rigidbody.MovePosition? The problem with setting transform.position is that it can cause issues with the physics system. You might not get correct collisions if you manually change the position of a rigidbody transform, as opposed to moving it either via forces or via MovePosition. If you're seeing jittering, and your character has a non-kinematic rigidbody on it, you might just need to set the rigidbody's Interpolation to Interpolate.
I used CharacterController.Move and I'm still using it for moving around, I just don't use it now to add elevator's delta movement to the player. I don't have Rigidbody on the player and I don't know if Move() calls MovePosition(), but I doubt because AFAIK CharacterController doesn't have Rigidbody. There is no Interpolation options for CharacterController either.
Yes, I Know this is from 2015. But I always find solutions for my projects from people who answered later. Well, I tried each tip and possible solutions in the comments but no one worked for me. So I found out the simplest solution: I just made everything that touches the elevator ground it's child. It reduced the bug a lot, but the jittering kept happening, so i changed elevator movement from void Update to FixedUpdate. Now EVERYTHING goes smoothly.