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. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

[C#] Move through rigidbody?

Discussion in 'Scripting' started by EthanWZech, Jul 3, 2018.

  1. EthanWZech

    EthanWZech

    Joined:
    Feb 25, 2017
    Posts:
    27
    I have this character that, when the player presses an arrow key, I want to move in a singular direction until it hits a wall, after which the player can move again. It also leaves a path behind it. This is part of my script.


    Code (CSharp):
    1.     //Move Character and Stop at Blocks
    2.         //Up
    3.     IEnumerator MoveUp()
    4.     {
    5.         Debug.Log("Moved Upwards");
    6.         stop = false;
    7.         start = true;
    8.         collider.size = new Vector2(0.10f, 0.46f);
    9.         Instantiate(downPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    10.         while (stop == false)
    11.         {
    12.             transform.position = new Vector2(transform.position.x, transform.position.y + 0.32f);
    13.             if (start == true)
    14.             {
    15.                 Instantiate(upPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);            
    16.             }
    17.             if (start == false)
    18.             {
    19.                 Instantiate(verticalPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y - 0.32f), Quaternion.identity, storage.transform);
    20.             }
    21.             start = false;
    22.             yield return null;
    23.         }
    24.         moving = false;
    25.         collider.size = new Vector2(0.32f, 0.32f);
    26.         Instantiate(upPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    27.         StartCoroutine(checkBlocks());
    28.     }
    29.         //Down
    30.     IEnumerator MoveDown()
    31.     {
    32.         Debug.Log("Moved Downwards");
    33.         stop = false;
    34.         start = true;
    35.         collider.size = new Vector2(0.10f, 0.46f);
    36.         Instantiate(upPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    37.         while (stop == false)
    38.         {
    39.             transform.position = new Vector2(transform.position.x, transform.position.y - 0.32f);
    40.             if (start == true)
    41.             {
    42.                 Instantiate(downPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    43.             }
    44.             if (start == false)
    45.             {
    46.                 Instantiate(verticalPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y + 0.32f), Quaternion.identity, storage.transform);
    47.             }
    48.             start = false;
    49.             yield return null;
    50.         }
    51.         moving = false;
    52.         collider.size = new Vector2(0.32f, 0.32f);
    53.         Instantiate(downPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    54.         StartCoroutine(checkBlocks());
    55.     }
    56.         //Left
    57.     IEnumerator MoveLeft()
    58.     {
    59.         Debug.Log("Moved Left");
    60.         stop = false;
    61.         start = true;
    62.         collider.size = new Vector2(0.46f, 0.10f);
    63.         Instantiate(rightPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    64.         while (stop == false)
    65.         {
    66.             transform.position = new Vector2(transform.position.x - 0.32f, transform.position.y);
    67.             if (start == true)
    68.             {
    69.                 Instantiate(leftPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    70.             }
    71.             if (start == false)
    72.             {
    73.                 Instantiate(horizontalPath, new Vector2(gameObject.transform.position.x + 0.32f, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    74.             }
    75.             start = false;
    76.             yield return null;
    77.         }
    78.         moving = false;
    79.         collider.size = new Vector2(0.32f, 0.32f);
    80.         Instantiate(leftPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    81.         StartCoroutine(checkBlocks());
    82.     }
    83.         //Right
    84.     IEnumerator MoveRight()
    85.     {
    86.         Debug.Log("Moved Right");
    87.         stop = false;
    88.         start = true;
    89.         collider.size = new Vector2(0.46f, 0.10f);
    90.         Instantiate(leftPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    91.         while (stop == false)
    92.         {
    93.             transform.position = new Vector2(transform.position.x + 0.32f, transform.position.y);
    94.             if (start == true)
    95.             {
    96.                 Instantiate(rightPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    97.             }
    98.             if (start == false)
    99.             {
    100.                 Instantiate(horizontalPath, new Vector2(gameObject.transform.position.x - 0.32f, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    101.             }
    102.             start = false;
    103.             yield return null;
    104.         }
    105.         moving = false;
    106.         collider.size = new Vector2(0.32f, 0.32f);
    107.         Instantiate(rightPath, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), Quaternion.identity, storage.transform);
    108.         StartCoroutine(checkBlocks());
    109.     }
    110.  
    111.     //If Enter Block, Stop
    112.     private void OnTriggerEnter2D (Collider2D other)
    113.     {
    114.         stop = true;
    115.     }

    The problem with this that I noticed is: usually my character moves normally and everything worked as intended. They moved in units of 0.32 and stopped at walls. The problem was that about every 1/10 times the character would phase into a block, and if the move button was pressed again pass through it. Now I am pretty sure this is because I am moving definitively instead of moving with Unity's physics.


    I can't find any examples of moving in unity without the Input.GetAxis method, and that won't work in my code because the player will only press the button once. Also, I need my character to always occupy spaces that are multiples of 0.32, and I detect this through colliders. So either I need code that will stop exactly at a block, or that can move my character to a multiple of 0.32 after the movement; all of this with physics based movement.

    Can anyone help me? Feel free to ask any questions, and I will provide the full script if needed. I don't need a fully coded answer (though that would be helpful), just someone to point me in the right direction.

    TLDR: Need character to continuously move in one direction through physics, and then occupy a position that is a multiple of 0.32.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,599
    When you set the transform.position of an object, to the Physics system, that is a "teleport." No actual checking is done. Collisions might happen, or not.

    If you want to "move with physics" a specific amount, then use a reference to your RigidBody (or Rigidbody2D) and call the .MovePosition() method. That will cause the physics system to move it for reals, triggering all the right collisions, bounds checking, bouncing, etc.

    As for the snapping on 0.32 boundaries, probably the easiest way is at the end of the movement, re-quantize the individual coordinates (X,Y) to be on 0.32 boundaries. You can re-quantize by first adding a small fudge amount (to make sure you aren't at 0.3199 for instance), then dividing by 0.32, taking the integer value of that, and then multiplying by 0.32 again.

    Code (csharp):
    1. float originalUnquantizedCoordinate = 0.123456f; // however you get this, from transform.position.x maybe?
    2.  
    3. const float Quantization = 0.32f;
    4. const float Fudge = 0.05f;
    5.  
    6. int wholeSteps = (int)(originalUnquantizedCoordinate + Fudge) / Quantization);
    7.  
    8. float quantizedCoodinate = wholeSteps * Quantization;
    Do that for X and for Y obviously, depending on your motion.
     
  3. EthanWZech

    EthanWZech

    Joined:
    Feb 25, 2017
    Posts:
    27
    I thank you for taking the time, and I have some more questions for you.

    I don't really understand how MovePosition() works. Specifically, how can I specify that the character should move left or right, and up or down? I don't understand the example given in the documentation.

    I also don't understand how the math in your example works. At all, honestly. I know it is asking for a bit much, but if you could walk me through in further detail it would be appreciated.
     
  4. xCyborg

    xCyborg

    Joined:
    Oct 4, 2010
    Posts:
    628
    MovePosition() basically teleport you to to Vector3 position with PhysX.
    I think the above example could use rounding instead.

    Code (CSharp):
    1.     public float speed = 10f;
    2.     private new Rigidbody rigidbody;
    3.  
    4.     public float Quantization = 0.32f;
    5.  
    6.     // Use this for initialization
    7.     void Start()
    8.     {
    9.         rigidbody = GetComponent<Rigidbody>();
    10.     }
    11.  
    12.     // Update is called once per frame
    13.     void FixedUpdate()
    14.     {
    15.         var hax = Input.GetAxis("Horizontal");
    16.  
    17.         if (hax > 0f) // Move Right along X
    18.         {
    19.             rigidbody.MovePosition(transform.position + new Vector3(Time.deltaTime * speed * hax, 0, 0));
    20.         }
    21.         else if (hax < 0f) // Move Left along X
    22.         {
    23.             rigidbody.MovePosition(transform.position + new Vector3(Time.deltaTime * speed * hax, 0, 0));
    24.         }
    25.         else // Readjust when input ceased
    26.         {
    27.             var pos = transform.position;
    28.             int roundedSteps = Mathf.RoundToInt(pos.x / Quantization);
    29.  
    30.             pos.x = roundedSteps * Quantization;
    31.             //transform.position = pos; OR
    32.             rigidbody.MovePosition(pos); // Preferably with Interpolate mode in Inspector set to Interpolate
    33.         }
    34.     }
    Can you try that?
     
  5. EthanWZech

    EthanWZech

    Joined:
    Feb 25, 2017
    Posts:
    27
    Thank you for your time, and I have a few questions for you if your are willing to stay and answer them.

    For your movement example wouldn't I have to hold down the left or right arrow to move? My issue is I need it to move continuously with one press of a button, and I don't understand how to do that without Input.getAxis.

    I would also like to know what Interpolate mode is.

    Thank you for your math example, I understand it and it seems to work.
     
  6. xCyborg

    xCyborg

    Joined:
    Oct 4, 2010
    Posts:
    628
    It's easy, you can use an enum and GetKeyDown.

    Code (CSharp):
    1.  
    2. ....
    3.     enum Dir { Idle, Left, Right }
    4.     Dir dir = Dir.Idle;
    5. ....
    6.  
    7.     // Update is called once per frame
    8.     void FixedUpdate()
    9.     {
    10.  
    11.         if (Input.GetKeyDown(KeyCode.LeftArrow)) dir = Dir.Left;
    12.         if (Input.GetKeyDown(KeyCode.RightArrow)) dir = Dir.Right;
    13.  
    14.         // Whatever condition you set for stop, for example:
    15.         if (Input.GetKeyDown(KeyCode.Space)) dir = Dir.Idle;
    16.  
    17.         if (dir == Dir.Left)
    18.         {
    19.             rigidbody.MovePosition(transform.position + new Vector3(-Time.deltaTime * speed, 0, 0));
    20.         }
    21.         else if (dir == Dir.Right)
    22.         {
    23.             rigidbody.MovePosition(transform.position + new Vector3(Time.deltaTime * speed, 0, 0));
    24.         }
    25.  
    26.         else if (dir == Dir.Idle) // Readjust when idle condition
    27.         {
    28.             var pos = transform.position;
    29.             int wholeSteps = Mathf.RoundToInt(pos.x / Quantization);
    30.  
    31.             pos.x = wholeSteps * Quantization;
    32.             //transform.position = pos; OR
    33.             rigidbody.MovePosition(pos); // Preferably with Interpolate mode in Inspector set to Interpolate
    34.         }
    35.     }
    Maybe you want to optimize the idle clause to run only once.
    Here is the doc page on rigidbody interpolation: https://docs.unity3d.com/ScriptReference/Rigidbody-interpolation.html
    Hope that helps.
     
    Kurt-Dekker likes this.
  7. EthanWZech

    EthanWZech

    Joined:
    Feb 25, 2017
    Posts:
    27
    Sorry that it has taken me until now to respond to you.

    Your code worked perfectly, and I know understand how MovePosition works, thank you. I also managed to use your rounding code to get my trails to work with the new movement system. You've truly given me a new foundation to stand on, and I thank you for that.
     
    Kurt-Dekker and xCyborg like this.
  8. xCyborg

    xCyborg

    Joined:
    Oct 4, 2010
    Posts:
    628
    You're welcome, glad I could be of help ;)
     
    EthanWZech likes this.