- ProtectCameraFromWallClip.cs
- Scripts /
- Cameras /
- Standard Assets /
- Assets /
- project /
1 using System;
2 using System.Collections;
3 using UnityEngine;
4
5 namespace UnityStandardAssets.Cameras
6 {
7 public class ProtectCameraFromWallClip : MonoBehaviour
8 {
9 public float clipMoveTime = 0.05f; // time taken to move when avoiding cliping (low value = fast, which it should be)
10 public float returnTime = 0.4f; // time taken to move back towards desired position, when not clipping (typically should be a higher value than clipMoveTime)
11 public float sphereCastRadius = 0.1f; // the radius of the sphere used to test for object between camera and target
12 public bool visualiseInEditor; // toggle for visualising the algorithm through lines for the raycast in the editor
13 public float closestDistance = 0.5f; // the closest distance the camera can be from the target
14 public bool protecting { get; private set; } // used for determining if there is an object between the target and the camera
15 public string dontClipTag = "Player"; // don't clip against objects with this tag (useful for not clipping against the targeted object)
16
17 private Transform m_Cam; // the transform of the camera
18 private Transform m_Pivot; // the point at which the camera pivots around
19 private float m_OriginalDist; // the original distance to the camera before any modification are made
20 private float m_MoveVelocity; // the velocity at which the camera moved
21 private float m_CurrentDist; // the current distance from the camera to the target
22 private Ray m_Ray; // the ray used in the lateupdate for casting between the camera and the target
23 private RaycastHit[] m_Hits; // the hits between the camera and the target
24 private RayHitComparer m_RayHitComparer; // variable to compare raycast hit distances
25
26
27 private void Start()
28 {
29 // find the camera in the object hierarchy
30 m_Cam = GetComponentInChildren<Camera>().transform;
31 m_Pivot = m_Cam.parent;
32 m_OriginalDist = m_Cam.localPosition.magnitude;
33 m_CurrentDist = m_OriginalDist;
34
35 // create a new RayHitComparer
36 m_RayHitComparer = new RayHitComparer();
37 }
38
39
40 private void LateUpdate()
41 {
42 // initially set the target distance
43 float targetDist = m_OriginalDist;
44
45 m_Ray.origin = m_Pivot.position + m_Pivot.forward*sphereCastRadius;
46 m_Ray.direction = -m_Pivot.forward;
47
48 // initial check to see if start of spherecast intersects anything
49 var cols = Physics.OverlapSphere(m_Ray.origin, sphereCastRadius);
50
51 bool initialIntersect = false;
52 bool hitSomething = false;
53
54 // loop through all the collisions to check if something we care about
55 for (int i = 0; i < cols.Length; i++)
56 {
57 if ((!cols[i].isTrigger) &&
58 !(cols[i].attachedRigidbody != null && cols[i].attachedRigidbody.CompareTag(dontClipTag)))
59 {
60 initialIntersect = true;
61 break;
62 }
63 }
64
65 // if there is a collision
66 if (initialIntersect)
67 {
68 m_Ray.origin += m_Pivot.forward*sphereCastRadius;
69
70 // do a raycast and gather all the intersections
71 m_Hits = Physics.RaycastAll(m_Ray, m_OriginalDist - sphereCastRadius);
72 }
73 else
74 {
75 // if there was no collision do a sphere cast to see if there were any other collisions
76 m_Hits = Physics.SphereCastAll(m_Ray, sphereCastRadius, m_OriginalDist + sphereCastRadius);
77 }
78
79 // sort the collisions by distance
80 Array.Sort(m_Hits, m_RayHitComparer);
81
82 // set the variable used for storing the closest to be as far as possible
83 float nearest = Mathf.Infinity;
84
85 // loop through all the collisions
86 for (int i = 0; i < m_Hits.Length; i++)
87 {
88 // only deal with the collision if it was closer than the previous one, not a trigger, and not attached to a rigidbody tagged with the dontClipTag
89 if (m_Hits[i].distance < nearest && (!m_Hits[i].collider.isTrigger) &&
90 !(m_Hits[i].collider.attachedRigidbody != null &&
91 m_Hits[i].collider.attachedRigidbody.CompareTag(dontClipTag)))
92 {
93 // change the nearest collision to latest
94 nearest = m_Hits[i].distance;
95 targetDist = -m_Pivot.InverseTransformPoint(m_Hits[i].point).z;
96 hitSomething = true;
97 }
98 }
99
100 // visualise the cam clip effect in the editor
101 if (hitSomething)
102 {
103 Debug.DrawRay(m_Ray.origin, -m_Pivot.forward*(targetDist + sphereCastRadius), Color.red);
104 }
105
106 // hit something so move the camera to a better position
107 protecting = hitSomething;
108 m_CurrentDist = Mathf.SmoothDamp(m_CurrentDist, targetDist, ref m_MoveVelocity,
109 m_CurrentDist > targetDist ? clipMoveTime : returnTime);
110 m_CurrentDist = Mathf.Clamp(m_CurrentDist, closestDistance, m_OriginalDist);
111 m_Cam.localPosition = -Vector3.forward*m_CurrentDist;
112 }
113
114
115 // comparer for check distances in ray cast hits
116 public class RayHitComparer : IComparer
117 {
118 public int Compare(object x, object y)
119 {
120 return ((RaycastHit) x).distance.CompareTo(((RaycastHit) y).distance);
121 }
122 }
123 }
124 }
2 using System.Collections;
3 using UnityEngine;
4
5 namespace UnityStandardAssets.Cameras
6 {
7 public class ProtectCameraFromWallClip : MonoBehaviour
8 {
9 public float clipMoveTime = 0.05f; // time taken to move when avoiding cliping (low value = fast, which it should be)
10 public float returnTime = 0.4f; // time taken to move back towards desired position, when not clipping (typically should be a higher value than clipMoveTime)
11 public float sphereCastRadius = 0.1f; // the radius of the sphere used to test for object between camera and target
12 public bool visualiseInEditor; // toggle for visualising the algorithm through lines for the raycast in the editor
13 public float closestDistance = 0.5f; // the closest distance the camera can be from the target
14 public bool protecting { get; private set; } // used for determining if there is an object between the target and the camera
15 public string dontClipTag = "Player"; // don't clip against objects with this tag (useful for not clipping against the targeted object)
16
17 private Transform m_Cam; // the transform of the camera
18 private Transform m_Pivot; // the point at which the camera pivots around
19 private float m_OriginalDist; // the original distance to the camera before any modification are made
20 private float m_MoveVelocity; // the velocity at which the camera moved
21 private float m_CurrentDist; // the current distance from the camera to the target
22 private Ray m_Ray; // the ray used in the lateupdate for casting between the camera and the target
23 private RaycastHit[] m_Hits; // the hits between the camera and the target
24 private RayHitComparer m_RayHitComparer; // variable to compare raycast hit distances
25
26
27 private void Start()
28 {
29 // find the camera in the object hierarchy
30 m_Cam = GetComponentInChildren<Camera>().transform;
31 m_Pivot = m_Cam.parent;
32 m_OriginalDist = m_Cam.localPosition.magnitude;
33 m_CurrentDist = m_OriginalDist;
34
35 // create a new RayHitComparer
36 m_RayHitComparer = new RayHitComparer();
37 }
38
39
40 private void LateUpdate()
41 {
42 // initially set the target distance
43 float targetDist = m_OriginalDist;
44
45 m_Ray.origin = m_Pivot.position + m_Pivot.forward*sphereCastRadius;
46 m_Ray.direction = -m_Pivot.forward;
47
48 // initial check to see if start of spherecast intersects anything
49 var cols = Physics.OverlapSphere(m_Ray.origin, sphereCastRadius);
50
51 bool initialIntersect = false;
52 bool hitSomething = false;
53
54 // loop through all the collisions to check if something we care about
55 for (int i = 0; i < cols.Length; i++)
56 {
57 if ((!cols[i].isTrigger) &&
58 !(cols[i].attachedRigidbody != null && cols[i].attachedRigidbody.CompareTag(dontClipTag)))
59 {
60 initialIntersect = true;
61 break;
62 }
63 }
64
65 // if there is a collision
66 if (initialIntersect)
67 {
68 m_Ray.origin += m_Pivot.forward*sphereCastRadius;
69
70 // do a raycast and gather all the intersections
71 m_Hits = Physics.RaycastAll(m_Ray, m_OriginalDist - sphereCastRadius);
72 }
73 else
74 {
75 // if there was no collision do a sphere cast to see if there were any other collisions
76 m_Hits = Physics.SphereCastAll(m_Ray, sphereCastRadius, m_OriginalDist + sphereCastRadius);
77 }
78
79 // sort the collisions by distance
80 Array.Sort(m_Hits, m_RayHitComparer);
81
82 // set the variable used for storing the closest to be as far as possible
83 float nearest = Mathf.Infinity;
84
85 // loop through all the collisions
86 for (int i = 0; i < m_Hits.Length; i++)
87 {
88 // only deal with the collision if it was closer than the previous one, not a trigger, and not attached to a rigidbody tagged with the dontClipTag
89 if (m_Hits[i].distance < nearest && (!m_Hits[i].collider.isTrigger) &&
90 !(m_Hits[i].collider.attachedRigidbody != null &&
91 m_Hits[i].collider.attachedRigidbody.CompareTag(dontClipTag)))
92 {
93 // change the nearest collision to latest
94 nearest = m_Hits[i].distance;
95 targetDist = -m_Pivot.InverseTransformPoint(m_Hits[i].point).z;
96 hitSomething = true;
97 }
98 }
99
100 // visualise the cam clip effect in the editor
101 if (hitSomething)
102 {
103 Debug.DrawRay(m_Ray.origin, -m_Pivot.forward*(targetDist + sphereCastRadius), Color.red);
104 }
105
106 // hit something so move the camera to a better position
107 protecting = hitSomething;
108 m_CurrentDist = Mathf.SmoothDamp(m_CurrentDist, targetDist, ref m_MoveVelocity,
109 m_CurrentDist > targetDist ? clipMoveTime : returnTime);
110 m_CurrentDist = Mathf.Clamp(m_CurrentDist, closestDistance, m_OriginalDist);
111 m_Cam.localPosition = -Vector3.forward*m_CurrentDist;
112 }
113
114
115 // comparer for check distances in ray cast hits
116 public class RayHitComparer : IComparer
117 {
118 public int Compare(object x, object y)
119 {
120 return ((RaycastHit) x).distance.CompareTo(((RaycastHit) y).distance);
121 }
122 }
123 }
124 }