219 lines
6.7 KiB
C#
219 lines
6.7 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.InputSystem;
|
|
|
|
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;
|
|
[SerializeField]
|
|
private float aimSpeed = 50f;
|
|
|
|
[Header("References")]
|
|
[SerializeField]
|
|
private Transform gunPos;
|
|
[SerializeField]
|
|
private RectTransform canvasRect;
|
|
[SerializeField]
|
|
private RectTransform hitMarkerRect;
|
|
|
|
private PlayerInput playerInput;
|
|
|
|
private Vector3 hitPosLocal, aimDir, aimDirTarget;
|
|
private SpringJoint joint;
|
|
private LineRenderer lr;
|
|
RaycastHit hit;
|
|
private bool grappled = false, grappling = false, boosted = false, changingLength = false, isStunned = false;
|
|
float changingLengthDir = 0;
|
|
private Vector3 currGrappleEndPos;
|
|
|
|
#region private methods
|
|
void Start()
|
|
{
|
|
lr = gameObject.GetComponentInChildren<LineRenderer>();
|
|
lr.enabled = false;
|
|
hitMarkerRect.gameObject.SetActive(false);
|
|
playerInput = gameObject.GetComponent<PlayerInput>();
|
|
}
|
|
|
|
|
|
void Update()
|
|
{
|
|
if(isStunned){
|
|
return;
|
|
}
|
|
|
|
if(grappled){
|
|
DrawRope(Time.deltaTime);
|
|
|
|
if(boosted){
|
|
joint.maxDistance -= grappleBoostSpeed * Time.deltaTime;
|
|
}
|
|
if(changingLength){
|
|
ChangeGrappleLength(changingLengthDir * grappleExtensionSpeed * Time.deltaTime);
|
|
}
|
|
return;
|
|
}
|
|
|
|
Aim();
|
|
|
|
|
|
}
|
|
|
|
private void Aim(){
|
|
aimDir = Vector3.Lerp(aimDir, aimDirTarget, Time.deltaTime * aimSpeed);
|
|
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<Image>().color = Color.green;
|
|
if(grappling){
|
|
StartGrapple(hit);
|
|
}
|
|
}else{
|
|
hitMarkerRect.gameObject.GetComponent<Image>().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;
|
|
grappling = false;
|
|
|
|
//Display
|
|
hitMarkerRect.gameObject.SetActive(false);
|
|
|
|
// Rope phys
|
|
joint = gameObject.AddComponent<SpringJoint>();
|
|
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;
|
|
grappling = 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;
|
|
}
|
|
|
|
}
|
|
|
|
private void UnStun(){
|
|
isStunned = false;
|
|
Debug.Log("unstunned");
|
|
}
|
|
#endregion
|
|
|
|
#region public methods
|
|
|
|
public void Stun(float duration){
|
|
isStunned = true;
|
|
EndGrapple();
|
|
Debug.Log("Stunned");
|
|
Invoke("UnStun", duration);
|
|
}
|
|
#endregion
|
|
|
|
#region InputActions
|
|
public void Grapple(InputAction.CallbackContext context){
|
|
if(grappling && grappled)return;
|
|
if(context.performed){
|
|
grappling = true;
|
|
}else if(context.canceled){
|
|
EndGrapple();
|
|
}
|
|
}
|
|
|
|
public void BoostToAnchor(InputAction.CallbackContext context){
|
|
if(context.performed && grappled){
|
|
boosted = true;
|
|
}
|
|
}
|
|
|
|
public void AimInput(InputAction.CallbackContext context){
|
|
Vector2 value = context.ReadValue<Vector2>();
|
|
|
|
if(playerInput.currentControlScheme.Equals("Controller")){
|
|
if(value.magnitude == 0)return;
|
|
aimDirTarget = new Vector3(value.x, value.y, 0).normalized;
|
|
}else if(playerInput.currentControlScheme.Equals("KbMouse")){
|
|
var screenToWoldPoint = Camera.main.ScreenToWorldPoint(new Vector3(value.x, value.y, Mathf.Abs(Camera.main.transform.position.z)));
|
|
var aimDirTemp = (new Vector3(screenToWoldPoint.x-transform.position.x, screenToWoldPoint.y-transform.position.y, 0)).normalized;
|
|
if(aimDirTemp.magnitude == 0)return;
|
|
aimDirTarget = aimDirTemp;
|
|
}
|
|
}
|
|
|
|
public void RaiseLowerGrapple(InputAction.CallbackContext context){
|
|
if(context.started){
|
|
//IsMoving and value should be 1 or -1
|
|
changingLength = true;
|
|
changingLengthDir = -context.ReadValue<Vector2>().y;
|
|
}else if(context.canceled){
|
|
//is not moving and shoud be 0
|
|
changingLength = false;
|
|
changingLengthDir = context.ReadValue<Vector2>().y;
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
}
|