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

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:

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

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.

‘‘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:

timeUntilNextCube = "next cube's arrivalAtTime"-(arrivalAtTime+afterArrivalGoToXInSeconds)

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?

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.

i would use corountines. Whenever the guy touches the target cube the corountine starts and stops for X amount of time

IEnumerable methodName(float timeYouWish){
//the trigger was already triggered so..
return new yield waitForSeconds(timeYouWish);
fallingCubeCode;
}
//then you start it with
startCoroutine(methodName
)

You know about another way to achieve this?

But then I manually have to set timeYouWish right? Then it’s not automated

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?

It might. I don’t have a working technique yet so I will have to figure it out. See my reply’s on @SubZeroGaming

I tried this:

closestCubeArrivalAtTime = player.closestCube.GetComponent<CubeMovement> ().arrivalAtTime;
timeUntilNextCube = closestCubeArrivalAtTime - (arrivalAtTime + afterArrivalGoToXInSeconds);
        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.

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.

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

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.

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

Got it working already:

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

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 :slight_smile:

AlphanumComparator script to sort the array alphanumeric:

public class AlphanumComparatorFast : IComparer<string>
{
    public int Compare(string x, string y)
    {
        string s1 = x as string;
        if (s1 == null)
        {
            return 0;
        }
        string s2 = y as string;
        if (s2 == null)
        {
            return 0;
        }

        int len1 = s1.Length;
        int len2 = s2.Length;
        int marker1 = 0;
        int marker2 = 0;

        // Walk through two the strings with two markers.
        while (marker1 < len1 && marker2 < len2)
        {
            char ch1 = s1[marker1];
            char ch2 = s2[marker2];

            // Some buffers we can build up characters in for each chunk.
            char[] space1 = new char[len1];
            int loc1 = 0;
            char[] space2 = new char[len2];
            int loc2 = 0;

            // Walk through all following characters that are digits or
            // characters in BOTH strings starting at the appropriate marker.
            // Collect char arrays.
            do
            {
                space1[loc1++] = ch1;
                marker1++;

                if (marker1 < len1)
                {
                    ch1 = s1[marker1];
                }
                else
                {
                    break;
                }
            } while (char.IsDigit(ch1) == char.IsDigit(space1[0]));

            do
            {
                space2[loc2++] = ch2;
                marker2++;

                if (marker2 < len2)
                {
                    ch2 = s2[marker2];
                }
                else
                {
                    break;
                }
            } while (char.IsDigit(ch2) == char.IsDigit(space2[0]));

            // If we have collected numbers, compare them numerically.
            // Otherwise, if we have strings, compare them alphabetically.
            string str1 = new string(space1);
            string str2 = new string(space2);

            int result;

            if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
            {
                int thisNumericChunk = int.Parse(str1);
                int thatNumericChunk = int.Parse(str2);
                result = thisNumericChunk.CompareTo(thatNumericChunk);
            }
            else
            {
                result = str1.CompareTo(str2);
            }

            if (result != 0)
            {
                return result;
            }
        }
        return len1 - len2;
    }
}

Script attached to all cubes:

[ReadOnly] public GameObject[] allCubes;
    [ReadOnly] public GameObject nextCube;
    private float timeUntilNextCube;   

int findIndex(GameObject target)
    {
        for (int i = 0; i < allCubes.Length; i++)
        {
            //If we find the index return the current index
            if (allCubes[i] == target)
            {
                return i;
            }
        }
        //Nothing found. Return a negative number
        return -1;
    }

void Awake()
{
allCubes = GameObject.FindGameObjectsWithTag("cube");
        allCubes = allCubes.OrderBy(obj => obj.name, new AlphanumComparatorFast()).ToArray();
        nextCube = null;
        int index = findIndex(gameObject) + 1;
        if (index < allCubes.Length - 1)
        {
            nextCube = allCubes [index];
            CubeMovement nextCubeScript = allCubes [index].GetComponent<CubeMovement> ();
            timeUntilNextCube = nextCubeScript.arrivalAtTime - (arrivalAtTime + afterArrivalGoToXInSeconds);
        }
        fallDownTime = afterArrivalGoToXInSeconds + arrivalAtTime + timeUntilNextCube + 0.15f;
        fallDownTime = Mathf.Round(fallDownTime * 100f) / 100f;
}

void Update()
{
if (Mathf.Approximately((Mathf.Round(timerScript.elapsedTime * 10f) / 10f), fallDownTime))
        {
            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));
        }
}

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

https://www.youtube.com/watch?v=lR9AAn1OMfw

1 Like

Awesome job man!

1 Like