- Home /
How to get Camera Collision Detection on Terrain
I wrote a third person controller and used part of a collision detection script that I found online. Currently it is able to move the camera in closer whenever objects are inbetween the camera and the player, but not when the terrain in inbetween the camera and the player.
Everything I use for detecting if there is an object between the player and the camera can be found in the OccludeRay method. Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraScript : MonoBehaviour {
[SerializeField]private GameObject player;
[SerializeField]private float cameraRadius;
[SerializeField]private Vector3 cameraOffset;
[SerializeField]private LayerMask CamOcclusionLayers;
private Vector3 camDistance;
private Vector3 camAnchor;
private Vector3 camDesiredPosition;
private Vector3 camMask;
[HideInInspector]public float cameraAngleX=0;
[HideInInspector]public float cameraAngleY=0;
// Use this for initialization
void Start () {
camAnchor = player.transform.position - cameraOffset;
transform.position = camAnchor - new Vector3(0,0,cameraRadius);
}
// Update is called once per frame
void Update () {
updateCamera ();
}
void updateCamera()
{
cameraAngleX += Input.GetAxis("Mouse X");
cameraAngleY -= Input.GetAxis("Mouse Y");
if (cameraAngleY > 90) {
cameraAngleY = 90;
}
if (cameraAngleY< -90) {
cameraAngleY = -90;
}
camAnchor = player.transform.position - cameraOffset;
camDistance = new Vector3 (cameraRadius*Mathf.Sin(cameraAngleX*Mathf.PI/180),cameraRadius*Mathf.Sin(cameraAngleY*Mathf.PI/180), cameraRadius*Mathf.Cos(cameraAngleX*Mathf.PI/180));
camMask = camAnchor - camDistance;
camDesiredPosition = camAnchor - camDistance;
occludeRay (ref camAnchor);
transform.position = camDesiredPosition;
transform.LookAt (camAnchor);
}
void occludeRay(ref Vector3 target)
{
//declare a new raycast hit.
RaycastHit wallHit = new RaycastHit();
//linecast from your player (targetFollow) to your cameras mask (camMask) to find collisions.
if (Physics.Linecast(target, camMask, out wallHit, CamOcclusionLayers))
{
//the smooth is increased so you detect geometry collisions faster.
//smooth = 10f;
//the x and z coordinates are pushed away from the wall by hit.normal.
//the y coordinate stays the same.
camDesiredPosition = new Vector3(wallHit.point.x + wallHit.normal.x * 0.5f, camDesiredPosition.y, wallHit.point.z + wallHit.normal.z * 0.5f);
}
}
}
Answer by GermiyanBey · Dec 16, 2019 at 02:28 PM
I would like to share my solution if anyone is needing. This method minimized passing through terrain very much for me.
What I did is simply, stopping the Camera Zoom by checking the distance of Camera to Terrain by sending a Raycast from Camera to Terrain. If the distance between Camera and Terrain is very short, then the Camera Zoom going below Terrain shouldn't work, but Camera Zoom going above should still work. And if the Camera is higher than Terrain above the minimum limit, then Camera Zoom should work without restriction. Moreover, if Player quickly scrolls to go down to Terrain, there is a little possibility the script couldn't prevent stopping the Player doing this in time, so a Trigger works if Camera collides with the Terrain, thus Camera is returned to a minimum height level smoothly. These are what the below script handles.
Note: The bottom part of the script is your Mouse Scroll code if you are using Mouse Scroll in Zooming, and the rest of the script is to limit the camera going below Terrain. Please make sure to add Sphere Collider (with Trigger on) and Rigidbody (without gravity, freeze rotation X and Z from the constraints too) to camera.
Also I considered the Terrain has "Terrain" tag, change it if you use something else, but make sure your Terrain has a tag.
[Tooltip("The time to move Cam away from Terrain")]
public float smoothTime = 0.1f; //Make it 0.1f, 0.3f, 1f or any number according to your preference. This defines movement speed of cam if cam collides with terrain. Smaller number means quicker movement.
[Tooltip("The min permitted Height limit between Cam and Terrain")]
public float minCamTerrainHeight = 0.15f;
[Tooltip("Raycast height from the Cam to Terrain")]
public float terrainDetectionHeight = 2f;
public float zoomSpeed = 350f;
private Vector3 velocity = Vector3.zero;
private bool colliding = false;
void OnTriggerEnter (Collider other){
if (other.gameObject.CompareTag("Terrain"))
colliding = true;
}
void OnTriggerExit (Collider other){
if (other.gameObject.CompareTag("Terrain"))
colliding = false;
}
//If Camera collides with Terrain, move the camera smoothly above the terrain
if (colliding){
transform.localPosition = Vector3.SmoothDamp(transform.localPosition, new Vector3(0,minCamTerrainHeight,0), ref velocity, smoothTime);
}
//Check Distance between Terrain-Camera object
RaycastHit hit;
if(Physics.Raycast(transform.position, -transform.up, out hit, terrainDetectionHeight)) {
//If the camera is at a certain height above the Terrain, limit Mousescroll going down further but don't limit it going up:
if(hit.collider.tag=="Terrain"){
print("Camera is very close to Terrain.");
float moveDown = Input.GetAxis("Mouse ScrollWheel");
if (moveDown < 0) //if going up, not down. This part limits going down.
transform.Translate(new Vector3(0, moveDown) * Time.deltaTime * -zoomSpeed, 0);
}
}
else
//move the camera when you scroll. This happens if it is above the terrainDetectionHeight.
transform.Translate(new Vector3(0, Input.GetAxis("Mouse ScrollWheel")) * Time.deltaTime * -zoomSpeed, 0);
Your answer
Follow this Question
Related Questions
Can someone modify this for me? 0 Answers
Raycast doesn't collide as it should 1 Answer
Weird error with RayCasting (CS1502) 1 Answer
How can I change this script? 0 Answers
Raycast collision on camera see's only part of object 0 Answers