SHOW:
|
|
- or go back to the newest paste.
1 | using UnityEngine; | |
2 | using System.Collections; | |
3 | using UnityEngine.Events; | |
4 | ||
5 | public class LedgeDetector : MonoBehaviour | |
6 | { | |
7 | private float distancePlayerToLedge; | |
8 | ||
9 | private Vector3 ledgePos; | |
10 | private Vector3 ledgeNormal; | |
11 | ||
12 | [SerializeField] | |
13 | private LayerMask hitMask = 1; | |
14 | ||
15 | [SerializeField] | |
16 | float grabbingDistance = 0.3f; | |
17 | ||
18 | private Transform playerFace; | |
19 | private Transform playerSpine; | |
20 | ||
21 | private bool Inrange = false; | |
22 | private bool hanging = false; | |
23 | GameObject ledgeDetector; | |
24 | GameObject ledgePosIndicator; | |
25 | ||
26 | private Vector3 raycastFloorPos; | |
27 | ||
28 | private Vector3 CombinedRaycastNormal; | |
29 | ||
30 | RaycastHit hit, hitDown; | |
31 | Animator anim; | |
32 | CharacterMovement charM; | |
33 | ||
34 | Vector3 wallhitPoint; | |
35 | Vector3 wallNormal; | |
36 | // Use this for initialization | |
37 | void Start() | |
38 | { | |
39 | charM = transform.GetComponent<CharacterMovement>(); | |
40 | anim = GetComponentInChildren<Animator>(); | |
41 | playerFace = anim.GetBoneTransform(HumanBodyBones.Head); // these are from the humanoid rig | |
42 | playerSpine = anim.GetBoneTransform(HumanBodyBones.Spine); | |
43 | SpawnLedgePosIndicator(); | |
44 | SpawnLedgeDetector(); | |
45 | } | |
46 | ||
47 | // Update is called once per frame | |
48 | void Update() | |
49 | { | |
50 | // draw ray to find walls, from the player chest | |
51 | Debug.DrawRay(playerSpine.position, transform.forward, Color.red); | |
52 | if (Physics.Raycast(playerSpine.position, transform.forward, out hit, 1, hitMask)) | |
53 | { | |
54 | Debug.DrawRay(playerSpine.position, transform.forward, Color.green); | |
55 | wallhitPoint = hit.point; | |
56 | wallNormal = hit.normal; | |
57 | Inrange = true; | |
58 | charM.WallNormal = hit.normal; | |
59 | } | |
60 | else | |
61 | { | |
62 | Inrange = false; | |
63 | // drop down if there is nothing in front of us and we are hanging | |
64 | if (hanging) | |
65 | { | |
66 | StopHanging(); | |
67 | } | |
68 | } | |
69 | ||
70 | // if in range of wall, shoot ray downward from the ledge detector | |
71 | if (Inrange) | |
72 | { | |
73 | ||
74 | Vector3 down = -ledgeDetector.transform.up; | |
75 | Debug.DrawRay(ledgeDetector.transform.position, down * 4f, Color.yellow); | |
76 | if (Physics.Raycast(ledgeDetector.transform.position, down, out hitDown, 4f, hitMask)) | |
77 | { | |
78 | Debug.DrawRay(ledgeDetector.transform.position, down * 4f, Color.cyan); | |
79 | ledgeNormal = hitDown.normal; | |
80 | ledgePos = new Vector3(wallhitPoint.x, hitDown.point.y, wallhitPoint.z); | |
81 | } | |
82 | else | |
83 | { | |
84 | //reset the position | |
85 | if (ledgePos != Vector3.zero) | |
86 | { | |
87 | ledgePos = Vector3.zero; | |
88 | } | |
89 | ||
90 | } | |
91 | // set the ledge indicator block | |
92 | ledgePosIndicator.SetActive(true); | |
93 | ledgePosIndicator.transform.position = ledgePos; | |
94 | ||
95 | // check distance from face to the ledge | |
96 | distancePlayerToLedge = Vector3.Distance(ledgePos, playerFace.transform.position); | |
97 | //, if its close enough, and the surface is flat on the ledge normal | |
98 | if (distancePlayerToLedge < grabbingDistance && ledgeNormal.y > 0.9f && ledgeNormal.y < 1.1f) | |
99 | { | |
100 | // if not already hanging, grab | |
101 | if (!hanging) | |
102 | { | |
103 | hanging = true; | |
104 | charM.GrabLedgePos(ledgePos); | |
105 | } | |
106 | } | |
107 | } | |
108 | ||
109 | if (hanging) | |
110 | { | |
111 | // check for places to climbup when hanging | |
112 | FindSuitablePlaceForClimbup(); | |
113 | } | |
114 | } | |
115 | ||
116 | Vector3 FindSuitablePlaceForClimbup() | |
117 | { | |
118 | float raycastWidth = 0.2f; | |
119 | // check floor on all raycasts | |
120 | // average only for those who are not returning zero | |
121 | int floorAverage = 1; | |
122 | CombinedRaycastNormal = FloorRaycasts(0, 0, 3f); | |
123 | floorAverage += (GetFloorAverage(raycastWidth, 0) + GetFloorAverage(-raycastWidth, 0) + GetFloorAverage(0, -raycastWidth) + GetFloorAverage(0, raycastWidth)); | |
124 | // if all 5 raycast hit something, and the surface is flat, there is space to climb up. | |
125 | Vector3 AverageNormal = CombinedRaycastNormal / floorAverage; | |
126 | if (floorAverage == 5 && AverageNormal.y > 0.9f && AverageNormal.y < 1.1f && distancePlayerToLedge < grabbingDistance + 0.4f) | |
127 | { | |
128 | charM.safeForClimbUp = true; | |
129 | // update the ledgeposition so it's in the correct place when moving | |
130 | charM.LedgePos = ledgePos; | |
131 | ledgePosIndicator.transform.position = ledgePos; | |
132 | } | |
133 | else | |
134 | { | |
135 | charM.safeForClimbUp = false; | |
136 | } | |
137 | ||
138 | return CombinedRaycastNormal / floorAverage; | |
139 | } | |
140 | ||
141 | // only add to average floor position if its not Vector3.zero | |
142 | int GetFloorAverage(float offsetx, float offsetz) | |
143 | { | |
144 | ||
145 | if (FloorRaycasts(offsetx, offsetz, 2f) != Vector3.zero) | |
146 | { | |
147 | CombinedRaycastNormal += FloorRaycasts(offsetx, offsetz, 3f); | |
148 | return 1; | |
149 | } | |
150 | else { return 0; } | |
151 | } | |
152 | ||
153 | Vector3 FloorRaycasts(float offsetx, float offsetz, float raycastLength) | |
154 | { | |
155 | // raycast from multiple points | |
156 | raycastFloorPos = ledgeDetector.transform.TransformPoint(0 + offsetx, -2f, 0 + offsetz); | |
157 | ||
158 | Debug.DrawRay(raycastFloorPos, Vector3.down * raycastLength, Color.red); | |
159 | if (Physics.Raycast(raycastFloorPos, Vector3.down, out hit, raycastLength, hitMask, QueryTriggerInteraction.Collide)) | |
160 | { | |
161 | if(hit.normal.y > 0.9f && hit.normal.y < 1.1f) | |
162 | Debug.DrawRay(raycastFloorPos, Vector3.down * raycastLength, Color.green); | |
163 | return hit.normal; | |
164 | } | |
165 | else return Vector3.zero; | |
166 | } | |
167 | ||
168 | void StopHanging() | |
169 | { | |
170 | // only drop when not currently climbing up or we get stuck | |
171 | if (hanging && !anim.GetCurrentAnimatorStateInfo(0).IsName("Climbup")) | |
172 | { | |
173 | hanging = false; | |
174 | charM.CancelHanging(); | |
175 | } | |
176 | } | |
177 | ||
178 | void SpawnLedgePosIndicator() | |
179 | { | |
180 | ledgePosIndicator = GameObject.CreatePrimitive(PrimitiveType.Cube); | |
181 | ledgePosIndicator.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f); | |
182 | ledgePosIndicator.GetComponent<Collider>().enabled = false; | |
183 | } | |
184 | ||
185 | void SpawnLedgeDetector() | |
186 | { | |
187 | ledgeDetector = GameObject.CreatePrimitive(PrimitiveType.Sphere); | |
188 | ledgeDetector.transform.SetParent(transform); | |
189 | ledgeDetector.transform.localPosition = new Vector3(0, 4.2f, 0.5f); | |
190 | ledgeDetector.GetComponent<Collider>().enabled = false; | |
191 | } | |
192 | ||
193 | } | |
194 |