I am trying to make my 3rd person camera not go uner the ground when being rotated or going down a hill, because you can see throught the bottom of the ground, so I want to be able to move it forward until it is not underground anymore, so I can see, but still not be in front of my person.I believe it is possible using raycasts, but I am not advanced enough to know how to do this on my own. I have a custom MouseLook script that I made, no I was wondering if someone could kinda incorperate the raycasting and moving camera into it or tell me how to incorperate it. Said script is attached to an empty object that's position is at my character's head, and my actual camera is a child of it. The empty object is a child of the 3rd person controller, along with the graphics and minimap. Here is my customized MouseLook script:
var sensitivityX : float = 10.0;
var sensitivityY : float = 10.0;
var minimumX : float = -360.0;
var maximumX : float = 360.0;
var minimumY : float = -60.0;
var maximumY : float = 25.0;
var minimumScroll : float = 16.0;
var maximumScroll : float = 20.0;
private var rotationY : float = 0.0;
private var rotationX : float = 0.0;
private var mouseScroll : float = 18.0;
private var mouseDrag : boolean = false;
private var mouseX : float;
private var mouseY : float;
private var mouseStartVector;
private var mouseDownStart : boolean = false;
private var mouseWasDown : boolean = false;
private var haveOverriden : boolean = false;
function Update () {
mouseX += Input.GetAxis("Mouse X");
mouseY += Input.GetAxis("Mouse Y");
if (Input.GetButton ("Fire2")) {
if (mouseDownStart == false){
mouseStartVector = Vector2(mouseX,mouseY);
mouseDownStart = true;
}
haveOverriden = true;
rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
mouseWasDown = true;
if (mouseX == mouseStartVector.x && mouseY == mouseStartVector.y){
mouseDrag = false;
}
else{
mouseDrag = true;
}
}
else{
if (mouseWasDown && mouseDrag == false){
transform.localEulerAngles = Vector3(0,0,0);
rotationY = 0.0;
rotationX = 0.0;
haveOverriden = false;
}
mouseWasDown = false;
mouseDownStart = false;
mouseDrag = false;
}
if (haveOverriden){
transform.localEulerAngles = Vector3(-rotationY, rotationX, 0);
}
mouseScroll -= Input.GetAxis ("Mouse ScrollWheel");
mouseScroll = Mathf.Clamp (mouseScroll, minimumScroll, maximumScroll);
var cameraZoom = Camera.main;
cameraZoom.fieldOfView = mouseScroll*20+50;
}
My script is customized so that you can rotate the camera by dragging the right mouse button but when you only click the right mouse button, the camera resets to it's original position.
Back when I used to use ogre3d I was playing with a 3rd person sandbox environment created and I wanted to implement camera crashing to prevent it from going through terrain and objects. I thought about the problem for a while and came up with a very simply solution that ended up working amazingly well.
Simply attach a character controller to the camera.
It was remarkable how easy and well it worked. Simply tell the camera to move to the position you want it, and the character controller will collide with any objects/terrain it may try pass through preventing it going through them.
It's really easy to implement, requires no maths or complex raycasting in various directions. A basic implementation has a few minor issues (especially) if camera is far away from character. Such as you the character might end up on 1 side of a hill and the camera on the other.
It's not a direct answer to your question, but just something you can consider.
I have worked on this for days now and I have finally invented my own solution:
Add a rigidbody to the camera (not sure if necessary). Add a collider to the camera that has "IsTrigger" checked.
Script:
var target : Transform;
var smoothTime = 0.3;
private var velocity = Vector3.zero;
private var colliding : boolean = false;
function OnTriggerEnter (){
colliding = true;
}
function OnTriggerExit (){
colliding = false;
}
function Update(){
if (colliding){
transform.localPosition = Vector3.SmoothDamp(transform.localPosition, Vector3(0,1,0), velocity, smoothTime);
}
else{
var hit : RaycastHit;
if (Physics.Raycast(transform.position, -transform.forward, hit, 1.5)){
print ("ray has hit");
}
else{
transform.localPosition = Vector3.SmoothDamp(transform.localPosition, Vector3(0,3.5,-6), velocity, smoothTime);
}
}
}
This works with the "IsTrigger" variable of the collider component. When the camera hits something (OnTriggerEnter function), a variable is set that tells the Update function that the camera is hitting something. The Update function then uses SmoothDamp to move the camera towards the target until the OnTriggerExit function sets the collision variable back, letting the Update function know that the camera is not hitting anything. To prevent the camera from zooming in and out and in and out repeatedly, a ray is cast behind the camera to check if there is anything there. If not, the SmoothDamp function moves the camera back until it is hitting something or it is back at the original point of the camera.
Using this script, I am not only able to not see under ground, but I also am able to not see into walls and other objects. However, I am wondering if, like tertle said, the camera might be able to get stuck on one said of a hill or wall and left behind, but considering the type of functions, probably so. Ah well, but I couldn't get the raycast scripts to work, or actually find an explanation of them. You don't learn anything without an explanation, which is why I have supplied one above^.