using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using MalbersAnimations.Events; using MalbersAnimations.Scriptables; using MalbersAnimations.Controller; using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Linq; using MalbersAnimations.Scriptables; using UnityEngine.Events; public class Grapple : MonoBehaviour { public MalbersAnimations.Controller.MAnimal Player; public GameObject Camera; public GameObject AttachmentPrefab; public GameObject ropeSegment; private GameObject attachment; private Vector3 attachedPoint; private Rigidbody attachedObject; private MalbersAnimations.Controller.MAnimal attachedCharacter; public float RopeSegmentLength; public bool isAttached; public float minDistance = 1.0f; public float maxDistance = 30.0f; public float pullForce = 20.0f; public float MaxPullForce = 25.0f; public float PushForce = 30.0f; public float pullAccel = 20.0f; public float playerWidth = 0.5f; public float playerHeight = 1.6f; public float playerHeightBuffer = 0.5f; public float breakChainTime = 0.5f; public float breakChainDistance = 0.5f; public float defaultRopeSegmentOrientation = 90.0f; private GameObject chain; private bool limitingPosition; private bool hasPullChainInputSequenceStarted; private bool inputPaused; private float pullChainInputTiming = 0.5f; private float inputPauseTiming = 1.0f; private float timer = 0.0f; private bool grappling; bool CheckInputDepressedThisFrame() { if (grappling) { grappling = false; return true; } return Input.GetAxis("Fire1") > 0.0f; } public virtual void StartGrapple() { grappling = true; } // Start is called before the first frame update void Start() { chain = new GameObject("Chain"); chain.AddComponent(); } // Update is called once per frame void Update() { timer += Time.deltaTime; if (inputPaused) { if (timer < inputPauseTiming) { return; } else { inputPaused = false; } } var cameraTransform = Camera.transform; if (attachment != null) { attachedPoint = attachment.transform.position; } if (Vector3.Distance(Player.transform.position, attachedPoint) > maxDistance) { //check if time limit has passed for being beyond distance limit without breaking } if (Vector3.Distance(Player.transform.position, attachedPoint) > maxDistance + breakChainDistance) { if (attachment != null) { GameObject.Destroy(attachment); var lineRenderer = chain.GetComponent(); lineRenderer.SetWidth(0, 0); } if (ropeSegment != null) { GameObject.Destroy(ropeSegment); } isAttached = false; return; } if (isAttached) { // limit the position of both sides of the chain to the length of the chain // // // // // if (Vector3.Distance(Player.transform.position, attachedPoint) > maxDistance) { var forceHeading = attachedPoint - cameraTransform.position; var forceDirection = forceHeading / forceHeading.magnitude; if (Player.GetComponent().velocity.x > MaxPullForce || Player.GetComponent().velocity.x < -MaxPullForce || Player.GetComponent().velocity.y > MaxPullForce || Player.GetComponent().velocity.y < -MaxPullForce) { Player.Force_Add(forceDirection, Vector3.Distance(Player.transform.position, attachedPoint), pullForce * 0.05f, false ); } if (attachedObject != null && attachedObject.velocity != null && attachedObject.velocity.x > MaxPullForce || attachedObject.velocity.x < -MaxPullForce || attachedObject.velocity.y > MaxPullForce || attachedObject.velocity.y < -MaxPullForce) { attachedObject.AddForce(-forceDirection * Vector3.Distance(Player.transform.position, attachedPoint) * pullForce * 0.05f); } if (attachedCharacter != null && attachedCharacter.GetComponent().velocity.x > MaxPullForce || attachedCharacter.GetComponentInParent().velocity.x < -MaxPullForce || attachedCharacter.GetComponentInParent().velocity.y > MaxPullForce || attachedCharacter.GetComponentInParent().velocity.y < -MaxPullForce) { attachedCharacter.Force_Add(-forceDirection, Vector3.Distance(Player.transform.position, attachedPoint), pullForce * 0.05f, false ); } limitingPosition = true; } if (limitingPosition && Vector3.Distance(Player.transform.position, attachedPoint) < maxDistance) { Debug.Log("Removing force"); Player.Force_Remove(); if (attachedObject != null) { attachedObject.velocity = new Vector3(0.0f, 0.0f, 0.0f); } if (attachedCharacter != null) { attachedCharacter.Force_Remove(); } limitingPosition = false; } var lineRenderer = chain.GetComponent(); lineRenderer.SetColors (Color.blue, Color.blue); lineRenderer.material = new Material(Shader.Find("Legacy Shaders/Particles/Additive")); lineRenderer.SetWidth(1f, 1f); lineRenderer.SetPosition(0, Player.transform.position); lineRenderer.SetPosition(1, attachedPoint); // Position if (ropeSegment != null) { ropeSegment.transform.position = (attachedPoint + cameraTransform.position) / 2.0f; // Rotation var heading = attachedPoint - cameraTransform.position; var direction = heading / heading.magnitude; ropeSegment.transform.rotation = new Quaternion(direction.x, direction.y, direction.z + defaultRopeSegmentOrientation, 0); // Scale var distance = Vector3.Distance(attachedPoint, Player.transform.position); ropeSegment.transform.localScale = new Vector3(0.1f, distance / 2, 0.1f); } if (hasPullChainInputSequenceStarted && timer > pullChainInputTiming) { Debug.Log("Detaching"); isAttached = false; inputPaused = true; timer = 0.0f; hasPullChainInputSequenceStarted = false; attachedObject = null; attachedCharacter = null; attachment.transform.parent = null; GameObject.Destroy(ropeSegment); GameObject.Destroy(attachment); return; lineRenderer.SetWidth(0, 0); } else if (hasPullChainInputSequenceStarted && CheckInputDepressedThisFrame()) { Debug.Log("Pulling"); // This is the preferred way of calculating direction between two Vectors // other ways might cause performance issues // See here: https://docs.unity3d.com/2018.3/Documentation/Manual/DirectionDistanceFromOneObjectToAnother.html // TODO: look into syntax/performance impact for (vector.position - vector.position).normalized var forceHeading = attachedPoint - cameraTransform.position; var forceDirection = forceHeading / forceHeading.magnitude; var applyToSelf = true; if (attachedObject != null) { attachedObject.AddForce(-forceDirection * pullForce); applyToSelf = false; } if (attachedCharacter != null) { attachedCharacter.Force_Add(-forceDirection, pullForce, pullAccel, false ); applyToSelf = false; } if (applyToSelf) { Player.Force_Add(forceDirection, pullForce, pullAccel, false ); } attachedPoint = new Vector3(0, 0, 0); inputPaused = true; timer = 0.0f; hasPullChainInputSequenceStarted = false; } else if (!hasPullChainInputSequenceStarted && !CheckInputDepressedThisFrame()) { Debug.Log("Starting Dettachment"); hasPullChainInputSequenceStarted = true; timer = 0.0f; } } else { if (attachment != null) { if (attachment.GetComponent().CollisionStuck) { // attachment.GetComponent().constraints = RigidbodyConstraints.FreezeAll; inputPaused = false; isAttached = true; } else { // attachment.GetComponent().constraints = RigidbodyConstraints.None; } if (Vector3.Distance(Player.transform.position, transform.position) > Player.GetComponent().maxDistance) { timer = 0.0f; GameObject.Destroy(attachment); inputPaused = false; isAttached = false; return; } } var lineRenderer = chain.GetComponent(); if (CheckInputDepressedThisFrame()) { var raycastStart = cameraTransform.position + transform.forward * minDistance; if (Physics.Raycast(raycastStart, cameraTransform.forward, out RaycastHit raycastHit)) { if (Vector3.Distance(Player.transform.position, raycastHit.point) < maxDistance) { Debug.Log("Attaching"); attachedPoint = raycastHit.point; isAttached = true; inputPaused = true; timer = 0.0f; hasPullChainInputSequenceStarted = false; if (raycastHit.transform != null && raycastHit.transform.gameObject != null) { if (raycastHit.transform.gameObject.GetComponent() != null) { attachedObject = raycastHit.transform.gameObject.GetComponent(); } else if (raycastHit.transform.gameObject.GetComponentInChildren() != null) { attachedObject = raycastHit.transform.gameObject.GetComponentInChildren(); } if (raycastHit.transform.gameObject.GetComponent() != null) { attachedCharacter = raycastHit.transform.gameObject.GetComponent(); } if (raycastHit.transform.gameObject.GetComponentInChildren() != null) { attachedCharacter = raycastHit.transform.gameObject.GetComponentInChildren(); } } if (attachment == null) { attachment = Instantiate(AttachmentPrefab); } timer = 0.0f; inputPaused = true; hasPullChainInputSequenceStarted = false; attachment.transform.localScale = new Vector3(6.25f, 6.25f, 18.75f); var heading = attachedPoint - cameraTransform.position; var direction = heading / heading.magnitude; attachment.transform.position = Player.transform.position + Quaternion.AngleAxis(direction.x, Vector3.right) * transform.forward * 1; // attachment.transform.position = new Vector3(Player.transform.position.x, Player.transform.position.y + playerHeight + playerHeightBuffer, Player.transform.position.z + playerWidth * 2); attachment.GetComponent().AddForce(direction * PushForce); // attachment.GetComponent().AddForce(direction * PushForce, ForceMode.Impulse); attachment.transform.position = raycastHit.point; attachment.transform.rotation = (Quaternion.Euler(cameraTransform.rotation.x, gameObject.transform.rotation.y, 0)); if (attachedObject != null) { attachment.transform.parent = attachedObject.transform; } if (attachedCharacter != null) { attachment.transform.parent = attachedCharacter.transform; } } else { Debug.Log("Missing / Too Far"); } } else { Debug.Log("Missing"); inputPaused = true; timer = 0.0f; hasPullChainInputSequenceStarted = false; } } } } }