Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

C# getting an object to work like a net.

Discussion in 'Scripting' started by clearrose, Sep 12, 2015.

  1. clearrose

    clearrose

    Joined:
    Oct 24, 2012
    Posts:
    349
    We are trying to get the player caught by a net thats dropping from above.
    We have tried numerous approaches. When the net hits it goes though the player and the player can ether goes up or down through the net. But he never goes in the net. We adjusted the animation many times. It Works sporadicly. We would like to have it work everytime.

    1. The player has a box collider2D and the net has 3 box Colliders forming the shape of a upside down U (note: We saw on a digital tutors tutorial that multiple colliders shouldn't cause a problem). The net is suppose to catch the player and the player dies. But, the player pushes past the nets colliders (Note: The net and player are both being moved by rigid bodies) and keeps moving up with the force of the players mouse click and then down and dies. To fix this we've tried stopping the players rigidbody using viva c# with :

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. using System.Collections;
    4.  
    5. public class NetsManager : MonoBehaviour {
    6.  
    7.     public Animator Netanimator; //Animator for the nets that will capture the player.
    8.     public Vector2 movePlayer;
    9.     public Collider2D NetCollider;
    10.  
    11.     void Start()
    12.     {
    13.         NetCollider.enabled = true;
    14.     }
    15.  
    16.     public void OnTriggerEnter2D(Collider2D other)
    17.     {
    18.         //Debug.Log ("Turtle has entered the coillider");
    19.         // if the player has collided with the net.
    20.         if (other.tag == "Player")
    21.         {
    22.             NetCollider.enabled = true;
    23.  
    24.             other.GetComponent<Rigidbody2D> ().MovePosition(Vector2.down - movePlayer * Time.unscaledDeltaTime); //Stop the velocity of the object taged player.
    25.             //Debug.Log("Turtle is caught in net");
    26.          
    27.             //other.GetComponent<Rigidbody2D> ().drag = 10; //increase the drag appiled to the rigidbody of the player.
    28.      
    29.             Invoke("StopNetAnimator", 2f); //start the void stop net animator in 2 sceonds.
    30.         }
    31.     }
    32.  
    33.     public void StopNetAnimator ()
    34.     {
    35.         NetCollider.enabled = true;
    36.  
    37.         Netanimator.enabled = false; //the net's animation is now disabled. Since player is caught, the net's animator has no reason to countine to the end of the animation clip.
    38.         //Debug.Log("Net animator is disabled");
    39.     }
    40. }
    41.  


    2. Also we have tried this script from the unity wiki for a object not being able to go through colliders:


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class DontGoThroughWalls : MonoBehaviour {
    5.  
    6.     // Careful when setting this to true - it might cause double
    7.     // events to be fired - but it won't pass through the trigger
    8.     public bool sendTriggerMessage = false;  
    9.  
    10.     public LayerMask layerMask; //make sure we aren't in this layer
    11.     public float skinWidth = 0.1f; //probably doesn't need to be changed
    12.  
    13.     private float minimumExtent;
    14.     private float partialExtent;
    15.     private float sqrMinimumExtent;
    16.     private Vector3 previousPosition;
    17.     private Rigidbody2D myRigidbody;
    18.     public Collider2D MyCollider;
    19.  
    20.  
    21.     //initialize values
    22.     void Start ()
    23.     {
    24.         myRigidbody = GetComponent<Rigidbody2D> ();
    25.         previousPosition = myRigidbody.position;
    26.         minimumExtent = Mathf.Min(Mathf.Min(MyCollider.bounds.extents.x, MyCollider.bounds.extents.y), MyCollider.bounds.extents.z);
    27.         partialExtent = minimumExtent * (1.0f - skinWidth);
    28.         sqrMinimumExtent = minimumExtent * minimumExtent;
    29.     }
    30.  
    31.     void FixedUpdate()
    32.     {
    33.         //have we moved more than our minimum extent?
    34.         Vector3 movementThisStep = (Vector3)myRigidbody.position - previousPosition;
    35.         float movementSqrMagnitude = movementThisStep.sqrMagnitude;
    36.      
    37.         if (movementSqrMagnitude > sqrMinimumExtent)
    38.         {
    39.             float movementMagnitude = Mathf.Sqrt(movementSqrMagnitude);
    40.             RaycastHit hitInfo;
    41.          
    42.             //check for obstructions we might have missed
    43.             if (Physics.Raycast(previousPosition, movementThisStep, out hitInfo, movementMagnitude, layerMask.value))
    44.             {
    45.              
    46.                 if (!hitInfo.collider)
    47.                     return;
    48.              
    49.                 if (hitInfo.collider.isTrigger)
    50.                     hitInfo.collider.SendMessage("OnTriggerEnter", MyCollider);
    51.              
    52.                 if (!hitInfo.collider.isTrigger)
    53.                     myRigidbody.position = hitInfo.point - (movementThisStep / movementMagnitude) * partialExtent;
    54.  
    55.             }
    56.         }
    57.      
    58.         previousPosition = myRigidbody.position;
    59.     }
    60. }
    61.  
    3. Another attempt that was unsuccessful was when we were trying to add force to the nets rigidbody, in theory pulling the player down and keeping him in the net.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. using System.Collections;
    4.  
    5. public class MoveNetCoillsions : MonoBehaviour {
    6.  
    7.     public Rigidbody2D NetColliders; // rigidbody of the net.
    8.     public float NetCoillidersSpeed = -2f; // speed of the coillders on the net as they fall towards the player.
    9.  
    10.     // Update is called once per frame
    11.     void Update ()
    12.     {
    13.         NetColliders.velocity = new Vector2(0, NetCoillidersSpeed * Time.deltaTime); // Add movement to the net's colliders.
    14.         NetColliders.AddForce(new Vector2(0, -4)* NetCoillidersSpeed * Time.deltaTime); // Addforce to the net's colliders to ensure that the player doesn't go though the colliders.
    15.     }
    16. }

    4. Plus, we tried to make the net like as if it was a magnet attraching the player when caught within a certain radius.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. using System.Collections;
    4.  
    5. public class NetMagnet : MonoBehaviour {
    6.  
    7.     public LayerMask m_MagneticLayers;
    8.     public Vector3 m_Position;
    9.     public float m_Radius;
    10.     public float m_Force;
    11.  
    12.     void FixedUpdate ()
    13.     {
    14.         Collider[] colliders;
    15.         Rigidbody rigidbody;
    16.      
    17.         colliders = Physics.OverlapSphere (transform.position + m_Position, m_Radius, m_MagneticLayers);
    18.         foreach (Collider collider in colliders)
    19.         {
    20.             rigidbody = (Rigidbody) collider.gameObject.GetComponent (typeof (Rigidbody));
    21.             if (rigidbody == null)
    22.             {
    23.                 continue;
    24.             }
    25.             rigidbody.AddExplosionForce (m_Force * -1, transform.position + m_Position, m_Radius);
    26.         }
    27.     }
    28.  
    29.     void OnDrawGizmosSelected ()
    30.     {
    31.         Gizmos.color = Color.red;
    32.         Gizmos.DrawWireSphere (transform.position + m_Position, m_Radius);
    33.     }
    34. }
    35.  

    5. Then we tried to use the newer feature the point effector to keep the player in the net. That didn't work.



    6. We also tried using another type of collider, the edge collider. There was one point we we had multiple edge colliders on the net. That didn't work ether.

     
    Last edited: Sep 14, 2015
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    Well I have to applaud your thoroughness... what a great series of attempts, and I'm sorry that it isn't working. This type of post is precisely the best kind for forum answers.

    One other thing to look into is setting the Collision detection on the Rigidbody(s) to be Continuous instead of Discrete. With relative motion, you would have to make all Rigidbodies use this, which may impose performance penalties.

    Perhaps what might solve your problem is to have code that constantly considers each "segment" of your U-shaped net as a discrete line segment, and always checks each prospective motion of the player to see if some part of them "crosses" that net. When it does, you would immediately make a fixed or hinge joint that joins the player up to the closest segment of the net that he hit, and then turns off gravity on the player.

    The problem I see with this is that the player will be "fixed" to the net via the hinge, but I don't know if he could still "rotate around" and fall through it. You MIGHT need to proxy the player to a new rigid body that is precisely AT the net's rigid body, or else turn OFF the player's rigidbody and increase the weight of the RigidBody that he is linked to by an amount to simulate him "lying" in the net, and then have some other type of script to keep him "cradled" above it.

    It's a tough problem... I hope my ideas help you out. When all is said and done, I would be curious to see how you solve it.
     
  3. clearrose

    clearrose

    Joined:
    Oct 24, 2012
    Posts:
    349
    The hinge joint was a good idea, unfortunately it didn't work. Also the "Proxy" Rigibody2D didn't work, unless I did something wrong. So can you expand your explain on the "proxy" Rigibody?
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    I was assuming you can succeed in checking with the line segments, right? Like prevent it passing through by mathematically checking the players current and subsequent location for passing through your "fence" of segments.

    Assuming you can hard-detect "The player is trying to pass through link X", then you would create a blank GameObject at that point, fixed-hinge-attach it to the net's body at (0,0,0) relative, and set its weight to the player's weight, so the net has a "dent" in it.

    Then over on the player, remove its rigidbody, and have a script that constantly keeps the player "hovering" at some fixed "upwardness" from the net anchor that contains the extra rigidbody.

    When you jump, just unparent the player from the proxy, add a new rigidbody, then delete the temporary weight that was attached to the net and send the player leaping.

    Does that make more sense?? No idea if it would work, but it might be something to try. And you can single-step debug it in the editor and see if what you think should be happening actually is happening.
     
  5. clearrose

    clearrose

    Joined:
    Oct 24, 2012
    Posts:
    349
    By checking the line segments, do you mean using ray casting to check and see if the player has left the area of the nets box collider? If not please advise.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    Since it is a series of line segments (the net in 2D), do first a check to see if you are within the total bounds of the net (like an AABB check), then iterate each of the line segments against the line segment of your current and proposed location (position to position+speed*deltaTime)
     
  7. clearrose

    clearrose

    Joined:
    Oct 24, 2012
    Posts:
    349

    After some time working on this I finally got it to work with the distance joint. Now, we are running into another problem for this to work during runtime. Our nets are instantiated so the distance joint ( thats connected to the player) needs to connect to the spawned instance of the net and it's not. Does anyone know how to get the distance joint to connect to a rigid body that is instantiated ?

    Nets Manager:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class NetsManager : MonoBehaviour {
    5.    
    6.     public Rigidbody2D NetBody;
    7.     private Rigidbody2D PlayerBody;
    8.     private GameObject SecondaryPlayerBody;
    9.     private DistanceJoint2D PlayerDistance;
    10.     private MoveNetCoillsions movenetcoillsions;
    11.     private PlayerManager playermanager;
    12.  
    13.     void Awake()
    14.     {
    15.         movenetcoillsions = GetComponent<MoveNetCoillsions> ();
    16.  
    17.         playermanager = GameObject.Find ("Player").GetComponent<PlayerManager> ();
    18.  
    19.         PlayerBody = GameObject.Find ("Player").GetComponent<Rigidbody2D> ();
    20.  
    21.         SecondaryPlayerBody = GameObject.Find ("SecondaryPlayerBody");
    22.  
    23.         PlayerDistance = GameObject.Find ("SecondaryPlayerBody").GetComponent<DistanceJoint2D> ();
    24.  
    25.         PlayerDistance.enabled = false;
    26.  
    27.         movenetcoillsions.enabled = true;
    28.     }
    29.  
    30.     public void OnTriggerEnter2D(Collider2D other)
    31.     {
    32.         // if the player has collided with the net.
    33.         if (other.tag == "Player")
    34.         {
    35.             movenetcoillsions.NetCoillidersSpeed = -240;
    36.  
    37.             PlayerDistance.enabled = true;
    38.  
    39.             PlayerBody.isKinematic =true;
    40.            
    41.             other.GetComponent<Rigidbody2D>().velocity = new Vector2(0, 0);
    42.  
    43.             other.GetComponent<Rigidbody2D>().angularDrag = 0;
    44.  
    45.             other.GetComponent<Rigidbody2D>().drag = 0;
    46.  
    47.             other.GetComponent<Rigidbody2D>().isKinematic = true;
    48.  
    49.             Invoke("StopNetAnimator", 2.5f); //start the void stop net animator in 2 sceonds.
    50.         }
    51.     }
    52.  
    53.     public void StopNetAnimator ()
    54.     {
    55.         NetBody.velocity = new Vector2 (0, 0);
    56.  
    57.         NetBody.isKinematic = true;
    58.  
    59.         NetBody.angularDrag = 0;
    60.  
    61.         NetBody.drag = 0;
    62.  
    63.         NetBody.gravityScale = 0;
    64.  
    65.         movenetcoillsions.enabled = false;
    66.  
    67.         //Debug.Log ("Net is stopped");
    68.  
    69.         Invoke ("MoveNet", 2f);
    70.     }
    71.  
    72.     public void MoveNet()
    73.     {
    74.         SecondaryPlayerBody.SetActive (false);
    75.        
    76.         PlayerDistance.enabled = false;
    77.  
    78.         NetBody.isKinematic = false;
    79.  
    80.         if (playermanager.IsDead == false)
    81.         {
    82.             NetBody.velocity = new Vector2 (-1, 0);
    83.             //Debug.Log("Net is Moving");
    84.         }
    85.  
    86.         else if (playermanager.IsDead == true)
    87.         {
    88.             NetBody.velocity = new Vector2 (0, 0);
    89.             //Debug.Log("Net is static");
    90.  
    91.             PlayerBody.isKinematic = false;
    92.  
    93.             PlayerBody.velocity = new Vector2 (0, 0);
    94.         }
    95.     }
    96. }
    97.  
    Parts of relevant code in Player Manager:

    Code (CSharp):
    1. public Rigidbody2D NetsBody;
    Code (CSharp):
    1.  //Revives the submarine
    2.     public void Revive()
    3.     {
    4.         StartCoroutine("ReviveProcess");
    5.         GetComponent<Animator>().Play("SwimmingTurtlePlayer");
    6.         GetComponent<BoxCollider2D> ().enabled = true;
    7.         IsDead = false;
    8.         //Debug.Log ("player is alive");
    9.         NetsBody.velocity = new Vector2 (-1, 0);
    10.         //Debug.Log ("Net Is Moving");
    11.         Time.timeScale = 1.0f;
    12.         TurtleBackgroundOffset2.enabled = true;
    13.         Turtle.isKinematic = false;
    14.         normalCollider.enabled = true;
    15.         //BackgroundStop.enabled = true;
    16.         BackgroundStop.speed = 1.0f;
    17.         //Waterline.enabled = true;
    18.         Waterline.speed = 1.0f;
    19.         Waterline2.speed = 1.0f;
    20.         AirBar script = gameObject.GetComponent<AirBar>();
    21.         if (script.Airbar.fillAmount <= 0f)
    22.         {
    23.             script.Start ();
    24.         }
    Code (CSharp):
    1.  if (distance < 0.25f)
    2.             {
    3.                 //Enable smoke emission
    4.                smoke.enableEmission = true;
    5.  
    6.                 if (GameObject.Find("NetCollision"))
    7.                 {
    8.                     smoke.enableEmission = false;
    9.                     StartCoroutine(BubbleTime());
    10.                 }
    Code (CSharp):
    1. IEnumerator BubbleTime ()
    2.     {
    3.         bubbles.enableEmission = true;
    4.         bubbles.Play ();
    5.  
    6.         yield return new WaitForSeconds (2f);
    7.  
    8.         bubbles.enableEmission = false;
    9.         bubbles.Stop ();
    10.     }
    Settings:

    player





    Second Rigidbody





    Net



     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,520
    With all you have got there, I recommend you step through the relevant code paths with the debugger to try and suss out where it is failing exactly, whether it is an unexpected result, the wrong object, the function simply not getting called, etc.
     
  9. clearrose

    clearrose

    Joined:
    Oct 24, 2012
    Posts:
    349
    Thank very much we got this to work like a charm.