Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Move Along Colliders

Discussion in 'Scripting' started by jlpeyton, Feb 14, 2020.

  1. jlpeyton

    jlpeyton

    Joined:
    Dec 22, 2017
    Posts:
    57
    Hello,

    I am trying to have the balls drop straight down, collide with the floor, and begin moving to the right. When the balls exit the floor they should start falling but they are getting caught at the edge and will begin moving in the opposite direction. Some will eventually break free and fall. The movement I'm going for is pretty straight forward:
    • Fall straight down when it goes over the edge.
    • Begin moving either left or right when it hits another floor.
    • Bounce and move in the opposite direction when it hits a wall.

    Each cube in the game has two colliders. One for the floor and one for the wall.
    COLLIDER.jpg

    Here's a video showing what's happening:


    Here is my script attached to the ball prefab:
    Code (CSharp):
    1. public class FleaManager : MonoBehaviour
    2. {
    3.     public bool moveRight = false;
    4.     public bool moveLeft = false;
    5.     public bool falling = true;
    6.     public int speed = 3;
    7.  
    8.     // Update is called once per frame
    9.     void Update()
    10.     {
    11.         if (moveRight)
    12.         {
    13.             transform.Translate(Vector2.right * speed * Time.deltaTime);
    14.         }
    15.         else if (moveLeft)
    16.         {
    17.             transform.Translate(Vector2.left * speed * Time.deltaTime);
    18.         }
    19.         else
    20.         {
    21.             transform.Translate(Vector2.down * speed * Time.deltaTime);
    22.         }
    23.        
    24.     }
    25.  
    26.     private void OnCollisionEnter2D(Collision2D collision)
    27.     {
    28.         if (collision.gameObject.tag == "Wall")
    29.         {
    30.             if (moveRight)
    31.             {
    32.                 moveRight = false;
    33.                 moveLeft = true;
    34.             }
    35.             else
    36.             {
    37.                 moveRight = true;
    38.                 moveLeft = false;
    39.             }
    40.         }
    41.         else if (collision.gameObject.tag == "Floor" && falling)
    42.         {
    43.             moveRight = true;
    44.             moveLeft = false;
    45.             falling = false;
    46.         }
    47.     }
    48.  
    49.     private void OnCollisionExit2D(Collision2D collision)
    50.     {
    51.         if(collision.gameObject.tag == "Floor"){
    52.             falling = true;
    53.             moveLeft = false;
    54.             moveRight = false;
    55.         }
    56.        
    57.     }
    58. }

    I'm scratching my head on this trying to figure out if it's an issue with my colliders or if I'm handling the movement in my code the wrong way.
     
    Last edited: Feb 14, 2020
  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    I can not watch your video. Says it's private.

    I'd advice creating a statemachine on paper. If you need full control over the states your program is in, i'd consider building a statemaching on paper and then just implementing that. You currently have tons of bools for such a small problem.
    However, what you want to do seems like a normal physics problem. You want things to fall, move and bounce off. So basically you should only need to set the velocity of your ball to, for example, (1,0) and then reverse that once you hit a wall (while falling). The rest, like falling itself, should be simulated by physics.
     
    Last edited: Feb 14, 2020
  3. jlpeyton

    jlpeyton

    Joined:
    Dec 22, 2017
    Posts:
    57
    The video is now visible.

    I do not want to simulate your typical physics drop where it falls but at an angle. I want it to drop straight down once it reaches the edge so I'm just translating the position up, down, left, and right.
     
  4. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    Even when using physics, you could still set your own custom velocity. In fact, independant of whether you use the build in physics engine for anything, i'd keep track of the velocities you intend to apply by saving them in a vector. That way you can easily flip it when you hit a wall, and could apply vertical and horizontal velocities at the same time, if that ever happened to be part of your game.

    The solution i would go for would look something like this:
    Code (CSharp):
    1. public class FleaManager : MonoBehaviour
    2. {
    3.     [SerializeField] private float speed = 3f;
    4.     [SerializeField] private float sphereRadius = 0.5f; // put correct value here
    5.     private bool falling = false;
    6.     private float facingDirection = 1;
    7.     private Vector2 moveDirection = Vector2.zero;
    8.  
    9.     // Update is called once per frame
    10.     void Update()
    11.     {
    12.         // Use a raycast to determine whether you are falling
    13.         RaycastHit hit = new RaycastHit();
    14.         float distanceToGround = -1f; // impossible default value
    15.         if (Physics.Raycast (transform.position, -Vector2.up, out hit))     {
    16.             // You need to add a check that you actually hit a cube, not a sphere here
    17.             distanceToGround = hit.distance;
    18.          }
    19.         // You may have to play around here a bit
    20.         falling = distanceToGround != -1 && distanceToGround > sphereRadius;
    21.  
    22.         // If distanceToGround > 0 but < sphereRadius, could  correct position as described below
    23.  
    24.         // Determine moving direction based on whether we are falling or not
    25.         if(falling){
    26.             moveDirection = Vector2.down;
    27.         } else{
    28.             moveDirection = new Vector2(facingDirection, 0);
    29.         }
    30.  
    31.         // Finally we apply the moveDirection once
    32.         transform.Translate(moveDirection * speed * Time.deltaTime);
    33.     }
    34.  
    35.     private void OnCollisionEnter2D(Collision2D collision)
    36.     {
    37.         if(collision.gameObject.tag == "Cube"){
    38.             facingDirection = -facingDirection;
    39.         }
    40.     }
    41. }
    Take it as pseudo code as i did not compile it.
    You should get the idea tho. It's also a lot cleaner and generally less code. Currently we can run into the problem that depending on our falling speed and the framerate, balls may stop after already clipping into the ground (same with your solution). That's also one reason why i suggested using the inbuild physics engine to calculate falling and so on, since it already has a lot of helpful stuff build in.
    To manually counteract this you can, for example, detect if the distanceToGround is smaller than the sphereRadius and then set your current position such that the distance would be exactly your sphereRadius.

    As for what's the problem with your approach, i'd say the problem lies in the collisions. It's probably possible to be in both colliders at the same time, or you enter or leave them in the wrong order, causing you to switch directions without actually falling. It's hard to follow with all these bools tho. And that's also why i'd get rid of all the redundant code :)

    Anyways, hope this helps.
     
    Last edited: Feb 15, 2020
  5. jlpeyton

    jlpeyton

    Joined:
    Dec 22, 2017
    Posts:
    57
    Thank you. You are right, it's easier to read without all the booleans. I'm referring to the Physics2D.Raycast documentation to draw a line straight down and check if the raycast collides with anything. It should store the distance in the variable distance. However, distance is returning the value 0 the entire time so falling is immediately set to false, causing the direction to move to the right.

    Code (CSharp):
    1. void Update()
    2.     {
    3.         RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
    4.  
    5.         if(hit.collider != null)
    6.         {
    7.             // Calculate the distance
    8.             distance = Mathf.Abs(hit.point.y - transform.position.y);
    9.         }
    10.  
    11.         if(distance != -1 && distance > floatHeight)
    12.         {
    13.             falling = true;
    14.         }
    15.         else
    16.         {
    17.             falling = false;
    18.         }
    19.  
    20.         // Determine moving direction based on whether we are falling or not
    21.         if (falling)
    22.         {
    23.             moveDirection = Vector2.down;
    24.         }
    25.         else
    26.         {
    27.             moveDirection = new Vector2(facingDirection, 0);
    28.         }
    29.  
    30.         transform.Translate(moveDirection * speed * Time.deltaTime);
    31.         Debug.Log(distance);
    32.     }
     
    TheDevloper likes this.
  6. TheDevloper

    TheDevloper

    Joined:
    Apr 30, 2019
    Posts:
    69
    There is so much if and else statement in your code, i advise you to use methods for visibility.
    Meanwhile you can use bouncing physics and just rigidbody instead of Vector2.down.
     
  7. jlpeyton

    jlpeyton

    Joined:
    Dec 22, 2017
    Posts:
    57
    I'm not going for any bounce type physics. I want the force going down to be the same speed as left and right and it should be straight down. I've adjusted my code and incorporated methods. My issue at the moment is the raycast shooting down is not detecting any objects so hit is always null.

    Code (CSharp):
    1. void Update()
    2.     {
    3.         RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
    4.  
    5.         if(hit.collider != null)
    6.         {
    7.             // Calculate the distance
    8.             distance = Mathf.Abs(hit.point.y - transform.position.y);
    9.         }
    10.  
    11.         falling = isFalling(distance, floatHeight);
    12.  
    13.         moveDirection = calculateDirection(falling);
    14.  
    15.         transform.Translate(moveDirection * speed * Time.deltaTime);
    16.         Debug.Log(distance);
    17.     }
    18.  
    19.     private bool isFalling(float distance, float floatHeight)
    20.     {
    21.         if (distance != -1 && distance > floatHeight)
    22.             return true;
    23.         else
    24.             return false;
    25.     }
    26.  
    27.     private Vector2 calculateDirection(bool falling)
    28.     {
    29.         // Determine moving direction based on whether we are falling or not
    30.         if (falling)
    31.             return Vector2.down;
    32.         else
    33.             return new Vector2(facingDirection, 0);
    34.     }
     
    Last edited: Feb 18, 2020