Moving a CharacterController Object together with a RigidBody Object

Hey everyone,

I’ll just get straight in to the problem. Basically I have a ship that the player can use. This ship is a Rigidbody and the player is a CharacterController. The player can press a button to use the ship and steer it, basically what happens is I turn off all the scripts moving the character and turn on all the scripts to move the ship, change the camera angle, etc. etc.

Quite obviously because the character is a CharacterController he will keep his current position and will basically slide off of the ship when it moves, or better said the ship moves out from underneath him as he stands still until the ship is away from him and he plunges in the water.

That was fine and all and is normal, however I wanted the character to be able to just stand still on the ship as it moves, and move with it. First I tried making the ship the players parent as it moves around, however the problem with this is that it only works when his CharacterController is fully turned off, but if I do that and then turn it on again when the player stops using the ship it means that the ship will continue to move a little longer until it comes to a standstill but at that moment the player glides over the deck of the ship, so that is sadly enough not an option. Then I tried the following piece of code:

using System.Collections;

public class objectsstick : MonoBehaviour {

	private float XNow;
	private float YNow;
	private float ZNow;
	private float XPrev;
	private float YPrev;
	private float ZPrev;

	void Start(){

		XNow = this.transform.parent.transform.position.x;
		YNow = this.transform.parent.transform.position.y;
		ZNow = this.transform.parent.transform.position.z;

	}

	void OnTriggerStay(Collider collisionObject) {
		
		if (collisionObject.GetComponent<CharacterController> () != null) {
			
			if(collisionObject.GetComponent<CharacterController>().enabled != false){
				
				if (collisionObject.tag != "Ship") {

					XPrev = XNow;
					YPrev = YNow;
					ZPrev = ZNow;
					XNow = this.transform.parent.transform.position.x;
					YNow = this.transform.parent.transform.position.y;
					ZNow = this.transform.parent.transform.position.z;

					float differenceX = XNow - XPrev;
					float differenceY = YNow - YPrev;
					float differenceZ = ZNow - ZPrev;

					collisionObject.transform.position = new Vector3 (collisionObject.transform.position.x + differenceX, collisionObject.transform.position.y + differenceY, collisionObject.transform.position.z + differenceZ);

					
				}
				
			}
			
		}

	}

}

basically what this code does is as long as something that is not part of the ship (in this case the player) is touching the ship then take the current position’s x y and z values, store those and do the same for those of the previous frame. Then find out what the difference is between the values of this frame and the previous one (so if in the previous fram we where at 1,0,1 and now we are at 2,0,2 then it should give me back 1,0,1 as the x,y,z differences) and then add those differences to the objects position so he moves with the ship.

Now the problem I am having is that it does seem to be added, however the object instead of staying still moves faster and faster, so if the ship is going forward and the player is our object then the player continue to speed up further and further until it falls off of the front of the ship, same goes in reverse and for falling off the back.

I have tried (in a desperate attempt) to add * time.deltaTime to the differnce’s but that only made it worse which I more or less expected seeing as it should be calculated on a frame by frame basis and should thus also be addes on a frame by frame basis and deltaTime should have nothing to do with it.

I hope one of you guys might know a way of doing this. Thanks already everyone!

EDIT: Just found out my code does actually work as long as I am not steering the ship, however if the ship is moving while the player just stands there it does seem to work.

EDIT2: Finally found out what the problem was. In another code (used to go in and out of steering the ship) the player is parented to the ship, thus it already had the ships velocity and we where now just adding even more movement to that, that was why the player started going faster that the ship. I’ll just leave this here on the forums in the case that someone ever finds it usefull.

Good luck to anyone else experiencing similar problems

You could define a box collider on the vehicle that represents the “cockpit”, and if the player enters the cockpit, bind their position to the position of the vehicle. There might be some weirdness when trying to disembark, but this should get you fairly close:

private gameObject _cockpit;

public void OnTriggerEnter(collider other) {
    if (other.tag != "cockpit") return;
    _cockpit = other.gameObject;
}

public void Update() {
    if (_cockpit != null) {
        transform.position = _cockpit.transform.position;
    }

    if (_cockpit != null && (Math.Abs(Input.GetAxis("Horizontal")) > 0.1 || Math.Abs(Input.GetAxis("Vertical")) > 0.1)) {
        // disembark if the player moves.
        _cockpit = null;
    }
}

I don’t have Unity in front of me right now, so forgive me if this doesn’t compile. But you should get the gist of it from that.