- Home /
Character Controller doesn't move with a moving parent
Using Unity 2019.1 There's no rigidbody in none of the objects. Character moves with CharacterController.Move method.
MovingPlatform:
Update() { transform.Translate(transform.forward * speed * Time.deltaTime); }
CharacterController:
private void OnControllerColliderHit(ControllerColliderHit hit)
{
if (charControl.isGrounded && hit.transform.tag == "Floor")
transform.SetParent(hit.transform);
}
The character keeps sliding out the platform while standing fixed. Platform has the tag "Floor". The object is being setted as child while looking at hierarchy.
Any solutions?
Ins$$anonymous$$d of changing the hierarchy, could you and the platform's speed to the character's speed?
This would break my logic... In previous versions of Unity, set parent was the way to achieve this. There was some change or is this a bug?
Answer by KazYamof · May 17, 2019 at 05:59 PM
Figured out that if I change the platform from Update to FixedUpdate, changing the parent of CharacterController will works, and it will be carried with the platform.
FixedUpdate
FixedUpdate() {transform.Translate (transform.forward * speed * Time.deltaTime); }
But I can not say if it's a bug or a feature! So, it does not seem to be a 'answer', even if it works
Late Update (not intended to be a pun): it also seems to be sensitive to Script Execution Order between platform rider (that parents/unparents the platform), character movement (that calls char controller's Move), and platform mover (that moves the platform) components. That is exactly the order I put them in to make it work. The default order, whatever it was, failed.
Answer by Kim-Nobre · May 17, 2019 at 04:03 PM
You need to add the platform movement in the CharacterController.Move.
Vector3 externalMovement = externalMoveSpeed * Time.deltaTime;
controller.Move(movement + externalMovement);
The "externalMoveSpeed" is a public Vector3. When the character collides with the platform, the platform should change that value. It would look something like this:
using UnityEngine;
public class Platform: MonoBehaviour
{
private CharacterMovement character;
public Vector3 moveDirection;
private void Update()
{
transform.Translate(moveDirection * Time.deltaTime);
}
private void OnCollisionEnter(Collision collision)
{
if (!character)
{
character = collision.gameObject.GetComponent<CharacterMovement>();
}
character.externalMoveSpeed = moveDirection;
}
private void OnCollisionExit(Collision collision)
{
character.externalMoveSpeed = Vector3.zero;
}
}
But I suggest you put a BoxCollider on top of the platform, check "IsTrigger" and use OnTriggerEnter/OnTriggerExit instead (with that same logic) because when the character moves, the OnCollisionExit method might get called and it won't work properly.
Just a note for future references because this is the first google result: this solution works well, but ONLY if the platforms aren't rotating. If the platforms are rotating you'll have to do some more complicated math or just use the other solution of actually switching the parents.
Another note is to make sure that you undo the parenting when the player jumps off of the platform or else you'll get some weirdness.
Answer by TheHemohscinProject · Apr 22 at 05:03 PM
turns out there's a much easier way to do this, instead of changing the transform in script using an animator and under the update mode change it to "animate physics", setting the object's parent under the same script of moving the character controller in a oncontrollercolliderhit method
void OnControllerColliderHit(ControllerColliderHit hit)
{
if (hit.collider.tag == "floor")
{
transform.parent = hit.transform;
}
else
{
transform.parent = null;
}
}
Answer by unity_l_ltyl3C41NYHQ · May 22 at 01:03 AM
I just got a very simple solution for this problem that might help someone coming to this post. It also solves the problem related to moving the player acordingly when the platform/spaceship rotates, without needing to have it parented!
Instead of parenting the object with the character controller to the platform or whatever, create an empty object and parent it instead. I will call it ghost.
On your custom player controller script, create a reference to the ghost and set its position the same as the player itself on Start():
private void Start() { ghost.transform.position = transform.position; }
Create a Vector3 representing the amount of movement your character should be doing to be synchronized with the platform (IMPORTANT: Make sure to use LateUpdate to create all of the player movement logic now on). Sum up with the movement logic on Move(), reset the ghost position to player position so it is always up to date on where the player is exactly and then get all the movement up to the next frame.
private void LateUpdate() { Vector3 translation = ghost.transform.position - transform.position; controller.Move(translation + movement); ghost.transform.position = transform.position; transform.rotation = ghost.transform.rotation; }
Now its up to you how to customize that. You can also use OnControllerColliderHit() to change which object should the player have its movement synchronized to, like this:
void OnControllerColliderHit(ControllerColliderHit hit) { if (hit.collider.tag == "Ground") { ghost.transform.parent = hit.transform; ghost.transform.position = transform.position; } }
Also a tip: Some unwanted behaviour might happen because of how the Character Controllers collisions works, turning the controller.detectCollisions to false will fix a lot of these problems. However, in order to get it perfect, a workaround is to remove all of the colliders from the object containing the rigidbody, create another independent object with only the colliders and simply copying the transform to the object with the rigidbody, so it will always be at the same pos/rot/scale. That is the most solid I could get. No jittering, no object going through eachother, fluid movement, etc. Hope it helps!
Your answer
Follow this Question
Related Questions
Character controller moves slow when an object its parented 1 Answer
Character-controller offset during gameplay 0 Answers
Weapon passing through colliders (objects)? 0 Answers
Parenting the Character Controller to rigidbody: won't stick 1 Answer
Making the character controller a child of another object 1 Answer