Search Unity

working 2D rope concept for sidscrolling games (for free)

Discussion in 'Works In Progress - Archive' started by hiphish, Feb 4, 2011.

  1. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Update: I don't have any of the code anymore, I'm sorry, but this thread is all that's left. I can't PM you a working example anymore

    Hi

    Some time ago I was came across the "Rope Script" made by a user called Jake. However, his rope was all fine for 3D games, but way too unpredictable for 2D games. So I set out to make my own rope.


    Instead of explaining the details and how amazing I am, just take a look:

    Get your hands on a working Lerpz With Rope example [DEAD LINK]

    So, how to make this? I will explain it step by step.



    1. the rope
    The rope consists of several segments connected through character joints. Only the topmost segment has a hinge joint instead.

    So, how to build the rope? Unfortunately, I have no idea, how to automate this process, so you'll have to do it by hand. If anyone can figure out how to make a script that does the work, be my guest.

    Start off with one segment (e.g. a capsule).
    Give it the following componnts: a collider (capsule recommended), rigidbody and character joint.
    Set the joint's properties for Axis to (1, 0, 0) and Swingg Axis to (0, 0, 1). I am not sure about this, but it works for me.

    Do the same for the next segment, which is above the one before.

    Go back to the fist segment and in the Character Joint component set "Connected Body" to the second segment.

    Here is a screenshot for reference:


    Do the same thing for all the other segments accordingly, always connecting it to the segment right below it.

    When you are about to make the final, topmost segment, give it a hinge joint.
    Set Axis to (1, 0, 0) as well, but leave "Connected Body" empty. This will connect the joint to the world, keeping it in place, and providing a reliable holder.

    As a final note, I set the layer of all segments, including the final one, to a layer, that can only collide with the player. So the rope will not be interrupted by enemies, powerups, or even other ropes. Usualy this is desirable in a game, as you don't want the rope to become unreachable thus making the player stuck.



    2. restricting the rope to 2D
    Even though the player is seeing the game as a 2D game, everything still works in 3D. So the rope might move along the z-Axis into the back- or foreground, an the player character will seem to walk through it.
    To restrict the rope i used a simple script. Attach it to every segment. It might be bad for performance, so you might want to be able to deactivate the rope when the player is too far away. Figure out what suits your needs best.
    Anyway, here is the script:
    Code (csharp):
    1. //prevents the object from moving and rotating in a way unfit for 2D
    2.  
    3. function FixedUpdate () {
    4.     transform.localPosition.z = 0;
    5.     transform.eulerAngles.x = 0;
    6.     transform.eulerAngles.y = 0;
    7. }
     
    Last edited: Apr 13, 2013
  2. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    3. climbing
    OK, here comes the cool part. You will need three scripts.
    The first one goes onto the player. It contains all the controls related aspects. When you attach it, disable it, we won't need it yet.
    Code (csharp):
    1.  
    2. /*
    3. STUFF TO DO:
    4. -Clean up the secondary variables stuff
    5. -see how the horizontal moving works out
    6.  
    7. */
    8.  
    9. //make speed for climbing and slipping idepentent, just in case
    10. var climbingSpeed = 3.0;
    11. var slippingSpeed = 3.0;
    12. var horizontalSpeed = 3.0;
    13.  
    14. //a nice little touch, disable for more control
    15. var slipsDownABit = true;
    16. var slipsUpABit = false;
    17.  
    18. //enable to be able to move horizontally
    19. var canMoveHorizontally = false;
    20. //enable to apply force on the carrier (overrides the above)
    21. var canShakeCarrier = false;
    22.  
    23. //these will be used for switching between climbing and sliding
    24. @System.NonSerialized
    25.     var climbingSwitch = 0;
    26. @System.NonSerialized
    27.     var slippingSwitch = 0;
    28.    
    29. //this will keep track of how many segments we are climbing at the moment
    30. var segmentHashtable: Hashtable;
    31. //the next lower segment the player could hang onto
    32. @System.NonSerialized
    33.     var previousParent: GameObject;
    34.  
    35. //the horizontal offset for climbing the target (0 is recommended), will be set by object to climb
    36. private var xOffset = 0.0;
    37.  
    38. @System.NonSerialized
    39.     var directionToFace = 1;
    40.  
    41.  
    42. function Awake(){
    43.     segmentHashtable = new Hashtable();
    44. }
    45.  
    46. function Update () {
    47.     //first snap to the thing we climb
    48.     transform.localPosition.x = xOffset;
    49.    
    50.     //cache raw and smoothed axis values
    51.     var rawVerticalAxis = Input.GetAxisRaw("Vertical");
    52.     var smoothVerticalAxis = Input.GetAxis("Vertical");
    53.     var rawHorizontalAxis = Input.GetAxisRaw("Horizontal");
    54.     var smoothHorizontalAxis = Input.GetAxis("Horizontal");
    55.    
    56.     //set the switches
    57.     if (smoothVerticalAxis > 0){
    58.         //climbing up
    59.         climbingSwitch = 1;
    60.         slippingSwitch = 0;
    61.     } else if (smoothVerticalAxis < 0){
    62.         //sliding down
    63.         climbingSwitch = 0;
    64.         slippingSwitch = 1;
    65.     } else{
    66.         //hanging still
    67.         climbingSwitch = 0;
    68.         slippingSwitch = 0;
    69.     }
    70.    
    71.     //now move, but only if a button is pressed OR shortly after releasing down (or up) to simulate some minor sliding
    72.     if (rawVerticalAxis != 0 || (smoothVerticalAxis < 0  slipsDownABit) || (smoothVerticalAxis > 0  slipsUpABit))
    73.         transform.Translate(Vector3.up * Mathf.Pow(climbingSpeed *smoothVerticalAxis, climbingSwitch) *  Mathf.Pow(slippingSpeed * smoothVerticalAxis, slippingSwitch) * Time.deltaTime);
    74.     //horizontal movement
    75.     if(smoothHorizontalAxis != 0  canMoveHorizontally)
    76.         transform.Translate(Vector3.right * horizontalSpeed * smoothHorizontalAxis * Time.deltaTime);
    77.        
    78.     //shake it!
    79.     if(canShakeCarrier)
    80.         transform.parent.gameObject.rigidbody.AddRelativeForce(Vector3.right * smoothHorizontalAxis * 10);
    81.        
    82.     if(Input.GetButtonDown("Jump"))
    83.         transform.parent.gameObject.GetComponent(RopeSegmentBehaviour).JumpOff(rawHorizontalAxis, gameObject); 
    84.     if(rawHorizontalAxis != 0)
    85.         directionToFace = rawHorizontalAxis;
    86. }
    87.  
    88. function LateUpdate(){
    89.     //set the rotation to fit the parent, if parented
    90. //  if(transform.parent)
    91. //      transform.rotation = transform.parent.transform.rotation;
    92. //  Debug.Log (GetSegments());
    93.    
    94.     /*
    95.     if(directionToFace == 1){
    96.         transform.localEulerAngles.y = 0;
    97.     } else{
    98.         transform.localEulerAngles.y = 180;
    99.     }
    100.     */
    101. }
    102.  
    103.  
    104. function RegisterSegment(segment: GameObject){
    105.     segmentHashtable.Add(segment.name, segment);
    106. }
    107.  
    108. function UnregisterSegment(segment: GameObject){
    109.     segmentHashtable.Remove(segment.name);
    110. }
    111.  
    112.  
    113. function SetXOffest(offset: float){
    114.     xOffset = offset;
    115. }
    116.  
    117. function SetUpController(newClimbingSpeed: float, newSlippingSpeed: float, newHorizontalSpeed: float, slipUp: boolean, slipDown: boolean, moveHorizontally: boolean, shake: boolean){
    118.     //if a passed value is 0, then ignore it
    119.     if (newClimbingSpeed != 0.0)
    120.         climbingSpeed = newClimbingSpeed;
    121.     if ( newSlippingSpeed != 0.0)
    122.         slippingSpeed = newSlippingSpeed;
    123.     if ( newHorizontalSpeed != 0.0)
    124.         horizontalSpeed = newHorizontalSpeed;
    125.     slipsDownABit = slipUp;
    126.     slipsUpABit = slipDown;
    127.     canMoveHorizontally = moveHorizontally;
    128.     canShakeCarrier = shake;
    129.    
    130.     //override canMoveHorizontally if needed
    131.     if(canShakeCarrier)
    132.         canMoveHorizontally = false;
    133. }
    134.  
    There are some things I don't intend to use in my game, but I put them in, just in case I might want in some future game. I won't go into detail, the code should have enough comments. There might be stuff to clean up, I haven't had time to go into details yet. Again, if anyone has suggestions or improvements, feel free to contribute.
     
    Last edited: Mar 30, 2011
  3. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    The second sript goes on every single segment and only works if the rope can only collide with the player. More speciffically, my player is carrying a game object, that does the rope- and enemy related collisions, while the player itself cannot collide with them. This approach gives me more control.

    just make sure the collider is slightly bigger than the player. This thing never collides with walls.

    Also, make sure to have all the segments' colliders as triggers or else they will move the player#s collision sensor around.

    So, attach this to every segment:
    Code (csharp):
    1.  
    2. /*
    3. --- script used to parent player or other objects to a rope during gameplay ---
    4.  
    5. Use this script in combination with a rope. Currently only works with triggers.
    6. The player has to press Up, in order to stick
    7. */
    8. var segmentNumber: int;
    9.  
    10. function OnTriggerEnter (collision: Collider){
    11.     collision.gameObject.transform.parent.gameObject.SendMessage("OnEnterRope", gameObject, SendMessageOptions.DontRequireReceiver);
    12. }
    13.  
    14. function OnTriggerExit (collision: Collider){
    15.     collision.gameObject.transform.parent.gameObject.SendMessage("OnExitRope", gameObject, SendMessageOptions.DontRequireReceiver);
    16. }
    17.  
    18. function JumpOff(theDirection: int, jumper: GameObject){
    19.     //always have some direction, if nothing use the joint's one
    20.     if(theDirection == 0)
    21.         theDirection = Mathf.Sign(rigidbody.velocity.x);
    22.    
    23.     //cache the controller script
    24.     var controllerScript = jumper.GetComponent(GroundController);
    25.    
    26.     //now set everything to be ready for the jump
    27.     controllerScript.jump.isPrimitive = false;
    28.     controllerScript.movement.momentum = rigidbody.velocity.x;
    29.     //choose the speed
    30.     if(Mathf.Abs(rigidbody.velocity.x) >= controllerScript.movement.runSpeed){
    31.         controllerScript.movement.speed = controllerScript.movement.runSpeed * Mathf.Sign(rigidbody.velocity.x);
    32.     } else if (Mathf.Abs(rigidbody.velocity.x) >= controllerScript.movement.walkSpeed){
    33.         controllerScript.movement.speed = controllerScript.movement.walkSpeed * Mathf.Sign(rigidbody.velocity.x);
    34.     } else{
    35.         controllerScript.movement.speed = rigidbody.velocity.x;
    36.     }
    37.     controllerScript.jump.launchDirection = theDirection;
    38.    
    39.     //decouple
    40.     jumper.transform.parent = null;
    41.     jumper.GetComponent(ClimbingController).segmentHashtable.Clear();
    42.    
    43.     //switch controller scripts and the decoupling is done
    44.     controllerScript.enabled = true;
    45.     jumper.GetComponent(ClimbingController).enabled = false;
    46.    
    47.     //now JUMP!
    48.     controllerScript.movement.verticalSpeed = controllerScript.CalculateJumpVerticalSpeed (controllerScript.jump.height);
    49.     controllerScript.DidJump();
    50. }
    51.  
    Again, cleanup still to be done. GroundController refers to the controller script I'm using for regular movement, so whenever "GroundController" is referenced, substitute these lines with whatever would be appropriate for you.

    I use third script on the player that handles managing different control scripts:
    Code (csharp):
    1.  
    2. /*
    3. --- Character Controls Manager Script ---
    4.  
    5. This script is used to receive Messages from various triggers and objects
    6. to enable controls the player to use powerups or switch control scripts
    7.  
    8. */
    9.  
    10. //using variables to cache script components for performance reasons
    11. @System.NonSerialized
    12.     var walkingScript: GroundController;
    13. @System.NonSerialized
    14.     var climbingScript: ClimbingController;
    15.  
    16.  
    17.  
    18. //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
    19. //setting everything up
    20. function Awake(){
    21.     walkingScript = gameObject.GetComponent(GroundController);
    22.     climbingScript = gameObject.GetComponent(ClimbingController);
    23. }
    24. //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
    25.  
    26.  
    27.  
    28. //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
    29. //here come the functions to call
    30.  
    31. function OnEnterRope(rope: GameObject){
    32.     if((Input.GetAxisRaw("Vertical") != 1  climbingScript.enabled == false) || climbingScript.segmentHashtable.ContainsValue(rope))
    33.         return;
    34.  
    35.     //add this segment to the hashtable keeping track
    36.     climbingScript.RegisterSegment(rope);
    37.    
    38. //  Debug.Log (Time.time + rope.name + gameObject.name);
    39.    
    40.     //only parent to the topmost segment or if not parented to any segment
    41.     if(transform.parent == null || transform.parent.position.y < rope.transform.position.y){
    42.         climbingScript.SetUpController(0.0, 0.0, 0.0, true, false, false, true);
    43.    
    44.         if(transform.parent == null){
    45.             //need something for refernece
    46.             climbingScript.previousParent = rope;
    47.         }else{
    48.             //the previous parent, which will be replaced now
    49.             climbingScript.previousParent = transform.parent.gameObject;   
    50.         }
    51.         transform.parent = rope.transform;
    52.        
    53.         climbingScript.SetXOffest(0.0);
    54.         walkingScript.enabled = false;
    55.         climbingScript.enabled = true;
    56.     }
    57. }
    58.  
    59. function OnExitRope(rope: GameObject){
    60.     if (climbingScript.enabled == false)
    61.         return;
    62.    
    63.     //remove this segment from the hashtable
    64.     climbingScript.UnregisterSegment(rope);
    65.    
    66. //  Debug.Log (Time.time + gameObject.name + rope.name + "exited collision");
    67.  
    68.     //when exiting the segment the player is parented to (i.e. climbing down) we need another parent
    69.     if(transform.parent == rope.transform){
    70.         transform.parent = climbingScript.previousParent.transform;
    71.         //some setup
    72.         var tempValue: int = 0; //the lowest segment must have the number 1
    73.         var nextParent: GameObject;
    74.         // loop through all remaining segments to find the topmost one, this will be the next ready segment
    75.         for(var segment: DictionaryEntry in climbingScript.segmentHashtable){
    76.             if(segment.Value.GetComponent(RopeSegmentBehaviour).segmentNumber > tempValue  transform.parent != segment.Value.transform)
    77.                 nextParent = segment.Value;
    78.             if(transform.parent != segment.Value.transform)
    79.                 tempValue = segment.Value.GetComponent(RopeSegmentBehaviour).segmentNumber;
    80.         }
    81.         if(nextParent){
    82.             climbingScript.previousParent = nextParent;
    83.         }else{
    84.             climbingScript.previousParent = transform.parent.gameObject;
    85.         }
    86.     }
    87.    
    88.     //the player will be touching several sements at a time. We want to dismount the player
    89.     //only if he exited the last trigger he was in
    90.     if(climbingScript.segmentHashtable.Count == 0){
    91.         //the following two make the player fall down straight
    92.         walkingScript.jump.isPrimitive = true;
    93.         walkingScript.movement.momentum = 0;
    94.         //now unparent
    95.         transform.parent = null;
    96.         //and acivate the right controller
    97.         walkingScript.enabled = true;
    98.         climbingScript.enabled = false;
    99.     }
    100. }
    101. //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
    102.  
    103.  
    104.  
    105. //_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-
    106. //various herlper functions
    107.  
    108. //my own Signum function to the rescue, because Mathf.Sign() sucks!
    109. function Signum(x: int){
    110.     var sgnm: int = 0;
    111.     if (x != 0)
    112.         sgnm = Mathf.Sign(x);
    113.     return sgnm;
    114. }
    115.  




    --------------------------------------------------------------------------------
    The explanations and codes above are provided for free and can be used and/or modified at will. They are free for any use, including commercial.
    I do not intend to support this concept, mainly for time reasons. It is just concept and there sure is room for improvement and addition.
     
    Last edited: Mar 30, 2011
  4. da7thSkull

    da7thSkull

    Joined:
    Feb 15, 2010
    Posts:
    22
    hello HiPhish

    first off all a big thx for the post, and for sharing your work wit the community.
    i've not really coding knowledge, and i have trying to rebuild the scene with your instructions. but i don't bring it to work :(.

    so now a ask, can someone please upload a working unitypackage, so i'am able to see what i do not correct.

    cheers

    michael
     
  5. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I might build a rope into the 2D gameplay tutorial provided by Unity. But it won't be anytime soon, I just don't have the time at the moment.
     
  6. da7thSkull

    da7thSkull

    Joined:
    Feb 15, 2010
    Posts:
    22
    hello dear unity community

    first of all one thing to clarify, i'm a "3D Artist" and not a "Dev", but since i know unity i trying to get the logic of coding :confused:.

    i trying to upload the .unitypackage (9.3MB) mix between the "Unity 2D Gameplay Tutorial" and "HiPhish's 2D Rope Climbing Controller", but always it comes up with the file is to large :eek: .

    :rolleyes:

    this is why i put it to: http://rapidshare.com/files/446634313/_2D_Rope_and_2D_Platformer.unitypackage

    :cool: sorry for that, and i am happy:D if someone will improve this version and upload it 4 the community.

    cheers

    michael
     
    Last edited: Feb 7, 2011
  7. rbeverly

    rbeverly

    Joined:
    Feb 19, 2011
    Posts:
    2
    Careful how you play with these things... it can get dangerous, as I discovered!



    Anyway, I hope the video is good for a laugh. On a more serious note, I'm working on ropes and other flexible things to use on iOS and other games. If I come up with anything useful beyond what's here or the other rope thread I'll share. Thanks for sharing the code!
     
  8. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Haha, nice one :) You have to find a way to switch back to the old controls and turn the climbing script off, once you are no longer touching any rope segments.
    Good luck with your project.
     
  9. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Hi everyone. Bad news.

    I had just returned to developing after a long break and found the same bug happening as in rbeverly's video. The rope did work in Unity 3.1, so it looks like one of the updates broke the rope.

    The problem is, that when entering a rope segment, OnTriggerEnter keeps being called every frame or so. The player keeps track of how many segments he is touching, so if OnTriggerEnter is called all the time, the numer gets way too high. One should slide off the rope when the count equals 0, but this way the count will never be that low, so the player stays parented to the last segment he touches.

    I already filed a bug report, but there is nothing else i can do at the moment. i will post here when the issue gets fixed.
     
  10. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Nice try Unity, but if you strike me down, I shall become more powerful than you could possibly imagine.

    I worked around the issue by using a hashtable to keep track of the segments instead of just counting their amount. This also allowed me to finally get rid of some ugly behaviour when climbing down. The scripts above have been updated, however weird stuff can stillhappen if the player swings around wildly, but let's just say that it's an intended design decision which reflects the real-world scenario when someone was swinging too much on a real rope ;) And if that doesn't sound convincing, just disable the player from being able to swing the rope.

    On an unrelated note, I won't be able to make an example project for upload. Ripping out my code and replacing it with other stuff and still making it work would take too much time in between studies, job and actually working on my game. Sorry guys, but this thread is the best I can offer.
     
    Last edited: Mar 30, 2011
  11. koki

    koki

    Joined:
    Nov 27, 2009
    Posts:
    43
    Hey HiPhish, congrats you did a great job on this. All in all, how did you do the ropes to swing?
     
  12. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Take a look into the climbing script in my second post. The important part is here:
    Code (csharp):
    1.  
    2. //shake it!
    3.     if(canShakeCarrier)
    4.         transform.parent.gameObject.rigidbody.AddRelativeForce(Vector3.right * smoothHorizontalAxis * 10);
    5.  
    Fist of all, you have to check canShakeCarrier in the inspector (or have it be true on default). Then when you press left or right this line will apply some force to the segment the player is holding on to.
     
  13. koki

    koki

    Joined:
    Nov 27, 2009
    Posts:
    43
    Hi HiPhish, thanks for your reply. Actually, i was referencing about the rope natural swing. I noticed the ropes has a constant movement independently from the user interaction with the ropes.

    Thanks
     
  14. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Oh that, just have the whole rope at an angle when you assemble it in the editor. Once the level lads gravity will do the work (just like it would in real life)


    Since all the segments are just triggers they won't be stopped when the player just jumps through the rope without holding "Up". This may not be physically accurate, but it feels more classic-game like.
     
    Last edited: Aug 30, 2011
  15. vshade

    vshade

    Joined:
    Aug 30, 2011
    Posts:
    1
    Hi, I'm working wiht koki, and we our rope is slowing down, we set the dampings to 0, but after some time it stops, does your hope have the same behaviour?
     
  16. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    No, it doesn't. With no information on what you did I can't help you either. Maybe Unity changed something in 3.4 or maybe there is friction between the joints. Have you set all the segments' collider to be triggers? Try just the rope without any scripts.
     
  17. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    OK, there is a working example for download right below the video in the first post. I put a rope into Unity's 2D gameplay tutorial project. It's very rough work, since my scripts were heavily modified and adapting my rope to the old stuff would have been too much work. Essentially the only thing that does not work properly is setting the PlatformerController script to reasonable values after jumping off the rope, so you will be stuck in mid-air. Since everyone will have their own tackle on the walking controls there was no real point in fixing this, as everyone would have to adapt it to their own code anyway.

    Treat the example as a working proof-of-concept. Also, the scripts in the example are slightly improved, but nothing special, so it doesn't really matter if you use the example or what's written here.
     
  18. mrochon

    mrochon

    Joined:
    Oct 19, 2011
    Posts:
    1
    Hello HiPhish,
    thanks a lot for sharing this with us, there is lots of useful infos in the technique you used for faking ropes and also great techniques in your scripts for managing different gameplay behaviors on your character.

    I am very new to Unity, but so far the experience has been pretty good. With the help of some files like the Lurpz tutorial files, I was able to quickly get things working. I was able to achieve the basis of the 2D platformer I wanted to do in only a few days. And the discovery of you rope example comes in at the perfect moment for continuing my learning.

    I struggled a bit with the integration of the rope at first, but now I got the basis working. I am using the latest version of Unity and it seems to work pretty well except for a couple of details.

    One thing that I found out in order to make it work is that the scripts seem to need a character setup a lot like Lurpz. I didnt have a seperate CollisionEmitter child object on mine, and also realised that I needed to lock the position and rotation (except z) axis on that CollisionEmitter in order to get it to work.
    Maybe thats a common setup for everyone, not sure.

    Thanks again!

    Manu

    .
     
  19. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Yeah, that's how I did it. The Lerpz example is just something I put out so people can try out a working example instead of figuring it out themselves. The whole thing was much better integrated into my game, putting it into the Lerpz tutorial was just a quick effort. As a result there are a few issues, but they have to be ironed out specifically for the scripts you are using. The controls for Lerpz work, but they are not very good, thus I assumed everyone would have their own code, so there was no point investing time into something that won't be of use to anyone. Except those who intend to ship their game with Lerpz's controls, but you really shouldn't do that.
     
  20. parnell

    parnell

    Joined:
    Jan 14, 2009
    Posts:
    206
    Any chance this would work as a grappling hook?
     
  21. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I don't see why not. The better question would be how to generate auch a rope at runtime. if you are looking for a grappling Hook like the hookshot in the Legend of Zelda games I'd say just fake it. It has no physics, it just drags you from point A to point B on a linear path with a nice looking animation.

    Now if you are looking for an actual grappling hook with physics... That's an interesting idea. I guess you could instantiate a rope consisting of only one segment and then keep adding one segment at a time as the animation plays until the topmost segment hits something. Then add a hinge joint component to it and make it connected to the world, stop generating segments and attach the player to the last segment added. Yes, that might actually work, but you will have to figure out the details yourself and it sounds like a ton of work.

    EDIT:
    A few links that might be of use

    http://unity3d.com/support/documentation/ScriptReference/Object.Instantiate.html
    http://unity3d.com/support/documentation/ScriptReference/Transform-parent.html
    http://unity3d.com/support/documentation/ScriptReference/GameObject.AddComponent.html
    http://unity3d.com/support/documentation/ScriptReference/HingeJoint.html
     
    Last edited: Oct 21, 2011
  22. mattbrand

    mattbrand

    Joined:
    Jan 16, 2011
    Posts:
    98
    Hey all. Has anyone translated these scripts into C Sharp? I have it mostly translated, but looping through the hashtable of rope segments is not working for me.
     
  23. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Using a hastabe was a stupid idea in the first place. Just use an array instead, should make things easier overall.
     
  24. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    lol
     
  25. mattbrand

    mattbrand

    Joined:
    Jan 16, 2011
    Posts:
    98
    Actually, that's exactly what I did, and now I have it working. Thanks so much for your example!

    The one thing I have not gotten right is the movement of the rope segments. In your example, they all stay tightly together, bottom of the higher segment attached right to the top of the lower segment. I used all the same variable settings for the segments as your example, but in my scene the rope segments swing properly, but come apart visually, so there are large gaps between them when the player swings.

    Any ideas on why?
     
    Last edited: Jan 17, 2012
  26. mattbrand

    mattbrand

    Joined:
    Jan 16, 2011
    Posts:
    98
    I got it now. I had to adjust the anchor y-coordinate for each rope segment.

    Thank you SO much for posting this. Very helpful. :)
     
  27. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    No problem, that's what I made it for :)
     
  28. Jefemcownage

    Jefemcownage

    Joined:
    May 29, 2012
    Posts:
    8
    mattbrand care to post the c# code?
     
  29. FourthFloor

    FourthFloor

    Joined:
    Aug 3, 2012
    Posts:
    2
    Hey hiphish and Community!

    Thanks for doing this, first of all. the help and code is extraordinarly helpful, im really grateful!
    Im writing this code in C#, and have encountered some issues.

    2 queries.
    First:
    ".JumpOff(rawHorizontalAxis, gameObject); " from line 82 of the Update func of the player code. My Visual Studio is having problems, saying it doesnt recognize it and frankly neither do I. It says "UnityEngine.Component does not contain a JumpOff func, method or extension" or something to that effect. Any Ideas?

    Second:
    The func "LateUpdate" in the climbing/player script is entirely commented. Do I not need that func? should I uncomment the code?

    Thanks very much, sorry if either of these are ridiculous questions.
    FourthFloor
     
  30. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    1) If you look into the scripting reference you see that GetComponent returns a "Component" object, which has no JumpOff function. What you need to do is either cast the returned value into the needed class or use the generic version of GetComponent (which I would recommend)

    Code (csharp):
    1.  
    2. //casting: this tells us to convert the returned value into a certain type
    3. RopeSegmentBehaviour myInstance = (RopeSegmentBehaviour) GetComponent(RopeSegmentBehaviour);
    4.  
    5. //generics: this means we already get the specified type back, no conversion needed
    6. RopeSegmentBehaviour myInstance = GetComponent<RopeSegmentBehaviour>();
    7.  
    Here is a link regarding generic functions. Keep in mind that I posted that stuff ages ago (well, that one year certainly felt like ages to me), I know more today and I use generics all the time:
    http://docs.unity3d.com/Documentation/Manual/GenericFunctions.html
    So why did it work in javaScript to begin with? JavaScript has an option to use dynamic typing, which means you don't need to specify the type of variables, the program keeps track at runtime. Needless to say it hurts performance, which is why no one should ever use it, but back then most examples and tutorials used dynamic typing and newly created javaScripts didn't start with #pragma strict (which forces you to use static typing) already set like they do now.

    2) Yeah, I guess that stuff wasn't needed at all but I didn't delete it since it might have come in handy sometime later (which it didn't). LateUpdate() works similar to Update() but it's called after all the Update() functions have finished. Please understand that that code hasn't been touched in a long time and I haven't been working on the game for months because I have been focusing on getting Grid Framework out. That stuff could do a good rewriting but I have no time for it at the moment.
     
  31. FourthFloor

    FourthFloor

    Joined:
    Aug 3, 2012
    Posts:
    2
    I am getting the error: "NullReferenceException: Object reference not set to an instance of an object" error while coding the 2d rope mechanic. As a result (at least, I assume its as a result) my code isnt working and the character wont child to the rope and thus be able to climb it. The error is at:

    CharacterControlsManager.OnExitRope (UnityEngine.GameObject rope) (at Assets/Standard Assets/Character Controllers/Sources/Scripts/CharacterControlsManager.cs:65) UnityEngine.GameObject:SendMessage(String, Object, SendMessageOptions) RopeSegmentBehavior:OnTriggerExit(Collider) (at Assets/Standard Assets/Character Controllers/Sources/Scripts/RopeSegmentBehavior.cs:31)

    The code works like this. I have one class, RopeSegmentBehaviour, attached to every rope segment. The collider is a trigger. In that class is the code:

    Code (csharp):
    1. public void OnTriggerEnter (Collider collision){
    2.         if (collision == null)
    3.             Debug.LogError("collider enter being read is null");
    4.         if (collision.tag == "Player")
    5.         {
    6.             collision.gameObject.transform.parent.gameObject.SendMessage("OnEnterRope", gameObject, SendMessageOptions.DontRequireReceiver);
    7.             Debug.Log("enterMessageSent!");
    8.         }
    9.  public void OnTriggerExit(Collider collision)
    10.     {
    11.         if (collision == null)
    12.             Debug.LogError("collider exit being read is null");
    13.         if (collision.tag == "Player")
    14.         {
    15.  
    16.             collision.gameObject.transform.parent.gameObject.SendMessage("OnExitRope", gameObject, SendMessageOptions.DontRequireReceiver);
    17.             Debug.Log("exitMessageSent!");
    18.         }
    [

    On the character, I have a component that manages climbing script, called the ClimbingController. I also have a Character Controls Manager class as a component. its set up like this:

    [
    Code (csharp):
    1. System.NonSerialized]
    2.         GroundController walkingScript;
    3.     [System.NonSerialized]
    4.        ClimbingController climbingScript;
    5.  
    6.  void Start () {
    7.       walkingScript = gameObject.GetComponent<GroundController>();
    8.          climbingScript = gameObject.GetComponent<ClimbingController>();
    9.  }//end Start
    10.  
    11. The lines that throw the error are in the CharacterControlsManager class. There is the conditional part of the below if:
    12.  
    13. void OnEnterRope( GameObject rope){ if ((Input.GetAxisRaw("Vertical") != 1  climbingScript.enabled == false) || climbingScript.segmentHashtable.ContainsValue(rope)) { Debug.Log("input.getAxisRaw Vertical did not equal one while the climbingScript was enabled OR we werent on the rope already"); return; }
    And the other error is in this if condition:

    Code (csharp):
    1. void OnExitRope(GameObject rope){
    2.         if (climbingScript.enabled == false)
    3.             return;
    Any help would be awesome.
     
  32. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    null reference exception happen when you try to reference an object that doesn't exist. Take for example
    Code (csharp):
    1.  
    2. myObject.Getcomponent<SphereCollider>().radius = 3.0f;
    3.  
    This will thro up an arror if there is no SphereCollider component added. You cannot change the size of something that does not exist. YOu can make a simple check to see if there is an instance of the object you need to reference:
    Code (csharp):
    1.  
    2. if(myObject.Getcomponent<SphereCollider>() != null))
    3.    myObject.Getcomponent<SphereCollider>().radius = 3.0f;
    4.  
    From your error and skimming your code it seems that you are missing a script (climbingScript) when exiting the rope (you cannot disable something that does not exist) and you don't have a parent when calling OnTriggerExit.
    If you double-click your error message in the console it will jump straight to the line of code that thrwe up the exception, so you can see what caused the null exception. It's not always a good idea to clutter everything with checks, you could miss something and wonder forever why nothing is happening. At least with a null exception you know something is missing.
     
  33. PythonDK

    PythonDK

    Joined:
    Sep 23, 2012
    Posts:
    16
    Being quite new to Unity, this seemed a little complex to me.
    Could you be so kind as to tell me what would be wrong with this approach?

    I haven't written the entire code, so at some points, I just added a comment, describing what I would have the code do there.

    The main thought of it is, that character is already moved by addForce, both sideways and when he jumps (space), and that would still apply even if he was attached to a piece of rope with a hinge joint.

    This would of course have the character hanging on the side of the rope, but I don't really think that is a problem... On the contrary...

    Anyways... Here goes:
    Code (csharp):
    1. var touchingRope : boolean = false;
    2. var attachedToRope : boolean = false;
    3. var ropeStateChange : boolean = true;
    4.  
    5. onCollisionEnter(theCollision : Collision)  {
    6.             if(theCollision.gameObject.name == "Rope")  {   touchingRope = true;
    7. }   }
    8.  
    9. onCollisionExit(theCollision : Collision)   {
    10.             if(theCollision.gameObject.name == "Rope")  {   touchingRope = false;
    11. }   }
    12.  
    13. function Update () {
    14.     if  (Input.GetKeyDown("space")) {   if(touchingRope)    {   AttachToRope ();        }  
    15.                                     if(!touchingRope)
    16.     {   DetachFromRope ();      }   }  
    17.  
    18.     if  (Input.GetAxis("Vertical"))     {   //move in direction of rope
    19. }   }
    20.  
    21.  
    22. AttachToRope () {   if (ropeStateChange)    {
    23. ropeStateChange = false;                                       
    24. attachedToRope = true;                 
    25. //add component hinge joint and attach to rope
    26. yield WaitForSeconds(.3);
    27. ropeStateChange = true;
    28. }   }
    29.  
    30. DetachFromRope ()   {   if (ropeStateChange)    {  
    31. ropeStateChange = false;
    32. attachedToRope = false;                                    
    33. //remove component hinge joint
    34. yield WaitForSeconds(.3);
    35. ropeStateChange = true;
    36.  
    37. }   }
     
  34. runonthespot

    runonthespot

    Joined:
    Sep 29, 2010
    Posts:
    305
    Have you considered using the linerenderer to render the rope? Would be interested to see how it looks with a line instead of capsules.

    Regs,
    Mike
    @Runonthespot
     
  35. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    LineRenderer is only for rendering lines, you still need something tangible like a collider. Capsules seemed like the best choice and since I needed to see what was going on using capsules for visualization made sense. That's not to say thet I would have kept capsules in the final game. LineRenderer seems OK, but mabe some sort of cloth would be better.

    I don't have the time to go over your code, but if you can make it simpler go for it. I was new to Unity and game programing in general when i wrote that code, it was just a proof of concept which I didn't bother updateing since then, there is certainly a lot of room for improvement.
     
  36. ghaddar0292

    ghaddar0292

    Joined:
    Feb 16, 2013
    Posts:
    4
    Hello Hiphish,

    First I would like to thank you for all the scripts you have shared, they have been very helpful to me. I know this is an old thread and you probably have not looked into your scripts for a very long while but I would appreciate it if you can help me with understanding something in your scripts. So I have applied your script and modified it to my needs but I have just used one big collider to cover for the whole rope segmants since I was having troubles understanding what you are trying to do with adding segmants and parenting. It is working as expected and I just need to add that last part to complete it.

    If you can just explain what you are trying to do and how that part of the code is working so I can get a better understanding in order to write my own scripts for my needs. My major problem is how do you avoid constant parenting if the character is colliding with lets say 3 segmants.

    Any help is very much appreciated.

    Thank you again for the scripts.
     
  37. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    I used several colliders to make the rope flexible (actually it's more like a chain than a rope). I think I avoided constant parenting by sorting the colliers by height and storing all the colliders the player is intersecting with in a list
    Code (csharp):
    1.  
    2. List<Transform> segments = new List<Transform>();
    3.  
    4. void OnCollisionEnter (Collision col) {
    5.     segments.Add(col.Transform);
    6.     SetParent ();
    7. }
    8.  
    9. void OnCollisionExit (Collision col) {
    10.     segments.Remove(col.Transform);
    11.     SetParent ();
    12. }
    13.  
    14. void SetParent () {
    15.     // here you would pick the topmost segment form the list
    16.     // then set it as the player's parent
    17. }
    18.  
    (you could do this in UnityScript, but C# has proper support for generic lists, which is faster)

    I'm not sure how exactly to pick the topmost segment, but if everything fails ou could just assign a number to each one manually and pick the highest. Whatever gets the job done.
     
  38. ghaddar0292

    ghaddar0292

    Joined:
    Feb 16, 2013
    Posts:
    4
    Hello hiphish,

    Thank you for your previous answer, my rope is working just fine now. I just have two little questions. How do you limit the swinging so the character will not be able to swing very high, at the moment if he keeps swinging he can make a complete circle. And also if I want to render this rope what method would I use?

    Thank you very much.
     
  39. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Those are both topics I hadn't really thought of back then. You could try limiting the angle of the hinge jooints, the HingeJoint class has that already built in:
    http://docs.unity3d.com/Documentation/ScriptReference/HingeJoint.html
    As for rendering, I really don't know. If you want a chanin just make every segment look like a chain, but it you want it to look like a rope, maybe you could fake it by putting a cloth over the "rope"?
     
  40. ghaddar0292

    ghaddar0292

    Joined:
    Feb 16, 2013
    Posts:
    4
    Regarding the limiting, you are right you can play around with the hinge joint parameters to fine tune it the way you like. About the rendering I will have to try, whenever I figure it out I will post it here for people to know. I appreciate all your help. Thank you.
     
  41. Mastrom

    Mastrom

    Joined:
    Dec 17, 2013
    Posts:
    4
    HI! can u upload the project again? is no longer in rapidshare :S
     
  42. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Sorry, but as I explained in the first post I don't have any of the code anymore.
     
  43. NutellaDaddy

    NutellaDaddy

    Joined:
    Oct 22, 2013
    Posts:
    288
    The game reminded me of Mario mixed with Happy Wheel!
     
  44. Skyboard_Studios

    Skyboard_Studios

    Joined:
    Jul 20, 2013
    Posts:
    51
    As of recently I made a little progress in my own swinging rope. Check it out

    http://www.youtube.com/watch?v=2kowyY7X-vA

    i changed the axis points and it seems to make a nice chain feel. still working out the kinks :)
     
  45. tequyla

    tequyla

    Joined:
    Jul 22, 2012
    Posts:
    335
    Hi,

    any chance to post unipackage of your rope script ?

    regards,

    +++
     
  46. adi99123

    adi99123

    Joined:
    Feb 6, 2015
    Posts:
    5
    Any successfully build this project? I am not able to move upward
     
  47. Hawre

    Hawre

    Joined:
    Jul 25, 2015
    Posts:
    3
    Hello thank you for posting these codes. But these codes error
    If possible, please let us know about the project
    I've been looking for such a system for a long time
    Please download the project for download
     
  48. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    Are you asking me whether I still have the code? I'm afraid I lost it ages ago, it's also stated in the OP. This thread is almost seven years old by now.
     
  49. Hawre

    Hawre

    Joined:
    Jul 25, 2015
    Posts:
    3
    No sorry I'm not good English
    I say put the project here to download
    The codes are in error
     
  50. hiphish

    hiphish

    Joined:
    Nov 13, 2010
    Posts:
    626
    As I said already, I do not have the code anymore. Sorry, but there is nothing left of it.