Untitled
unknown
csharp
3 years ago
23 kB
8
Indexable
using System.Collections.Generic; //using System.Diagnostics; using System.Linq; using Unity.Burst.CompilerServices; using Unity.VisualScripting; //using System.Numerics; using UnityEngine; using UnityEngine.SocialPlatforms; using UnityEngine.UIElements; using static UnityEngine.UIElements.UxmlAttributeDescription; public class Cast_v2 : MonoBehaviour { public float PullForce = 5f; public int Shots = 2; public float ClimbSpeed = 1f; //how fast you can move toward grapple point public float SlideSpeed = 2f; // how fast you can rappel away from grapple point public float Range = 12f; //grapple range public float shotspeed = 10f; //cast speed public float retractspeed = 5f; //retract speed public float WiggleForce = 1f; //how much you can move while hanging private float tshot; //timer for shot private float tret; //timer for retraction public int ShotsLeft; public float ropelength = 0; private Vector2 MousePosonClick; private LineRenderer lr; private Vector2 CharPos; public Rigidbody2D rb; private Rigidbody2D GrappleBody; private EdgeCollider2D GrappleObjCollider; public Movement mvmt; public DistanceJoint2D Grapple; public bool WillGrapple; public Vector2 RopeGrapplePoint; private Vector2[] GrappleColliderPoints; private Vector2 GrabPointinWorld; private RaycastHit2D Updatehit; private RaycastHit2D hit; //public LayerMask IgnoreLayer = 7; private bool clicked = false; private bool clicking = false; private bool rclicked = false; //want to eventually make it so rclick is an item grabber private bool rclicking = false; private bool ClickedCheck; private bool ClickingCheck; private float angle_storage; public int RangeMode = 0; //0 -- normal range; 1 -- extended range private Vector2 GrabPointinLocal; private Dictionary<int, Vector2> WrappingPoints = new(); private Dictionary<int, Rigidbody2D> WrappingBodies = new(); private Dictionary<int, int> WrappingAngleLookup = new(); public bool ReadytoRetract; Vector2 dir = Vector2.zero; private bool prevmotorstate; private bool firstmotorstate; //private bool FreshlyWrapped = false; // Start is called before the first frame update void Start() { Grapple = GetComponent<DistanceJoint2D>(); Grapple.enabled = false; ShotsLeft = Shots; lr = GetComponent<LineRenderer>(); rb = GetComponent<Rigidbody2D>(); mvmt = GetComponent<Movement>(); } // Update is called once per frame void Update() { if (rb.velocity.magnitude >= 25f && RangeMode == 0) //increase range if moving fast { Range *= 1.1f; RangeMode = 1; } if (rb.velocity.magnitude < 25f && RangeMode == 1) // return to normal range once slowed down { Range /= 1.1f; RangeMode = 0; } if (clicked) { return; } else { clicked = Input.GetMouseButtonDown(0); } if (rclicked) { return; } else { rclicked = Input.GetMouseButtonDown(1); } clicking = Input.GetMouseButton(0); rclicking = Input.GetMouseButton(1); } void FixedUpdate() { Vector2 aim = Input.mousePosition; Vector2 target = Camera.main.ScreenToWorldPoint(aim); CharPos = rb.position; dir = -(CharPos - target).normalized; //direction from player to target //Check and initiate grapple if (clicked || rclicked) { MousePosonClick = target; if (clicked) { IntitialCastCheck(); clicked = false; if (hit.rigidbody.GetComponent<SliderJoint2D>() != null)// shut off elevator motor so player can pull it down { var slider = hit.rigidbody.GetComponent<SliderJoint2D>(); if (slider.limitState == JointLimitState2D.UpperLimit) { prevmotorstate = slider.useMotor; firstmotorstate = prevmotorstate; slider.useMotor = false; //???????????????????????????? wanna make it so elevators can lift us while grappling to them, but can still be pulled down by grappling // maybe use a spring joint } } } else if (rclicked) { tshot = 0; tret = 0; rclicked = false; } } //if not going to grapple, still run the shooting animation if (!WillGrapple && ReadytoRetract) { lr.SetPosition(1, CharPos); var shottime = Range / shotspeed; Vector3 End = CharPos - Range * (CharPos - MousePosonClick).normalized; if (tshot < shottime) { Vector3 newpos; newpos = Vector3.Lerp(CharPos, End, tshot / shottime); lr.SetPosition(0, newpos); tshot += Time.deltaTime; } if (tshot >= shottime) { Retract(End); } } //update linerenderer, movement/swinging, wrapping if (clicking && WillGrapple && WrappingBodies.Count > 0) { if (hit.rigidbody.GetComponent<TriggerLift>() != null) //deal with elevator trigger thats controller rotating thing { var slider = hit.rigidbody.GetComponent<SliderJoint2D>(); var trigged = hit.rigidbody.GetComponent<TriggerLift>().isTrigged; if (trigged) { prevmotorstate = false; } else { prevmotorstate = firstmotorstate; } } GrabPointinLocal = WrappingPoints[WrappingPoints.Count - 1]; //grapple point in local coords -- this remains constant as object moves GrabPointinWorld = WrappingBodies[WrappingBodies.Count - 1].transform.TransformPoint(GrabPointinLocal); //get new grapple point in world coords -- this changes each frame ropelength = 0; RopeUpdater(); GrappleMove(); } //un-hook and retract rope if (!clicking && WillGrapple && ReadytoRetract) { if (hit.rigidbody.GetComponent<SliderJoint2D>() != null)//return elevator to its initial stae { var slider = hit.rigidbody.GetComponent<SliderJoint2D>(); slider.useMotor = prevmotorstate; } Retract(WrappingBodies[WrappingBodies.Count - 1].transform.TransformPoint(WrappingPoints[WrappingPoints.Count - 1])); } } void OnCollisionExit2D(Collision2D collision) //mark as un-grounded upon leaving ground { if (collision.gameObject.CompareTag("Ground")) { ShotsLeft = Shots; //reset shots } } void InitialGrabCheck() { //will need to use slider joints instead of the distance joint tshot = 0; tret = 0; var mask = ~(1 << 7 | 1 << 2); hit = Physics2D.CircleCast(CharPos, 0.1f, dir, Range, mask); //raycast from character to target lr.positionCount = 2; lr.SetPosition(1, CharPos); //will stay at characer lr.SetPosition(0, CharPos);// will eventually go to grapple point if (hit.collider != null) //if the raycast hits, initiate grapple { GrappleObjCollider = hit.collider as EdgeCollider2D; //get the target's collider //GrappleObjCollider = hit.collider as hit.collider.GetType(); //get the target's collider WrappingBodies.Add(0, hit.rigidbody); //get targets rigidbody GrabPointinLocal = WrappingBodies[0].transform.InverseTransformPoint(hit.point); //Get the hit-point in the grapple body's ref frame. This will make //it easy to get connect to moving bodies //1) move to bodies frame //2) body moves in world frame, doesnt move in its own frame //3) move back to world frame to get the new location of the hit point // on the body (for linerenderer) //(with GrappleBody, anchor point is in terms of local coords) WrappingPoints.Add(0, GrabPointinLocal); WrappingAngleLookup.Add(0, 0); Grapple.connectedBody = WrappingBodies[0]; //set connected body to grapple rigid body Grapple.connectedAnchor = WrappingPoints[0]; //set grapple point to hit point Grapple.distance = hit.distance; //set grapple distance WillGrapple = true; Grapple.enabled = true; } else if (hit.collider == null)// if raycast doesnt hit anything, dont anchor { WillGrapple = false; } ReadytoRetract = true; } void IntitialCastCheck() { tshot = 0; tret = 0; if (ShotsLeft > 0) { var mask = ~(1 << 7 | 1 << 2); //dont grapple on NoRope and Ignore Raycast layers hit = Physics2D.CircleCast(CharPos,0.75f,dir,Range, mask); //raycast from character to target lr.positionCount = 2; lr.SetPosition(1, CharPos); //will stay at characer lr.SetPosition(0, CharPos);// will eventually go to grapple point if (hit.collider != null) //if the raycast hits, initiate grapple { GrappleObjCollider = hit.collider as EdgeCollider2D; //get the target's collider //GrappleObjCollider = hit.collider as hit.collider.GetType(); //get the target's collider WrappingBodies.Add(0, hit.rigidbody); //get targets rigidbody GrabPointinLocal = WrappingBodies[0].transform.InverseTransformPoint(hit.point); //Get the hit-point in the grapple body's ref frame. This will make //it easy to get connect to moving bodies //1) move to bodies frame //2) body moves in world frame, doesnt move in its own frame //3) move back to world frame to get the new location of the hit point // on the body (for linerenderer) //(with GrappleBody, anchor point is in terms of local coords) WrappingPoints.Add(0, GrabPointinLocal); //store intitial grapple point WrappingAngleLookup.Add(0, 0); //store angle (for unwrapping) Grapple.connectedBody = WrappingBodies[0]; //set connected body to grapple rigid body Grapple.connectedAnchor = WrappingPoints[0]; //set grapple point to hit point Grapple.distance = hit.distance; //set grapple distance WillGrapple = true; Grapple.enabled = true; //enable the distance joint ShotsLeft--; //decrement shots remaining } else if (hit.collider == null)// if raycast doesnt hit anything, dont anchor { WillGrapple = false; } ReadytoRetract = true; } } void GrappleMove() //how movement works while grappled (ie. swinging) { float xMove = Input.GetAxisRaw("Horizontal"); //A,D down float yMove = Input.GetAxisRaw("Vertical"); //W, S down Vector2 GrappleAnchor = GrabPointinWorld; Vector2 PlayertoAnchor = -(CharPos - GrappleAnchor).normalized; List<float> DPs = new() //DPs[0] = DP with up, DPs[1] = DP with right { Mathf.Abs(Vector2.Dot(PlayertoAnchor, Vector2.up)), Mathf.Abs(Vector2.Dot(PlayertoAnchor, Vector2.right)) }; int DirIndex = DPs.IndexOf(DPs.Max()); if (DirIndex == 0) //if grapple point is above or below player { var DPVert = Vector2.Dot(PlayertoAnchor, Vector2.up); rb.AddForce(new Vector2(xMove * WiggleForce, 0), ForceMode2D.Impulse); //x-movement is unchanged if (DPVert > 0 && ropelength < Range)//if under the anchor point { rb.velocity += yMove * ClimbSpeed * PlayertoAnchor; //up is climb, down is slide Grapple.distance -= yMove * ClimbSpeed; } if (DPVert < 0 && ropelength < Range) // if above the anchor { rb.velocity += yMove * ClimbSpeed * PlayertoAnchor; // down is climb, up is slide Grapple.distance += yMove * ClimbSpeed; } } if (DirIndex == 1) //if grapple is to the left or right of player { var DPHoriz = Vector2.Dot(PlayertoAnchor, Vector2.right); rb.AddForce(new Vector2(0, yMove * WiggleForce), ForceMode2D.Impulse); if (DPHoriz > 0 && ropelength < Range)//if to the left of the anchor { rb.velocity += xMove * ClimbSpeed * PlayertoAnchor; // right is climb, left is slide Grapple.distance -= xMove * ClimbSpeed; } if (DPHoriz < 0 && ropelength < Range) // if to the right of the anchor { rb.velocity += xMove * ClimbSpeed * PlayertoAnchor; //left is climb, right is slide Grapple.distance += xMove * ClimbSpeed; } } if (ropelength >= Range) // keep rope from going over its max length { Grapple.distance -= (ropelength - Range); } } void RopeUpdater() { //Grapple.connectedAnchor = GrabPointinLocal; //Grapple.connectedBody = WrappingBodies[WrappingPoints.Count - 1]; //initial rope cast Vector2 Grappoint0inWorld = WrappingBodies[0].transform.TransformPoint(WrappingPoints[0]); // the initial grapple point var shottime = (CharPos - Grappoint0inWorld).magnitude / shotspeed; //time to reach grapple position if (tshot < shottime) //cast rope to grapple point animation { Vector3 newpos; newpos = Vector3.Lerp(CharPos, Grappoint0inWorld, tshot / shottime); lr.SetPosition(0, newpos); tshot += Time.deltaTime; } else if (tshot > shottime) // keep rope at grapple point as it moves { //tshot = shottime; lr.SetPosition(0, Grappoint0inWorld); RopeGrapplePoint = lr.GetPosition(0); } for (int i = 0; i < lr.positionCount - 1; i++) { lr.SetPosition(i, WrappingBodies[i].transform.TransformPoint(WrappingPoints[i]));// move rope points along with moving objects ropelength += (lr.GetPosition(i) - lr.GetPosition(i + 1)).magnitude; // measure rope length } lr.SetPosition(lr.positionCount - 1, CharPos); // keep the last rope position on charachter //Wrapping handler var dir2 = (GrabPointinWorld - CharPos).normalized; //from character to the current grab point Updatehit = Physics2D.Raycast(CharPos, dir2, (CharPos - GrabPointinWorld).magnitude - 0.5f); //a new raycast to see if we should wrap the rope //wrapper if (Updatehit.collider != null) { var WrappingGrappleObj = Updatehit.collider as EdgeCollider2D; //get (possibly new) grapple object GrappleColliderPoints = WrappingGrappleObj.points; //get the points of the collider of the grapple object GrappleBody = Updatehit.rigidbody; Debug.DrawLine(Updatehit.point, Updatehit.point + Updatehit.normal, Color.red, 10f); var OrderedDistanceDict = GrappleColliderPoints.ToDictionary<Vector2, float, Vector2> // dictionary that finds the collider point thats closest to the raycast hit point (position => Vector2.Distance(Updatehit.point, GrappleBody.transform.TransformPoint(position)), position => GrappleBody.transform.TransformPoint(position)).OrderBy(e => e.Key); GrabPointinWorld = OrderedDistanceDict.First().Value; //get closest point GrabPointinLocal = GrappleBody.transform.InverseTransformPoint(GrabPointinWorld); //make closest point the new grapple point WrappingPoints.Add(WrappingPoints.Count, GrabPointinLocal); //add the new point and rigid body to wrapping dictionaries WrappingBodies.Add(WrappingBodies.Count, GrappleBody); WrappingAngleLookup.Add(WrappingAngleLookup.Count, 0); lr.positionCount++; //add a line render position Grapple.connectedBody = GrappleBody; // anchor to new object at the new point Grapple.connectedAnchor = GrabPointinLocal; Grapple.distance = (CharPos - GrabPointinWorld).magnitude; lr.SetPosition(lr.positionCount - 1, lr.GetPosition(lr.positionCount - 2)); //put character position as the final linerender point lr.SetPosition(lr.positionCount - 2, GrabPointinWorld); //2nd last LR point is the new grapple point } if (WrappingPoints.Count > 1) //unwrapper { /* Vector2 HingetoChar = (lr.GetPosition(lr.positionCount - 1) - lr.GetPosition(lr.positionCount - 2)); //vector stuff to find the unwrapping angle Vector2 NextHingetoCurrentHinge = (lr.GetPosition(lr.positionCount - 2) - lr.GetPosition(lr.positionCount - 3)); var interhingeAngle = Vector2.Angle(lr.GetPosition(lr.positionCount - 3), NextHingetoCurrentHinge); Vector2 NextHingetoChar = (lr.GetPosition(lr.positionCount - 1) - lr.GetPosition(lr.positionCount - 3)); var HingetoCharangle = Vector2.Angle(lr.GetPosition(lr.positionCount - 3), NextHingetoChar); */ // Maybe use angles in local coordinates? -- does seem to work better var lr_1 = GrappleBody.transform.InverseTransformPoint(lr.GetPosition(lr.positionCount - 1)); var lr_2 = GrappleBody.transform.InverseTransformPoint(lr.GetPosition(lr.positionCount - 2)); var lr_3 = GrappleBody.transform.InverseTransformPoint(lr.GetPosition(lr.positionCount - 3)); Vector2 HingetoChar = (lr_1 - lr_2); Vector2 NextHingetoCurrentHinge = (lr_2 - lr_3); var interhingeAngle = Vector2.Angle(lr_3, NextHingetoCurrentHinge); Vector2 NextHingetoChar = (lr_1 - lr_3); var HingetoCharangle = Vector2.Angle(lr_3, NextHingetoChar); var ang = HingetoCharangle - interhingeAngle; Debug.Log(ang); if (ang < 0) { if (WrappingAngleLookup[WrappingAngleLookup.Count - 1] == 1) //if initial angle was positive, unwrap { UnwrapHandler(); return; } WrappingAngleLookup[WrappingAngleLookup.Count - 1] = -1; //set the wrapping angle indicator to -1 to indicate that the initial angle is negative } else { if (WrappingAngleLookup[WrappingAngleLookup.Count - 1] == -1) //if initial angle was negative, unwrap { UnwrapHandler(); return; } WrappingAngleLookup[WrappingAngleLookup.Count - 1] = 1;//set the wrapping angle indicator to +1 to indicate that the initial angle is positive } } } void UnwrapHandler() { WrappingPoints.Remove(WrappingPoints.Count - 1); //remove the current grapple point from the dictionaries WrappingBodies.Remove(WrappingBodies.Count - 1); WrappingAngleLookup.Remove(WrappingAngleLookup.Count - 1); GrappleBody = WrappingBodies[WrappingBodies.Count - 1]; //set new grapple point to the previous grapple point GrabPointinLocal = WrappingPoints[WrappingPoints.Count - 1]; GrabPointinWorld = GrappleBody.transform.TransformPoint(GrabPointinLocal); Grapple.connectedBody = GrappleBody; Grapple.connectedAnchor = GrabPointinLocal; //anchor to new point Grapple.distance = (GrabPointinWorld - CharPos).magnitude; lr.SetPosition(lr.positionCount - 2, CharPos); lr.positionCount--; Debug.Log("unwrapped"); } void Retract(Vector2 RetractFrom) { Grapple.connectedBody = null; //disconnect joint Grapple.enabled = false; var retracttime = (RetractFrom - CharPos).magnitude / retractspeed; if (tret < retracttime) //run retraction animation { lr.SetPosition(lr.positionCount - 1, CharPos); Vector3 newposret; newposret = Vector3.Lerp(RetractFrom, CharPos, tret / retracttime); lr.SetPosition(0, newposret); tret += Time.deltaTime; } else if (tret >= retracttime) { WrappingPoints.Clear(); WrappingBodies.Clear(); WrappingAngleLookup.Clear(); lr.positionCount = 0; ReadytoRetract = false; } } }
Editor is loading...