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 |