Search Unity

How to detect if object stopped moving and is in front of another gameobject?

Discussion in 'Scripting' started by Jip1912, Jul 24, 2017.

  1. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    Hi,

    You might not understand the question so I try to make it clear. In my game, you have to jump from cube to cube. If you miss the jump, the cube you're standing on should fall down.
    This is how it looks like:


    I made a script attachted to each cube to controll the movement as seen in this picture:


    The cubes move only in X-axis, the Y-axis is always 0 and the Z=axis is always 1.5 away from the cube before.
    What I want, is that the cube you're standing on, should fall down automatically when you stay on it for too long. I already made it so, that whenever you jump, the cube beneath you will fall down.
    The tricky part is that some cubes should fall down really fast if the player jump on it and some cubes should fall down after a longer time. So I can't just make it so that whenever the player jumps on a cube, it should fall down after x seconds.

    I already tried to make a Fall Down Time (time after the game start when the cubes falls down in seconds). I made it like this:
    Code (CSharp):
    1. fallDownTime = arrivalAtTime + afterArrivalGoToXInSeconds + 0.6f; //after the cube is arrived at the point where the player should jump, the player has 0.6 seconds until the cube falls down.
    This didn't work, because the cube sometimes has to wait with the player on it before the next cube arrives.

    I also tried to make a trigger in front of each cube, that checks if another cube is in front of it. So if there came a cube in the trigger, the cube with the trigger should fall down after around 0.6 seconds for example.


    However, this also didn't work, because sometimes two cubes start on the same X-asis and that would trigger the collider immediately like in the image below.


    So in short, each cube should fall down automatically after a short amount of time (the time a player has to react) when the next cube is arrived, where the player should jump to.
    Why do I want this? Because otherwise, you will never fail the level if you just stay on a cube without jumping like you can see below.
    https://i.gyazo.com/06284f344e6f54c4c4a7119bfb960ed2.mp4

    I understand if you are really confused and don't understand what I mean. Then please ask me.'

    Thanks
     
  2. GameDevJon

    GameDevJon

    Joined:
    Jul 21, 2017
    Posts:
    25
    Assuming the player has a chance to "jump" on the cube before it falls,

    Here's what I would do:

    Create a variable to store the amount of time before falling.

    Set up a coliision on each cube, and when OnTriggerEnter or OnCollisionEnter occurs, check if it's the player. If it is, then start the timer. When the timer (time.deltaTime + 1) becomes greater than the fall time, call the FallMethod().

    Forcing the player to jump to the next cube, and the same will happen.

    If you want to start a chain reaction, where as soon as you step on the first one, they will all fall, then look into a StepManager class, and basically call a function that has a grand timer, and store a list of all steps, and drop them in a sequential order.
     
  3. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    ''When the timer (time.deltaTime + 1) becomes greater than the fall time, call the FallMethod()'' . Then I would still manually need to set a fall time right? I want it to be automatically.
    I have a new idea to make it like this:
    Code (CSharp):
    1. timeUntilNextCube = "next cube's arrivalAtTime"-(arrivalAtTime+afterArrivalGoToXInSeconds)
    2.  
    3. fallDownTime = arrivalAtTime + afterArrivalGoToXInSeconds + timeUntilNextCube + 0.6f;
    But I don't know if this works, because I need to get arrivalAtTime of the next cube. So Cube8 needs to acces the arrivalAtTime of Cube9 and Cube9 needs to get the arrivalAtTime of Cube10. I don't know how I could do that (I know I can assign each cube in the inspector but I would like to have it automatic), do you know?
     
  4. GameDevJon

    GameDevJon

    Joined:
    Jul 21, 2017
    Posts:
    25
    Right. So how can you know "the next cube" ?

    One way is to have a "List" of all the cubes, and have them in order that you can hop to it.

    Then, to get to the "next" cube, you can access the list through it's current iteraiton + 1.
     
  5. MaxiARG

    MaxiARG

    Joined:
    Jul 24, 2017
    Posts:
    10
    i would use corountines. Whenever the guy touches the target cube the corountine starts and stops for X amount of time
    Code (CSharp):
    1.  
    2. IEnumerable methodName(float timeYouWish){
    3. //the trigger was already triggered so..
    4. return new yield waitForSeconds(timeYouWish);
    5. fallingCubeCode;
    6. }
    7. //then you start it with
    8. startCoroutine(methodName
    9. )
     
  6. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    You know about another way to achieve this?

    But then I manually have to set timeYouWish right? Then it's not automated
     
  7. MaxiARG

    MaxiARG

    Joined:
    Jul 24, 2017
    Posts:
    10
    It depends on your design. You would have a method/class that gives you that information based on random numbers, or based on teh cube you are in, or what ever bussines rule you want. Your timeYouWish is based on the cube he is in, right?
     
  8. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    It might. I don't have a working technique yet so I will have to figure it out. See my reply's on @GameDevJon
     
  9. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    I tried this:
    Code (CSharp):
    1. closestCubeArrivalAtTime = player.closestCube.GetComponent<CubeMovement> ().arrivalAtTime;
    2. timeUntilNextCube = closestCubeArrivalAtTime - (arrivalAtTime + afterArrivalGoToXInSeconds);
    3.         fallDownTime = afterArrivalGoToXInSeconds + arrivalAtTime + timeUntilNextCube + 0.6f;
    It doesn't work because you don't need the arrivalAtTime of next's cube, but the cube after that.
     
  10. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    Ok, I made an auto-generated array, but the order of the cubes seems to be just random.


    Now I can't use the +1 thing..
    I searched up how to sort it, but couldn't find a working answer.
     
  11. GameDevJon

    GameDevJon

    Joined:
    Jul 21, 2017
    Posts:
    25
    Inserting them randomly into the list isn't what you wanna do.

    There is a programatic way to sort it how you want, but that's beyond the scope of this.

    Simply, take 5 minutes in the scene and order it how you want. Then you can do the +1 thing
     
  12. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    Yes, I could do that. I am just curious about how I could do this and I like to experiment with it. I like to have as much automated as I can which I made by myself. I asked this array problem on stackoverflow and if I won't get an answer from there, I will just put them in manually. I will let you know if it worked or not.
     
  13. GameDevJon

    GameDevJon

    Joined:
    Jul 21, 2017
    Posts:
    25
    So to do it programtatically, here's a hint for you.

    https://msdn.microsoft.com/en-us/library/system.collections.icomparer(v=vs.110).aspx

    The icomparer interface allows you to do a comparison between two and check if they are less than, greater than , or equal to.

    Check out the examples and see how you can apply this to your needs
     
  14. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    Got it working already:
    - https://stackoverflow.com/questions/45289742/sort-gameobject-array-by-name
    - https://stackoverflow.com/questions/45309318/get-the-position-of-a-gameobject-in-an-array

    I will try to make the fall down system this evening or tommorow.
     
  15. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    It works!
    I actually did need the next cube's arrivalAtTime and not the next next cube.
    It's pretty complicated in my opinion, but it's all automatic like I wanted :)

    AlphanumComparator script to sort the array alphanumeric:

    Code (CSharp):
    1. public class AlphanumComparatorFast : IComparer<string>
    2. {
    3.     public int Compare(string x, string y)
    4.     {
    5.         string s1 = x as string;
    6.         if (s1 == null)
    7.         {
    8.             return 0;
    9.         }
    10.         string s2 = y as string;
    11.         if (s2 == null)
    12.         {
    13.             return 0;
    14.         }
    15.  
    16.         int len1 = s1.Length;
    17.         int len2 = s2.Length;
    18.         int marker1 = 0;
    19.         int marker2 = 0;
    20.  
    21.         // Walk through two the strings with two markers.
    22.         while (marker1 < len1 && marker2 < len2)
    23.         {
    24.             char ch1 = s1[marker1];
    25.             char ch2 = s2[marker2];
    26.  
    27.             // Some buffers we can build up characters in for each chunk.
    28.             char[] space1 = new char[len1];
    29.             int loc1 = 0;
    30.             char[] space2 = new char[len2];
    31.             int loc2 = 0;
    32.  
    33.             // Walk through all following characters that are digits or
    34.             // characters in BOTH strings starting at the appropriate marker.
    35.             // Collect char arrays.
    36.             do
    37.             {
    38.                 space1[loc1++] = ch1;
    39.                 marker1++;
    40.  
    41.                 if (marker1 < len1)
    42.                 {
    43.                     ch1 = s1[marker1];
    44.                 }
    45.                 else
    46.                 {
    47.                     break;
    48.                 }
    49.             } while (char.IsDigit(ch1) == char.IsDigit(space1[0]));
    50.  
    51.             do
    52.             {
    53.                 space2[loc2++] = ch2;
    54.                 marker2++;
    55.  
    56.                 if (marker2 < len2)
    57.                 {
    58.                     ch2 = s2[marker2];
    59.                 }
    60.                 else
    61.                 {
    62.                     break;
    63.                 }
    64.             } while (char.IsDigit(ch2) == char.IsDigit(space2[0]));
    65.  
    66.             // If we have collected numbers, compare them numerically.
    67.             // Otherwise, if we have strings, compare them alphabetically.
    68.             string str1 = new string(space1);
    69.             string str2 = new string(space2);
    70.  
    71.             int result;
    72.  
    73.             if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
    74.             {
    75.                 int thisNumericChunk = int.Parse(str1);
    76.                 int thatNumericChunk = int.Parse(str2);
    77.                 result = thisNumericChunk.CompareTo(thatNumericChunk);
    78.             }
    79.             else
    80.             {
    81.                 result = str1.CompareTo(str2);
    82.             }
    83.  
    84.             if (result != 0)
    85.             {
    86.                 return result;
    87.             }
    88.         }
    89.         return len1 - len2;
    90.     }
    91. }
    Script attached to all cubes:

    Code (CSharp):
    1. [ReadOnly] public GameObject[] allCubes;
    2.     [ReadOnly] public GameObject nextCube;
    3.     private float timeUntilNextCube;  
    4.  
    5. int findIndex(GameObject target)
    6.     {
    7.         for (int i = 0; i < allCubes.Length; i++)
    8.         {
    9.             //If we find the index return the current index
    10.             if (allCubes[i] == target)
    11.             {
    12.                 return i;
    13.             }
    14.         }
    15.         //Nothing found. Return a negative number
    16.         return -1;
    17.     }
    18.  
    19. void Awake()
    20. {
    21. allCubes = GameObject.FindGameObjectsWithTag("cube");
    22.         allCubes = allCubes.OrderBy(obj => obj.name, new AlphanumComparatorFast()).ToArray();
    23.         nextCube = null;
    24.         int index = findIndex(gameObject) + 1;
    25.         if (index < allCubes.Length - 1)
    26.         {
    27.             nextCube = allCubes [index];
    28.             CubeMovement nextCubeScript = allCubes [index].GetComponent<CubeMovement> ();
    29.             timeUntilNextCube = nextCubeScript.arrivalAtTime - (arrivalAtTime + afterArrivalGoToXInSeconds);
    30.         }
    31.         fallDownTime = afterArrivalGoToXInSeconds + arrivalAtTime + timeUntilNextCube + 0.15f;
    32.         fallDownTime = Mathf.Round(fallDownTime * 100f) / 100f;
    33. }
    34.  
    35. void Update()
    36. {
    37. if (Mathf.Approximately((Mathf.Round(timerScript.elapsedTime * 10f) / 10f), fallDownTime))
    38.         {
    39.             iTween.MoveTo (gameObject, iTween.Hash ("y", gameObject.transform.position.y - 15f, "time", 0.8f, "oncomplete", "DeactiveObject", "oncompletetarget", this.gameObject, "easeType", "easeInCubic", "loopType", "none", "delay", 0));
    40.         }
    41. }
    42.  

    I made a video where you can see the result, thanks again for helping :)


     
    RaMaPoTTeR likes this.
  16. GameDevJon

    GameDevJon

    Joined:
    Jul 21, 2017
    Posts:
    25
    Awesome job man!
     
    RaMaPoTTeR likes this.