using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class GrappleHook : MonoBehaviour { [Header("Grapple settings")] [SerializeField] private float maxGrappleDist = 200; [SerializeField] private float grappleExtensionSpeed = 10; [SerializeField] private float grappleStrength = 4.5f * 5f; [SerializeField] private float grappleDamper = 7f; [SerializeField] private float grappleBoostSpeed = 50f; [SerializeField] private float grappleDrawingSpeed = 20; [SerializeField] private LayerMask grappleableLayer; [Header("References")] [SerializeField] private Transform gunPos; [SerializeField] private RectTransform canvasRect; [SerializeField] private RectTransform hitMarkerRect; private Vector3 hitPosLocal; private SpringJoint joint; private LineRenderer lr; RaycastHit hit; private bool grappled = false, boosted = false; private Vector3 currGrappleEndPos; void Start() { lr = gameObject.GetComponentInChildren(); lr.enabled = false; hitMarkerRect.gameObject.SetActive(false); } void Update() { if(Input.GetMouseButtonUp(0)){//TODO Change to correct input system EndGrapple(); } if(grappled){ DrawRope(Time.deltaTime); if(Input.GetMouseButtonDown(1)){ boosted = true; } if(boosted){ joint.maxDistance -= grappleBoostSpeed * Time.deltaTime; } // TODO extend and retract rope if(Input.GetKey(KeyCode.W)){ ChangeGrappleLength(-grappleExtensionSpeed * Time.deltaTime); }else if(Input.GetKey(KeyCode.S)){ ChangeGrappleLength(grappleExtensionSpeed * Time.deltaTime); } return; } Aim(); } private void Aim(){ Vector3 mousePos; mousePos = Input.mousePosition; mousePos.z = Mathf.Abs(Camera.main.transform.position.z); mousePos = Camera.main.ScreenToWorldPoint(mousePos); Vector3 aimDir = (mousePos - gameObject.transform.position).normalized; if(!hitMarkerRect.gameObject.activeSelf)hitMarkerRect.gameObject.SetActive(true); hitMarkerRect.anchoredPosition = WorldToUI(gameObject.transform.position + aimDir * maxGrappleDist); if(Physics.Raycast(gameObject.transform.position, aimDir, out hit, maxGrappleDist, grappleableLayer)){ hitMarkerRect.anchoredPosition = WorldToUI(hit.point); hitMarkerRect.gameObject.GetComponent().color = Color.green; if(Input.GetMouseButtonDown(0)){ StartGrapple(hit); } }else{ hitMarkerRect.gameObject.GetComponent().color = Color.red; } } private void DrawRope(float deltaTime){ // TODO animate a wiggle on the rope if(!grappled)return; lr.SetPosition(0, gunPos.position); Vector3 endPoint; if(hit.rigidbody != null){ endPoint = hit.transform.TransformPoint(hitPosLocal); }else{ endPoint = hit.point; } currGrappleEndPos = Vector3.Lerp(currGrappleEndPos, endPoint, deltaTime * grappleDrawingSpeed); lr.SetPosition(1, currGrappleEndPos); if(!lr.enabled)lr.enabled = true; } private void StartGrapple(RaycastHit hit){ grappled = true; //Display hitMarkerRect.gameObject.SetActive(false); // Rope phys joint = gameObject.AddComponent(); joint.anchor = transform.InverseTransformPoint(gunPos.position); joint.autoConfigureConnectedAnchor = false; joint.maxDistance = hit.distance * 0.9f; if(hit.rigidbody != null){ Rigidbody hitRb = hit.rigidbody; joint.connectedBody = hitRb; joint.connectedAnchor = hit.transform.InverseTransformPoint(hit.point); hitPosLocal = hit.transform.InverseTransformPoint(hit.point); }else{ joint.connectedAnchor = hit.point; } joint.spring = grappleStrength; joint.damper = grappleDamper; joint.massScale = 4.5f; currGrappleEndPos = transform.position; } private void EndGrapple(){ grappled = false; lr.enabled = false; boosted = false; Destroy(joint); } private Vector2 WorldToUI(Vector3 point){ Vector2 viewPortPos = Camera.main.WorldToViewportPoint(point); Vector2 pointScreenPos = new Vector2(((viewPortPos.x*canvasRect.sizeDelta.x)-(canvasRect.sizeDelta.x*0.5f)), ((viewPortPos.y*canvasRect.sizeDelta.y)-(canvasRect.sizeDelta.y*0.5f))); return pointScreenPos; } private void ChangeGrappleLength(float value){ if(joint != null) joint.maxDistance += value; } }