- Home /
Entering/Exiting Vehicle 90% complete
I have put together a working enter & exit system for a car (or any other land based vehicle). I have worked quite hard to piece this system together as I noticed there's many unity questions about this particular system, but few specific tutorials or examples. I have supplied mine below. Please feel free to use it however you like :)
NOTE: Make sure after you import the package, you create a new tag "MMM" or it won't work. Use Enter/Return to enter the car and Space to exit. Textures weren't included to minimize file size.
I would appreciate some help/advice regarding three specific additions I'd like to make to this system:
(1) How can I make the character invisible once it enters the vehicle and have it's collider disabled etc?
(2) If I add additional cameras to the car (eg. Dashboard view, Bumper view etc) how could I switch between them, without switching to the players cameras, and vice versa?
(3) How difficult would it be to convert the current two camera system to a one camera system? Since if for example I have a mere 5 cars in the scene, that will be a difference of having either 5 or 10 cameras to deal with.
I know that the mesh renderer can be disabled: GetComponent(MeshRenderer).enabled = false; but no matter where I put this in the script it simply does not work (example here). Also, for the camera system would it be simpler to create a switching camera system such as the one described here, or would it be better to parent the character to the vehicle upon entering and use the character's cameras to view the vehicle (example here).
Please, if someone knows how to do any one of these, I would really appreciate your help.
Driving Package 10mb
Well, as long as you aren't rendering from more than one camera at a time, there's no real penalty to having a lot of different camera angles to choose from! This only really answers part of your question, and right now I don't have time to go into more detail on the others (sorry) so this goes as a comment...
Answer by save · Oct 10, 2011 at 02:55 PM
Without having the ability to test your package, I'd say that this is the easiest way to solve your problems:
Question 1:
How can I make the character invisible once it enters the vehicle and have it's collider disabled etc?
Your options are to either make the collider into a trigger and inactivate the renderer, use the camera layers for culling or inactivate the GameObject. I'm not sure what the problem with your script is, try to isolate the event within a new project where you only disable an object. If the object is separated into several GameObjects then you'd have to iterate through them. Use #pragma strict to make sure dynamic scripting is off so you get a more reliable workflow.
#pragma strict #pragma downcast
private var player : GameObject;
function Start () { player = GameObject.Find("Player"); }
function OnEnterVehicle () { player.renderer.enabled = false; player.collider.isTrigger = true;
}
function OnExitVehicle () { player.renderer.enabled = true; player.collider.isTrigger = true; }
To iterate through the components use this (and this is why we use #pragma downcast):
for (child in player.transform) {
child.renderer.enabled = false;
}
Question 2:
If I add additional cameras to the car (eg. Dashboard view, Bumper view etc) how could I switch between them, without switching to the players cameras, and vice versa?
You could consider setting everything up with just one camera and make that camera reposition itself. Although you probably want to have different abilities for them where one camera is able to move smoothly around the player and several of them stuck onto the object (like the bumper camera). Then it's easier to work with several cameras in the scene where you just switch between them. They all have their separate scripts which gets activated if the camera is in use.
To iterate through your current cameras you can use something like this:
#pragma strict
var currentCamera : int = 0; var cameras : Camera[];
function Start () { SwitchCamera(false); }
function Update () { if (Input.GetKeyDown(KeyCode.C)) { SwitchCamera(true); } }
function SwitchCamera (switchCam : boolean) {
if (switchCam) {
if (currentCamera < cameras.length-1) {
currentCamera++;
} else {
currentCamera = 0;
}
}
for (cam in cameras) {
cam.enabled = false;
cam.GetComponent(AudioListener).enabled = false;
}
cameras[currentCamera].enabled = true;
cameras[currentCamera].GetComponent(AudioListener).enabled = true;
}
To make this work you'd have to only have the cameras for the car inside the cameras
array. When you enter the car you activate the script object (or instantiate the cameras childed to an empty GameObject as a prefab - remember in that case to destroy the earlier set of cameras) and deactivate the camera for the player:
function OnEnterVehicle () {
player.renderer.enabled = false;
player.collider.isTrigger = true;
//Adding:
vehicleCameras.active = true;
playerCamera.active = false;
}
Then you'd reverse it for OnExitVehicle()
.
You could then have a reference to the car you just entered and let the script know what object to position and child itself to.
static var enteredVehicle : GameObject;
function OnEnterVehicle () {
player.renderer.enabled = false;
player.collider.isTrigger = true;
vehicleCameras.active = true;
playerCamera.active = false;
//Adding:
enteredVehicle = theCar;
vehicleCameras.transform.position = theCar.transform.position;
vehicleCameras.parent = theCar.transform;
}
There are a couple of ways to determine what car has been entered. One is to tag them within their script with an int which gets referenced to by the player, or you could determine this with a raycast from the player at entrance. So theCar
would be set as a GameObject from a raycast inside OnEnterVehicle()
. You'd call OnEnterVehicle()
inside an update if the player is looking at a car, pressing the button and by checking its distance.
You probably have different sizes of the vehicles where you'd have to reposition some of the cameras. This can be done quite easily with a predefined case-switch:
function SwitchCamera (switchCam : boolean) {
//Do this after you've altered currentCamera
switch (currentCamera) {
case 0:
cameras[currentCamera].transform.localPosition = Vector3(-2,0,4);
break;
case 1:
//and so on
break;
}
}
You could also position them towards another array with empty GameObjects:
cameras[currentCamera].transform.position = positions[currentCamera].transform.position;
Question 3:
How difficult would it be to convert the current two camera system to a one camera system? Since if for example I have a mere 5 cars in the scene, that will be a difference of having either 5 or 10 cameras to deal with.
It would be easier to have two separated systems for vehicles and walking. The main reason is that you can deactivate camera-scripts that isn't needed easier. You just switch between the systems like described in the answer for Question 2. If you only use one camera or one base for all cameras then you'd have to have a quite large case switch which isn't necessary if you instead object orient this.
Firstly, thank you so much for your effort Save. I was a little worried that this would seam like too much work for anyone who actually knew how to do it. I'm not expecting people to write my entire script for me, which is why I've put together most of the hard work myself. However as I am still a javascript program$$anonymous$$g novice I may have to ask you some very newb questions. I apologize in advance.
The way the current camera system works is that the character cam is a basic smooth follow (Camera1), which upon entering the car changes to a camera (CameraC) that, as far as I understand, tags either the character or the vehicle by a predefined tag ($$anonymous$$$$anonymous$$$$anonymous$$), since all of these objects are untagged before/after runtime. Here is a link to a webplayer using a similar system to $$anonymous$$e. Hope this helps.
(1) I have been testing this script extensively. I am assu$$anonymous$$g it only needs to be applied to one relevant Gameobject but I tried all the combinations anyway just in case. I've tried attaching to the camera, character, vehicle separately, and to all at once, and to two at once etc. But unfortunately the results are the same, and the character is still visible.
(2) When I add the camera names ("CameraC", "CarFrontCam")to the array (var cameras : Camera[];) I get a: UCE0001: ';' expected. Insert a semicolon at the end, error. The second camera is parented to the car, I'm not sure if that makes a difference.
I think you're definitely right about separating the cameras between vehicle and character. I asked since Unity does not feature a folder system in the hierachy, so large numbers of runtime assets (Cameras) are not so easily organized. Thanks again, looking forward to hearing from you.
Here is a copy of the the script attached to the vehicle. It is the main script controlling the interaction.
//
var somer = 0;
//
var btarget : Transform;
function OnTriggerEnter (other : Collider) {
// if (gameObject.tag == "$$anonymous$$$$anonymous$$$$anonymous$$") gameObject.tag = "$$anonymous$$$$anonymous$$$$anonymous$$";
// if (gameObject.tag == "Untagged") gameObject.tag = "Player";
somer=2;
}
// //
function OnTriggerExit (other : Collider) {
if (gameObject.tag == "$$anonymous$$$$anonymous$$$$anonymous$$") gameObject.tag = "$$anonymous$$$$anonymous$$$$anonymous$$";
if (gameObject.tag == "Player") gameObject.tag = "Untagged";
somer=0;
}
function Update () {
//var go = GameObject.Find("3rdPerson"); // go.active = false;
rigidbody.drag = 0;
//
if (gameObject.tag== "Player"){
//
if (Input.Get$$anonymous$$eyDown ("return")&& (somer==2)&& GetComponent (Car)){
//
gameObject.tag = "$$anonymous$$$$anonymous$$$$anonymous$$";
//
btarget.position = transform.position;
//
GetComponent (Car).enabled=true ;
//
var go = GameObject.Find("3rdPerson");
go.animation.enabled = false;
go.GetComponent(ThirdPersonController).enabled = false;
//
var go1 = GameObject.Find("Camera1");
go1.GetComponent(Camera).enabled = false;
//
var go3 = GameObject.Find("CameraC");
go3.GetComponent(Camera).enabled = true;
}
}
if (Input.Get$$anonymous$$eyDown ("space") &&(gameObject.tag== "$$anonymous$$$$anonymous$$$$anonymous$$")){
var go33 = GameObject.Find("CameraC");
go33.GetComponent(Camera).enabled = false;
//go.active = true;
//
GetComponent (Car).enabled=false ;
// go3.GetComponent(Camera).enabled = false;
//
var go21 = GameObject.Find("3rdPerson");
go21.transform.position=transform.position + Vector3(6,2,0);
//
var go221 = GameObject.Find("Camera1");
go221.GetComponent(Camera).enabled = true;
//
rigidbody.drag = rigidbody.velocity.magnitude / 00;
//
somer=0;
gameObject.tag = "Untagged";
}
}
You don't have to apologize, we've all been there. ;-)
About folder hierarchy: You can always group objects by empty GameObjects. That's how you could do to easily attach several cameras to one object using the parenting method. Which means you'd have one empty GameObject (but it could also have the camera-switch script for the cars), the cameras as children and the GameObject childed to the current selected car.
The array problem: What does your array look like? It sure sounds like something is missing in the script for the array. If you have something like 'if (this > that.length)' then the script inside probably is ignored until you fill the array - so look for what happens inside that particular statement. You should get a line number and if you double click the error in the console (using $$anonymous$$ono Develop) you'd go to that particular line. Sometimes the error you have isn't what expected, where you might have scripted something erroneous in the actual language ins$$anonymous$$d of forgot the semicolon.
Parenting objects will not make a difference for what happens inside an array unless you specifically address that. The objects are referenced by their GameObject ID inside the hierarchy whenever you do this: 'var myGameObject : GameObject;' or 'var myGameObjectArray : GameObject[];'
Regarding visibility of character: You could also cull the character by layers, making the camera for the car not render that particular layer of the player. You'd still have to disable the collider though for the player. I'd keep a reference to the player from start, where a 'var player : GameObject;' always can activate or deactivate the entire GameObject.
$$anonymous$$eep in $$anonymous$$d that disabling a GameObject entirely will also disable their entire scripts, so if you reference to things attached to that GameObject you'd need to prepare for that, this can be done with a simple 'if(player)'. So basically, try to object orient everything, the player should only have scripts that control that particular GameObject - where references that might be needed even if a GameObject is disabled - should be in an object that act as a manager and never gets touched, until you programmatically say so. This is also good when looking at the bigger picture where you can load another level and use 'DontDestroyOnLoad' for a managing object. This will help you keep things organized the levels through.
Also try to use references from the beginning ins$$anonymous$$d of finding objects at runtime, lookups are heavier than you sometimes might expect. Doing lookups every time the user interacts with something could ins$$anonymous$$d be a predefined lookup in the 'Start ()' function or as your structure seem, a variable set in the inspector which never gets altered by script. Again here would a manager come in handy too.
I'd also recommend on posting this on the Unity Forums as you seem to want help in a very broad topic. Unity Answers is more of a specific issue - kind of deal.
Omg, I completely forgot about the camera culling system! I tried this and it worked, I can't believe I didn't think of such a simple solution. Thank you so much Save, you're a champ!!
I think for now I'll leave the camera system as is, since it isn't the most important thing and if I spend too much time trying to make everything exactly how I want it, I'll never get what needs to be done finished.
If you would like to repost the culling para above as an answer, I can mark it correct so you get the much deserved kudos ;) Thanks again Save
Your answer
Follow this Question
Related Questions
Renderer on object disabled after level reload 1 Answer
Make a simple tree 1 Answer
Camera Switching or Scene Changes? 3 Answers
Camera be invisible in scene view for all my projects 2 Answers