Search Unity

Cube walking?

Discussion in 'Scripting' started by Mothil, Jan 10, 2017.

  1. Mothil

    Mothil

    Joined:
    Jan 14, 2014
    Posts:
    434
    While browsing the app store yesterday to find myself some new inspiration, I came across a game called "Hocus". It's a simple game that features a cube walking in the direction you slide your finger, and I found this to be quite fun. I ended up trying to code that sort of walking behaviour myself, but found it to be a lot harder than it looks.



    Any idea how I can effectively achieve walking like this? The closest I've gotten to the desired behaviour is something like this:


    Code (CSharp):
    1.     private float x;
    2.  
    3.     void Update () {
    4.         if (x < 90) {
    5.             x++;
    6.         }
    7.  
    8.         transform.rotation = Quaternion.Euler(x, 0, 0);
    9.     }
    10.  
    Which does turn it almost 90 degrees, but since it's a float, it ends up on 89.981. It also doesn't lift the cube as it walks. Is this actually a lot harder to achieve than it looks, or am I missing something? :)
     
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
  3. Mothil

    Mothil

    Joined:
    Jan 14, 2014
    Posts:
    434
    Would it be a valid option to change the pivot point every 90 degrees? Cause RotateAround will achieve the desired effect for the first flip, but after that it'll just continue rotating around that point.
     
  4. JoeMcDowall

    JoeMcDowall

    Joined:
    Sep 12, 2013
    Posts:
    64
    Could you give the cube a parent, perform the rotation in local space and then once it completes shift the cube back to the center and shift the parent forward by the same amount? Effectively resetting it but having it moved forward by one sides length. Then you could just repeat this function indefnitely in any direction as long as you use the correct axis in RotateAround.

    There may be a more clever solution, but this is the first one that came to my mind.
     
  5. JoeMcDowall

    JoeMcDowall

    Joined:
    Sep 12, 2013
    Posts:
    64
    On second thought, just offsetting the axis in RotateAround based on your current position would be simpler.
     
  6. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,443
  7. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    I've experimented a bit and here is the result:

    It's quicker to show the code than explaining it, so here it is:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Cube : MonoBehaviour
    5. {
    6.  
    7.     public float tumblingDuration = 0.2f;
    8.  
    9.     void Update()
    10.     {
    11.         var dir = Vector3.zero;
    12.  
    13.         if (Input.GetKey(KeyCode.UpArrow))
    14.             dir = Vector3.forward;
    15.  
    16.         if (Input.GetKey(KeyCode.DownArrow))
    17.             dir = Vector3.back;
    18.  
    19.         if (Input.GetKey(KeyCode.LeftArrow))
    20.             dir = Vector3.left;
    21.  
    22.         if (Input.GetKey(KeyCode.RightArrow))
    23.             dir = Vector3.right;
    24.  
    25.         if (dir != Vector3.zero && !isTumbling)
    26.         {
    27.             StartCoroutine(Tumble(dir));
    28.         }
    29.     }
    30.  
    31.     bool isTumbling = false;
    32.     IEnumerator Tumble(Vector3 direction)
    33.     {
    34.         isTumbling = true;
    35.  
    36.         var rotAxis = Vector3.Cross(Vector3.up, direction);
    37.         var pivot = (transform.position + Vector3.down * 0.5f) + direction * 0.5f;
    38.  
    39.         var startRotation = transform.rotation;
    40.         var endRotation = Quaternion.AngleAxis(90.0f, rotAxis) * startRotation;
    41.  
    42.         var startPosition = transform.position;
    43.         var endPosition = transform.position + direction;
    44.  
    45.         var rotSpeed = 90.0f / tumblingDuration;
    46.         var t = 0.0f;
    47.  
    48.         while (t < tumblingDuration)
    49.         {
    50.             t += Time.deltaTime;
    51.             if( t < tumblingDuration)
    52.             {
    53.                 transform.RotateAround(pivot, rotAxis, rotSpeed * Time.deltaTime);
    54.                 yield return null;
    55.             }
    56.             else
    57.             {
    58.                 transform.rotation = endRotation;
    59.                 transform.position = endPosition;
    60.             }
    61.         }
    62.  
    63.         isTumbling = false;
    64.     }
    65. }
     
    Last edited: Aug 29, 2018
    quadbox, khrysller, rahul_ak and 7 others like this.
  8. Mothil

    Mothil

    Joined:
    Jan 14, 2014
    Posts:
    434
    I'm amazed at how effectively you solved this, ericbegue. It's.. It's like magic. :eek:
     
  9. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    only thing I would point out is that that code will only work on a flat plane, the original vid has a more complex environment with the cube tumbling across "walls" and the like; you might need to replace line 37 with something a little more in depth to check what plane it's rotating on as well.
     
  10. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    I could explain how it works, if there are some lines that are not clear enough.

    It's essentially that:
     
    KUFgoddess and Mothil like this.
  11. Phoenix7

    Phoenix7

    Joined:
    Mar 18, 2014
    Posts:
    22
    creat script! I want to rotate the dice 3 or 5 times when i press the keys. But wenn I add *3 after the calling, like so:
    dir = Vector3.forward * 3; the dice jump directly 3 times in the direction. It will not rolling 3 times 1 side of the dice..
    when i add a while or a fornext loop, nothing happens and the dice not rolling.. :-( Do you have a idea for the solution?
    sry for my bad english, but I hope you understand my question. THX