Parenting to a vehicle and switching controllers......

Can’t figure it out. I’ve been through dozens of discussions which you’d think would answer it but none of the answers seem to work.

For some reason it was more complicated to parent the player prefab to a vehicle using gameobjects as mountpoints so I just use myTransform.Translate(0,1.5f, 2) to move the character up and over.

Currently the trigger event fires off a function called Mount() looks like:

public void Mount() {		
_horse = transform.Find("Horse");
CharacterController playerMove = _controller; //previously cached it in script
CharacterController horseMove = GetComponent<CharacterController>(); //how I get horse controller?	

     _myTransform.parent = _horse;		
     playerMove.active = false; //turns controller off to switch to next.
     horseMove.active = true; //turn horse controller on

     _myTransform.Translate(0,1.5f,3);
     _myTransform.transform.localRotation = Quaternion.identity;	

   //also tried stuff like this
   //  _horse.GetComponent<CharacterController>().active = true;
   
}

Basically when I run into anything tagged “horse” it triggers that function which turns me to face forward and moves the char up and over while disabling the controller, but I can’t figure out how to access the horse controller to turn it on. I tried a tank controller script, several car controllers and just cannot figure it out. Anything would work, even a FPS controller to drive the horse so I can turn with the mouse and use WASD and maybe even jump…

What object is this script attached to?

It’s actually inside my AdvancedMovement.cs script (modified fps walker I believe) I use for both the player and mob’s movement…for the player I use PlayerInput.cs to send messages to AdvancedMovement based on input from the user. Or in the case of the Mobs use an AI.cs script to determine what input to give and sends messages the AdvancedMovement.cs script as well.

So basically I also gave the playerInput, advancedMovement.cs, rigidbody(with and without), character controller, script to my horse prefab as well, then drug the horse prefab into my mob generator slot so it spawns an instance of one when I log in…

The flow of things is:
PlayerInput.cs has:

void Update() {
if(mount == true) {
		SendMessage("Mounted", true);
} else {
		SendMessage("Mounted", false);
     }
}
[B]public void OnTriggerEnter(Collider other)[/B] {

if(other.CompareTag("Water"))
	SendMessage("IsSwimming", true);

else if(other.CompareTag("Horse"))
	[B]mount = true;[/B]
}
[B]public void OnTriggerExit(Collider other) {[/B]
if(other.CompareTag("Water")) 
	SendMessage("IsSwimming", false);
else if(other.CompareTag("Horse"))
	[B]mount = false;[/B]
}

So it sets mounted true which gets caught in the If statement in the update() and sends a message called (“Mounted”, true) to AdvancedMovement.cs

AdvancedMovement.cs:

public void[B] Mounted (bool mount)[/B] {
	_isMounted = mount;
}

which gets caught in another If else statement inside a function called ActionPicker() like so.

private void ActionPicker() {
if(_controller.isGrounded || _isSwimming || _isCrouching  || _isClimbing || _isMounted) {

//goes down a list of If, Else statements looking for the variable clause that matches

[B]} else if(_isMounted ) {
	Mount();[/B]
}

So Since _isMounted was set to true, the else if runs calling Mount()

public void [B]Mount()[/B] {	
CharacterController playerMove = _controller;
CharacterController horseMove = GetComponent<CharacterController>();	

_myTransform.parent = _horse;	
_myTransform.Translate(0,1.5f,3);
_myTransform.transform.localRotation = Quaternion.identity;	

playerMove.active = false;	
horseMove.active = true;
}

The player’s transform is cached earlier in the script as _myTransform, the player’s charactercontroller is cached as _controller

Edit:: also forgot at the top of that script I (try to at least) cache the horse transform as _horse with:

_horse = transform.Find("Horse");

Not sure how that would work if there were more than 1 horse though…

The reason for using the Advanced Movement script was to expose variables for all my animations so it was “supposed” to be easy to swap the controls around with different objects, then just type in the particular name of that object’s animations into the right slot. It then substitutes the right name into the function that ties the animation to input so going forward also plays the walk animation + sound, etc.

Well it seems to be that my AdvancedMovement and PlayerInput scripts only work on 2 models and don’t work on the rest. I don’t have any understanding why it works on 2 characters and not the others…they are all fbx and all have a dozen+ animations.

On the characters that don’t work with my custom scripts I can hack together a script to like:

function Awake() {
form = GetComponent(Transform);		
animation["Walk"].wrapMode = WrapMode.Once;
}

function Update() {
	if(Input.GetButtonDown("Jump")) {
		form.Translate(0,5,0);
			animation.Play("Jump");
		}
	if(Input.GetButton("Move Forward")) {
		transform.Translate(0,0,1);
			animation.Play("Walk");
		}
}

…and the characters will move and play their animations, so the models definitely do work. But I don’t know why they won’t work with the normal scripts I use…when I can log in with 2 other characters and they work fine but not with several characters I bought including the horse…

I can put my hacked testing script on the horse and drive it around but if I put my custom input/movement scripts on it doesn’t work but it triggers debug statements showing that the input got into the movement script and just doesn’t trigger an event in the “ActionPicker()”. It even goes so far to trigger the event but ActionPicker() never catches it.

PlayerInput sends a message to AdvancedMovement, Advancedmovement changes a variable that’s supposed to trigger an else if(condition met) but the condition never gets met. Could it be resetting itself before it fires or something? It works on 2 other characters as it is though…

Ok, I’m not quite sure what’s going on here. You’re calling transform.Find(“horse”), but transform.Find will only look for objects that are children of the object your script is attached to. Is this your intention?

No, that’s what I’m not sure. I think I want the parent transform of the horse, then child the player to the horse when the collision enters.

The horse has a box collider that is a little bigger than the horse mesh, if you run straight at the horse and enter the trigger collider it spins you to face the same direction as the horse, it disables your character controller and you’re then stuck.

I was messing with it last night on a different level and I got my other characters to work, and can drive the horse without the player mounted using my script, but when you run the player into the horse it gives a NULLEXCEPTION and disables your (players) movement controller, when you click the error it opens AdvancedMovement at the line of the where I try to set the horses controller to active…

Edit:: also the alternative to the NullException is a warning message saying something like “component.move is being called but is not enabled”. Something to that effect after it turns off the player controller.

Basically I just need to know how to access the horses controller to turn it on. Or cache the horse first then access it’s components…

I was having trouble figuring out how do you get the transform of the object you collide with? Like if there are 20 horses and I run into 1 causing a trigger how can I distinguish that horse from the others to parent my character and activate that 1 horse’s controls???

//-----------------------------------------------------------------------------
Different question for the same problem. Alternatively I tried to make the mounting work with 2 game objects called Saddle and Tush. “Saddle” is childed to the horse prefab and positioned where I want the player to sit on the horses back. “Tush” is child to the Player prefab and centered at his wast.

I abandoned this because I couldnt get it to work but I think that was a problem again of not knowing how to access objects/components from the other models.

I read through the Unity Resources where it shows you how to access other scripts/components but I don’t seem to do it right…

Yeah, I think all you need to do is get the transform of the object you collide with, like so:

 void OnTriggerEnter(Collider other) {
        Transform colTransform = other.transform;
    }

Hope that helps.

That’s what Im looking for, I think the problem is how do I access it in AdvancedMovement.cs when the onTrigger is in PlayerInput.cs?

I see how to do it with scripts here: Unity - Scripting API: Component.GetComponent but is a transform the same way?

In AdvancedMovement.cs I need to cache colTransform from PlayerInput.cs. In PlayerInput, inside the OnTriggerEnter(), I put: Transform colTransform = other.transform;

Inside AdvanceMovement how do I get colTransform from OnTriggerEnter() and cache it to otherTransform inside AdvancedMovement?

I tried this to test but it gives a null reference exception

Transform otherTransform = GameObject.Find("Horse").GetComponent<Transform>() as Transform;

CharacterController playerMove = GetComponent<CharacterController>();
CharacterController horseMove = otherTransform.GetComponent<CharacterController>();
PlayerInput otherInput = otherTransform.GetComponent<PlayerInput>();
playerMove.active = false;	
otherTransform.active =true;
otherInput.active = true;

Thanks for your guidance, it’s so close, it mounts and can spin the horse.

Are AdvancedMovement and PlayerInput on the same gameobject?

Edit: nevermind, I reread your post and get it now.

You don’t really need to cache the coltransform in your PlayerInput. Just put the OnTriggerEnter() override into your AdvancedMovement script.

I’d never heard of override. I looked it up and tried it but since both scripts derive from monobehaviour it gives errors saying a suitable match to override cant be found, because they don’t derive from one another.

I put

public void OnTriggerEnter(Collider other) {		
	 if(other.CompareTag("Horse")) {
	Transform otherTransform = other.transform;
		 Debug.Log(otherTransform);
	}
}

at the bottom of my AdvancedMovement script.

If I run into the horse it logs out the horses transform.

At the beginning I declare Transform otherTransform;

Then I try to access it in my Mount() function but it gives a null reference…so it’s local to ontriggerenter()…I tried to assign it outside of ontriggerenter() and can’t.

You’re on the right track.

You need to define the horse transform as a private variable at the beginning of your script:

private Transform horseTransform;

Then assign it in OnTriggerEnter:

public void OnTriggerEnter(Collider other){
     if(other.CompareTag("Horse")){
          horseTransform = other.transform;
     }
}

Hope that helps!

Thanks so much. I tried that and it still wasn’t working but I figured out the horse was tagged “Horse” and since it has AdvancedMovement as well it was causing it to trigger with itself, it would mount itself onto itself up and over and turn off its controller. Then if the character ran into it’s trigger again it would get stuck and have it’s controller turned off, and the only thing you could do from there was spin around thanks to the mouselook script.

I just went to the Mount() function and wrapped everything in an if(transform.CompareTag(“Player”)) {//mount the player to the code and switch controllers} and it works great, you run into the horse and can drive it around perfectly, toggle cameras. Now I just need to make a hotkey that unparents it :slight_smile:

Thanks a ton.

Great! Glad you got it working.