About Camera Collision
Hello. I'm trying to make my camera zoom in to my character when collide with the terrain. I know that I should use Physics.Linecast to set my camera origin and my character's position. But I'm stuck at coding. I need help. Here is my code. The code is a camera that follows a player.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraScript : MonoBehaviour {
public Transform lookAt;
public Transform camTransform;
private const float Y_ANGLE_MIN = 5.0F;
private const float Y_ANGLE_MAX = 50.0F;
private Camera cam;
private float distance = 20.0f;
private float currentX = 0.0f;
private float currentY = 0.0f;
private float sensivityX = 4.0f;
private float sensivityY = 1.0f;
private void Start()
{
camTransform = transform;
cam = Camera.main;
}
private void Update()
{
currentX += Input.GetAxis ("Mouse X");
currentY += Input.GetAxis ("Mouse Y");
currentY = Mathf.Clamp (currentY, Y_ANGLE_MIN, Y_ANGLE_MAX);
}
private void LateUpdate()
{
Vector3 dir = new Vector3 (0, 0, -distance);
Quaternion rotation = Quaternion.Euler (currentY, currentX, 0);
camTransform.position = lookAt.position + rotation * dir;
camTransform.LookAt (lookAt.position);
}
}
Answer by theterrificjd · Dec 13, 2017 at 02:40 PM
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraOrbitControl : MonoBehaviour {
public GameObject target;
public float distance = 5.0f;
public float sensitivityX = 20.0f;
public float sensitivityY = 20.0f;
public float yMinLimit = -30;
public float yMaxLimit = 75;
public float minimumDistance = 1f;
public float maximumDistance = 50f;
public float pushDamping = .01f;
private float currentDistance;
private bool hasHit;
private Vector3 hitPoint;
private Vector3 hitNormal;
private float hitDistance;
private float hitTimer;
private float clippedDistance;
private float currentX = 0.0f;
private float currentY = 0.0f;
public float cameraSmoothing = 0.2f;
private float currentSmoothing;
private bool forcingSmooth;
private float xSmooth = 0.0f;
private float ySmooth = 0.0f;
private float xVelocity = 0.0f;
private float yVelocity = 0.0f;
void Start () {
currentDistance = distance;
currentSmoothing = cameraSmoothing;
}
public void ForceSmoothing() {
currentSmoothing = 0f;
forcingSmooth = true;
}
void Update ()
{
if (forcingSmooth) {
currentSmoothing += Time.deltaTime / 100f;
Mathf.Clamp (currentSmoothing, 0, 1);
if (currentSmoothing >= cameraSmoothing) {
currentSmoothing = cameraSmoothing;
forcingSmooth = false;
}
}
if (target)
{
currentX += Input.GetAxis("Mouse X") * sensitivityX;
currentY += Input.GetAxis("Mouse Y") * sensitivityY;
currentY = Mathf.Clamp(currentY, yMinLimit, yMaxLimit);
xSmooth = Mathf.SmoothDamp(xSmooth, currentX, ref xVelocity, currentSmoothing);
ySmooth = Mathf.SmoothDamp(ySmooth, currentY, ref yVelocity, currentSmoothing);
float posOrNeg = Input.GetAxis ("Mouse ScrollWheel");
float wheelDistance = distance - posOrNeg * distance;
if (wheelDistance < maximumDistance) {
if (posOrNeg > 0) {
distance = Mathf.Clamp (wheelDistance, minimumDistance, maximumDistance);
}
}
if (wheelDistance > minimumDistance) {
if (posOrNeg < 0) {
distance = Mathf.Clamp (wheelDistance, minimumDistance, maximumDistance);
}
}
RaycastHit hit;
int layermask = ~((1 << 9) | (1 << 8)) ;
float smoothOverride = currentSmoothing;
if (Physics.Raycast (target.transform.position, transform.position - target.transform.position, out hit, maximumDistance, layermask)) {
hasHit = true;
hitPoint = hit.point;
hitDistance = hit.distance;
forcingSmooth = true;
clippedDistance = hit.distance;
} else {
clippedDistance = currentDistance;
hasHit = false;
}
if (currentDistance > clippedDistance) {
distance = Mathf.Lerp (distance, clippedDistance, smoothOverride * pushDamping);
currentDistance = Mathf.Lerp (currentDistance, clippedDistance, smoothOverride);
} else {
currentDistance = Mathf.Lerp (currentDistance, distance, smoothOverride);
}
transform.localRotation = Quaternion.Euler(ySmooth, xSmooth, 0);
if (hasHit) {
transform.position = Vector3.Lerp (transform.position, transform.rotation * new Vector3 (0.0f, 0.0f, -currentDistance) + target.transform.position, smoothOverride * 5f) + hitNormal * .5f;
} else {
transform.position = Vector3.Lerp(transform.position,transform.rotation * new Vector3(0.0f, 0.0f, -currentDistance) + target.transform.position,smoothOverride * 5f);
}
}
}
}
@Paincide I finally have it perfect! It rotates around the object (should be both parent object and set to target in the editor view). This is based entirely on the targets up direction too, so if you rotate the camera will rotate. You can always parent a Rig to follow the target object without rotation to fix this (ie: if your object is a ball, you obviously don't want the camera to roll with it).
Thanks for the answer! But I've got a problem. When I move my character, the camera zooms in really deep in to my character and it stays there. What I checked is
Player is set to layer8(player)
Terrain is set to layer0(default)
The Player has one box collider and rigid body(I use box collider ins$$anonymous$$d of mesh collider)
There is no collider between The Player and the Terrain
Here is the pics.
I've updated my original answer to include a whole script that I added and tested in a fresh scene. It collides fairly well, and with the new smoothing values (you may need to right click and reset the script, or adjust them yourself), it functions pretty well.
I don't know what could've gone wrong and where, but make sure the script is attached to the Camera, not the gameobject (not sure just by the way you have camTransform declared, if its on the camera, you can just type transform to access the transform object, so that's why I say this).
I fixed my problem. I just let my Terrain to layer8 and player to layer0... Worked! Thx!
Hey, make sure you also don't have a collider attached to your camera, or that will cause issues. If you do, make sure it's on the same layer mask.
I didn't attach any collider to my camera. And $$anonymous$$y camera's layer is set to layer9 same as my player's layer. The zoom in works really fine. I calculates the collider and works really cool. But it never zoom out.
sorry for another reply. It seems to work, but it keeps going stick to Character.. Layer is not the problem
$$anonymous$$ake sure there are no child objects on the character that aren't on the layer.
Also, I've added a few more smoothing functions to the original script (couldn't help refining it while I had it open).
I checked all of it... But it keeps zoom in whether it doesn't have to be. I set my terrain and all others to default and only character and its child a Player layer. It keeps magnify and not co$$anonymous$$g back to it's position.
Answer by Paincide · Dec 14, 2017 at 07:14 AM
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraScript : MonoBehaviour {
public Transform lookAt;
public Transform camTransform;
private const float Y_ANGLE_MIN = 0.0F;
private const float Y_ANGLE_MAX = 60.0F;
private Camera cam;
public float cameraWidth = 5f;
public float minimumDistance = 20f;
public float maximumDistance = 20f;
public float cameraSmoothing = 5f;
public float pushDamping = 1f;
private float clippedDistance;
private float currentDistance;
private float distance = 20.0f;
private float currentX = 0.0f;
private float currentY = 0.0f;
private float sensivityX = 4.0f;
private float sensivityY = 1.0f;
private void Start()
{
camTransform = transform;
cam = Camera.main;
}
private void Update()
{
currentX += Input.GetAxis ("Mouse X");
currentY += Input.GetAxis ("Mouse Y");
currentY = Mathf.Clamp (currentY, Y_ANGLE_MIN, Y_ANGLE_MAX);
}
private void LateUpdate()
{
Vector3 dir = new Vector3 (0, 0, -currentDistance);
Quaternion rotation = Quaternion.Euler (currentY, currentX, 0);
camTransform.position = Vector3.Lerp(camTransform.position,lookAt.position + rotation * dir,cameraSmoothing);
camTransform.LookAt(lookAt.position);
RaycastHit hit;
int layermask = ~(1<<9);
if (Physics.Linecast (lookAt.position, transform.position, out hit, layermask))
{
if (hit.distance < clippedDistance - .1f && hit.distance > minimumDistance) clippedDistance = hit.distance - cameraWidth;
}
else
{
clippedDistance = distance;
}
if (distance > clippedDistance) {
currentDistance = Mathf.Lerp (currentDistance, Mathf.Clamp (clippedDistance, minimumDistance, maximumDistance), cameraSmoothing);
distance = Mathf.Lerp (distance, clippedDistance, cameraSmoothing * pushDamping);
}
else
{
currentDistance = Mathf.Lerp (currentDistance, Mathf.Clamp (distance, minimumDistance, maximumDistance), cameraSmoothing);
}
}
}
First of all, thanks for the kind reply. I tested all kind of stuff. I changed all kind of values. I changed the center of my model. I changed the parent of my gameobject. I changed position to 0,0,0 of my gameobject. I double checked that my script is in my camera. I checked the layers twice and checked only my player is layered in 9(which is player layer). I changed the script as you said and added the line you told me. The camera zooms really cool and well, but after it zooms in, it never zoom out. If I change my minimum to 1~19 and maximum to 20, it always zoom in and never zoom out. I tried to set lower maximum and higher maximum too. But it never zoom out. Can you suggest me any more solutions?