View difference between Paste ID: 4JAqk62i and cmRstG6c
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