Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Mr_Whiteflame · May 11, 2020 at 08:21 AM · c#2draycast

Getting a Raycast rope to follow its object

Hey all! So I have been working on a 2D game for a few months now. It is a platformer using a grappling hook to swing from object to object. As a basis I went with this: https://www.raywenderlich.com/348-make-a-2d-grappling-hook-game-in-unity-part-1 to get started. From then I have ironed out a bunch of bugs, etc. And it works great! But I have hit a blockade that I have no idea how to fix. And I was wondering if you wonderful people would be able to help. So I have a point where you attach to a moving grapple point to get through a level. But once the grapple hits, it does not follow the object as it is not really attached, it just takes the point of the raycast it hits. Is there a way to fix this as to possibly make it so the attached rope will follow the raycasted object? This one has me stumped so any help means the world! Thanks!

 public class RopeSystem : MonoBehaviour
 {
     public LineRenderer ropeRenderer;
     public LayerMask ropeLayerMask;
     public float climbSpeed = 3f;
     public GameObject ropeHingeAnchor;
     public DistanceJoint2D ropeJoint;
     public Transform crosshair;
     public SpriteRenderer crosshairSprite;
     public PlayerMovement playerMovement;
     private bool ropeAttached;
     private Vector2 playerPosition;
     private List<Vector2> ropePositions = new List<Vector2>();
     public float ropeMaxCastDistance = 10f;
     private Rigidbody2D ropeHingeAnchorRb;
     private bool distanceSet;
     private bool isColliding;
     private Dictionary<Vector2, int> wrapPointsLookup = new Dictionary<Vector2, int>();
     private SpriteRenderer ropeHingeAnchorSprite;
     private bool touchingBarrier;
 
 
     void Awake ()
     {
         ropeJoint.enabled = false;
         playerPosition = transform.position;
         ropeHingeAnchorRb = ropeHingeAnchor.GetComponent<Rigidbody2D>();
         ropeHingeAnchorSprite = ropeHingeAnchor.GetComponent<SpriteRenderer>();
     }
 
     /// <summary>
     /// Figures out the closest Polygon collider vertex to a specified Raycast2D hit point in order to assist in 'rope wrapping'
     /// </summary>
     /// <param name="hit">The raycast2d hit</param>
     /// <param name="polyCollider">the reference polygon collider 2D</param>
     /// <returns></returns>
     private Vector2 GetClosestColliderPointFromRaycastHit(RaycastHit2D hit, PolygonCollider2D polyCollider)
     {
         // Transform polygoncolliderpoints to world space (default is local)
         var distanceDictionary = polyCollider.points.ToDictionary<Vector2, float, Vector2>(
             position => Vector2.Distance(hit.point, polyCollider.transform.TransformPoint(position)), 
             position => polyCollider.transform.TransformPoint(position));
 
         var orderedDictionary = distanceDictionary.OrderBy(e => e.Key);
         return orderedDictionary.Any() ? orderedDictionary.First().Value : Vector2.zero;
     }
 
     // Update is called once per frame
     void Update ()
     {
         var worldMousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0f));
         var facingDirection = worldMousePosition - transform.position;
         var aimAngle = Mathf.Atan2(facingDirection.y, facingDirection.x);
         if (aimAngle < 0f)
         {
             aimAngle = Mathf.PI * 2 + aimAngle;
         }
 
         var aimDirection = Quaternion.Euler(0, 0, aimAngle * Mathf.Rad2Deg) * Vector2.right;
         playerPosition = transform.position;
 
         if (!ropeAttached)
         {
             SetCrosshairPosition(aimAngle);
             playerMovement.isSwinging = false;
         }
         else
         {
             playerMovement.isSwinging = true;
             playerMovement.ropeHook = ropePositions.Last();
             crosshairSprite.enabled = false;
 
             // Wrap rope around points of colliders if there are raycast collisions between player position and their closest current wrap around collider / angle point.
             if (ropePositions.Count > 0)
             {
                 var lastRopePoint = ropePositions.Last();
                 var playerToCurrentNextHit = Physics2D.Raycast(playerPosition, (lastRopePoint - playerPosition).normalized, Vector2.Distance(playerPosition, lastRopePoint) - 0.1f, ropeLayerMask);
                 if (playerToCurrentNextHit)
                 {
                     var colliderWithVertices = playerToCurrentNextHit.collider as PolygonCollider2D;
                     if (colliderWithVertices != null)
                     {
                         var closestPointToHit = GetClosestColliderPointFromRaycastHit(playerToCurrentNextHit, colliderWithVertices);
                         if (wrapPointsLookup.ContainsKey(closestPointToHit))
                         {
                             // Reset the rope if it wraps around an 'already wrapped' position.
                             ResetRope();
                             return;
                         }
 
                         ropePositions.Add(closestPointToHit);
                         wrapPointsLookup.Add(closestPointToHit, 0);
                         distanceSet = false;
                     }
                 }
             }
         }
 
         UpdateRopePositions();
         HandleRopeLength();
         HandleInput(aimDirection);
         HandleRopeUnwrap();
     }
 
     /// <summary>
     /// Handles input within the RopeSystem component
     /// </summary>
     /// <param name="aimDirection">The current direction for aiming based on mouse position</param>
     private void HandleInput(Vector2 aimDirection)
     {
         if (Input.GetMouseButton(0))
         {
 
             if (ropeAttached) return;
             ropeRenderer.enabled = true;
 
             var hit = Physics2D.Raycast(playerPosition, aimDirection, ropeMaxCastDistance, ropeLayerMask);
             if (hit.collider != null)
             {
                 ropeAttached = true;
                 if (!ropePositions.Contains(hit.point) && hit.transform.gameObject.layer == 12)
                 {
                     ropeRenderer.enabled = false;
                     ropeAttached = false;
                     ropeJoint.enabled = false;
                 }
 
                 else if (!ropePositions.Contains(hit.point))
                 {
                 // Jump slightly to distance the player a little from the ground after grappling to something.
                 transform.GetComponent<Rigidbody2D>().AddForce(new Vector2(0f, 2f), ForceMode2D.Impulse);
                 ropePositions.Add(hit.point);
                 wrapPointsLookup.Add(hit.point, 0);
                 ropeJoint.distance = Vector2.Distance(playerPosition, hit.point);
                 ropeJoint.enabled = true;
                 ropeHingeAnchorSprite.enabled = true;
                 }
             }
             else
             {
                 ropeRenderer.enabled = false;
                 ropeAttached = false;
                 ropeJoint.enabled = false;
             }
         }
 
         if (Input.GetMouseButton(1))
         {
             ResetRope();
         }
     }
 
     /// <summary>
     /// Resets the rope in terms of gameplay, visual, and supporting variable values.
     /// </summary>
     private void ResetRope()
     {
         ropeJoint.enabled = false;
         ropeAttached = false;
         playerMovement.isSwinging = false;
         ropeRenderer.positionCount = 2;
         ropeRenderer.SetPosition(0, transform.position);
         ropeRenderer.SetPosition(1, transform.position);
         ropePositions.Clear();
         wrapPointsLookup.Clear();
         ropeHingeAnchorSprite.enabled = false;
     }
 
     /// <summary>
     /// Move the aiming crosshair based on aim angle
     /// </summary>
     /// <param name="aimAngle">The mouse aiming angle</param>
     private void SetCrosshairPosition(float aimAngle)
     {
         if (!crosshairSprite.enabled)
         {
             crosshairSprite.enabled = true;
         }
     }
 
     /// <summary>
     /// Retracts or extends the 'rope'
     /// </summary>
     private void HandleRopeLength()
     {
         if (Input.GetAxis("Vertical") >= 1f && ropeAttached && !isColliding)
         {
             ropeJoint.distance -= Time.deltaTime * climbSpeed;
         }
         else if (Input.GetAxis("Vertical") < 0f && ropeAttached && ropeJoint.distance <= ropeMaxCastDistance && touchingBarrier == false)
         {
             ropeJoint.distance += Time.deltaTime * climbSpeed;
         }
     }
 
     /// <summary>
     /// Handles updating of the rope hinge and anchor points based on objects the rope can wrap around. These must be PolygonCollider2D physics objects.
     /// </summary>
     private void UpdateRopePositions()
     {
         if (ropeAttached)
         {
             ropeRenderer.positionCount = ropePositions.Count + 1;
 
             for (var i = ropeRenderer.positionCount - 1; i >= 0; i--)
             {
                 if (i != ropeRenderer.positionCount - 1) // if not the Last point of line renderer
                 {
                     ropeRenderer.SetPosition(i, ropePositions[i]);
                     
                     // Set the rope anchor to the 2nd to last rope position (where the current hinge/anchor should be) or if only 1 rope position then set that one to anchor point
                     if (i == ropePositions.Count - 1 || ropePositions.Count == 1)
                     {
                         if (ropePositions.Count == 1)
                         {
                             var ropePosition = ropePositions[ropePositions.Count - 1];
                             ropeHingeAnchorRb.transform.position = ropePosition;
                             if (!distanceSet)
                             {
                                 ropeJoint.distance = Vector2.Distance(transform.position, ropePosition);
                                 distanceSet = true;
                             }
                         }
                         else
                         {
                             var ropePosition = ropePositions[ropePositions.Count - 1];
                             ropeHingeAnchorRb.transform.position = ropePosition;
                             if (!distanceSet)
                             {
                                 ropeJoint.distance = Vector2.Distance(transform.position, ropePosition);
                                 distanceSet = true;
                             }
                         }
                     }
                     else if (i - 1 == ropePositions.IndexOf(ropePositions.Last()))
                     {
                         // if the line renderer position we're on is meant for the current anchor/hinge point...
                         var ropePosition = ropePositions.Last();
                         ropeHingeAnchorRb.transform.position = ropePosition;
                         if (!distanceSet)
                         {
                             ropeJoint.distance = Vector2.Distance(transform.position, ropePosition);
                             distanceSet = true;
                         }
                     }
                 }
                 else
                 {
                     // Player position
                     ropeRenderer.SetPosition(i, transform.position);
                 }
             }
         }
     }
 
     void OnTriggerStay2D(Collider2D colliderStay)
     {
         isColliding = true;
     }
 
     private void OnTriggerExit2D(Collider2D colliderOnExit)
     {
         isColliding = false;
     }
 
     private void OnCollisionEnter2D(Collision2D Barrier)
     {
         touchingBarrier = true;
         Debug.Log("Touching");
     }
     private void OnCollisionExit2D(Collision2D Barrier)
     {
         touchingBarrier = false;
         Debug.Log("Not Touching");
     }
 
     private void HandleRopeUnwrap()
     {
         if (ropePositions.Count <= 1)
         {
             return;
         }
         // Hinge = next point up from the player position
         // Anchor = next point up from the Hinge
         // Hinge Angle = Angle between anchor and hinge
         // Player Angle = Angle between anchor and player
 
         // 1
         var anchorIndex = ropePositions.Count - 2;
         // 2
         var hingeIndex = ropePositions.Count - 1;
         // 3
         var anchorPosition = ropePositions[anchorIndex];
         // 4
         var hingePosition = ropePositions[hingeIndex];
         // 5
         var hingeDir = hingePosition - anchorPosition;
         // 6
         var hingeAngle = Vector2.Angle(anchorPosition, hingeDir);
         // 7
         var playerDir = playerPosition - anchorPosition;
         // 8
         var playerAngle = Vector2.Angle(anchorPosition, playerDir);
 
         if (!wrapPointsLookup.ContainsKey(hingePosition))
         {
             Debug.LogError("We were not tracking hingePosition (" + hingePosition + ") in the look up dictionary.");
             return;
         }
 
         if (playerAngle < hingeAngle)
         {
             // 1
             if (wrapPointsLookup[hingePosition] == 1)
             {
                 UnwrapRopePosition(anchorIndex, hingeIndex);
                 return;
             }
 
             // 2
             wrapPointsLookup[hingePosition] = -1;
         }
         else
         {
             // 3
             if (wrapPointsLookup[hingePosition] == -1)
             {
                 UnwrapRopePosition(anchorIndex, hingeIndex);
                 return;
             }
 
             // 4
             wrapPointsLookup[hingePosition] = 1;
         }
     }
 
     private void UnwrapRopePosition(int anchorIndex, int hingeIndex)
     {
         // 1
         var newAnchorPosition = ropePositions[anchorIndex];
         wrapPointsLookup.Remove(ropePositions[hingeIndex]);
         ropePositions.RemoveAt(hingeIndex);
 
         // 2
         ropeHingeAnchorRb.transform.position = newAnchorPosition;
         distanceSet = false;
 
         // Set new rope distance joint distance for anchor position if not yet set.
         if (distanceSet)
         {
             return;
         }
         ropeJoint.distance = Vector2.Distance(transform.position, newAnchorPosition);
         distanceSet = true;
     }
 }
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

777 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Issue with raycasting in 2D 1 Answer

Cast multiple rays from an object between two angles? 0 Answers

Raycasting not working? 1 Answer

Reverse object position order 1 Answer

Upon shooting, Raycast target moves infinitely 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges