If function not working (transform.position.y related)

Context: The 1st If function has the player start the game by touching the screen once. After which, the touch input is "disabled" until after a few player sprite animation and position changes.

The problem: In the 2nd If function I am trying to have the player sprite fall to a certain height before having it jump back up. This hasn't gone to plan as nothing is triggering in the 2nd If function. Honestly not sure what the error is after trying a few iterations.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller : MonoBehaviour
{
    private Animator anim;
    private Rigidbody2D rb2d;
    private bool inputEnabled = true;
    void Start()
    {
        anim = GetComponent<Animator>();
        rb2d = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        foreach (Touch t in Input.touches) {
            if (inputEnabled == true) {
                rb2d.velocity = new Vector2(3f, 5f);
                anim.SetBool("isOnGround", false);
                inputEnabled = false;
                }
            }
        if (transform.position.y <= -5.5f) {
                anim.SetBool("isFlying", true);
                transform.Translate(0 , 2*Time.deltaTime, 0);
        }
    }
}

Generally, it would be great if you included what happens, or does not happen. There is not a lot that could go wrong with transform.position.y <= -5.5f. So the if statement certainly should be working. The contents may not.

If anim.SetBool does 'not work', check if 'isFlying' is spelled correctly and exists. Capitalization matters.

Also, be aware that you currently describe behavior which makes the object go upwards if it's below -5.5f, but this is only true until it reaches -5.5f, so the statement will only be true for one frame or so. If the object is affected by gravity, it will then fall below the -5.5f treshshold and trigger the if-statement again, making it rise to -5.5f again and so on. You get the picture, effectively, the described behavior currently is "fall to -5.5f, then stay there", which, if desired, can be achieved more easily. From what you wrote i believe you want it to fall to -5.5f, then stop falling and instead rise to.. some other coordinate. If you want to do something like this, take a look into state machines.

Also transform.position refers to the gameobjects position the script is attached to. The script is called Controller.. so i'm not sure it should move at all. Is it actually attached to the correct object you are refering to?

Last but not least, since it's a bit offtopic: you do not need to compare bools to true or false. They themselves are truth-values. So if(someBool == true) is the same as if(someBool), and if(someBool == false) is the same as if(!someBool).

Thanks for the detailed reply! I will look into state machines.

What happens currently is that the sprite continues to free fall beyond the -5.5f point without anything happening. I've checked and "isFlying" does exist and is spelled correctly.

Sorry, I didn't quite catch this explanation. Regarding the issue of going below -5.5f point, wouldn't the "less than" sign ensure that the If statement applied to a wider range of conditions (anything below -5.5f) than just a few frames.

"transform.Translate(0 , 2*Time.deltaTime, 0);" was originally "rb2d.velocity = new Vector2("something");". I changed it as I wasn't sure what the problem was.

The script is attached to the right GameObject. Also, I do get the bool thing haha but I just wanted it to be more explicit for myself as I'm new to coding.

Thanks for the prompt reply. Really appreciate it.


I probably did a bad job explaining what i meant. Let's say you are at -5.4. We move down due to gravity and end up at -5.55, now your if condition is true, meaning we apply a translation upwards, bringing us at some value slightly above -5.5 (in one or a few frames). As soon as we translated to above -5.5, the condition is not true anymore, thus we do not further translate upwards and other forces, like gravity, pull us down again, meaning we will sink down to < -5.5 again.. then rise a bit, then sink again and so on. So basically, we "stay" at -5.5, or more precisely we hover around that position by a tiny margin. Hope this makes more sense.
Potential fixes are setting the velocity, or using a statemachine. Both would prevent the upwards movement to stop just because the initial <= -5.5 condition was not true anymore. Setting the velocity is probably fine.


That's fine, i just wanted to mention it ;)
I too had some habits like that until i felt comfortable.

After line 24 in the example above, please add a Debug.Log(transform.position.y); to see what the position of the actual object is. Inside the if-statement below add a Debug.Log("ENTERED"); to see if you actually enter the statement. In case you did not yet know, Debug.Log is a helpful tool to print informations to the console. Use this to check if the object position is what you think it is, and to see if the if-statement gets entered when you think it should be.
If both of these work as expected, ie you see a 'ENTERED' in the console after reaching -5.5, i assume that 2*Time.deltaTime may simply not be enough to slow your fall in a noticable way. But since you set velocity before and had the same problem, i'm not sure. Just translate it by some larger number, like 5, for testing purposes. If the if-statement gets entered, this should work.

One last thing. You do not have any other exceptions in your console, do you? An exception can cause following code to be skipped. You should always fix all exceptions before questioning unexpected behavior.

Edit:
I found some time to do some testing with your code, and it should work as expected. The translation is indeed way too small to cancel your fall speed. You'd either need to set the velocity to 0 and then translate, or directly set the velocity to an upwards value, as shown below. I dont know why this did not work when you tested it, but it should. Does it work for you this way?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller : MonoBehaviour
{
    private Animator anim;
    private Rigidbody2D rb2d;
    private bool inputEnabled = true;
    void Start()
    {
        anim = GetComponent<Animator>();
        rb2d = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        foreach (Touch t in Input.touches)
        {
            if (inputEnabled == true)
            {
                rb2d.velocity = new Vector2(3f, 5f);
                anim.SetBool("isOnGround", false);
                inputEnabled = false;
            }
        }
        Debug.Log(transform.position.y);
        if (transform.position.y <= -5.5f)
        {
            Debug.Log("ENTERED");
            anim.SetBool("isFlying", true);
            rb2d.velocity = new Vector2(0,20);
        }
    }
}
1 Like

There are no other exceptions and I managed to get it to work with your advice! It's really as you said, the velocity value was too little to influence a visible change. Damn, I had no idea Unity's physics systems were so realistic hahaha.

Man, I took a look at state machines and boy do they look complex haha. I'll try to slowly figure out how to integrate it into my coding.

Yikes, you even helped test the code.Thanks Yoreki, you're the best! :smile:


Dont be scared ;) When looking for statemachines, you will most likely find a lot of diagrams. These are fine (and helpful) for visualizing what you want, but in the end they only contain some sort of states (often circles), which are connected by lines with arrows. These indicate which conditions allow you to leave the state, and in which state you end up then.

As a practical example, if we wanted to create a character controller and we had some different states in mind:
Standing, Walking, Running, Jumping, Crouching, ...., Swimming, ...
These states often do not work together. For example, you wouldnt want to be able to swim and run at the same time. Or crouch and jump at the same time. So we would define a state machine that takes care of this. We would define these states (most likely using an Enum), and then use if-statements or a switch-case to control which state we are in.
So in pseudo code, this may look like so:

// All below in Update()

if (currentState = State.Standing){
    // Check conditions for leaving this state
    if (jumpKeyPressed) currentState = State.Jumping;
    if (crouchKeyPressed) currentState = State.Crouching;
    ... and so on

    // Do whatever this state contains
    // ... for example play idle / standing animation,
    // ... regenerate HP at an increased rate, ... or whatever
}
else if(currentState = State.Jumping){
    // Again, check state-changing conditions
    if(touchingTheGroundAgain) currentState = State.Standing;

    // Do what this state is supposed to do..
    // which is basically nothing, after one quick burst of upwards force,
    // until we touch the ground again.
    // Some games may allow for in-air control, so that would go here too.
}

With the above structure, it would be impossible to, for example, crouch while jumping. In the above example you can only crouch from the Standing state, and you can only reach that state from Jumping after you touch the ground again. So you'd Stand (state) -> press jump key (condition) and apply upwards force -> Jump (state) -> touch ground again (condition) -> Stand (state) -> press crouch key (condition) -> Crouch (state) -> let go of crouch key (condition) -> Standing (state) -> ... and so on.

Hope this makes it more clear. It's really not that scary, but very useful. In your case, if using translate, you could create a 'Rising' state, in which the translation is applied every frame, and velocity is set to 0 every frame, until some coordinate is reached. That would be your condition to leave the Rising state, after which you can fall down to -5.5 again and so on. More generally speaking, if that was the only thing it did, an object could have a Rising and a Falling state, which alternate. The object would rise after falling, and fall after rising and so on.
This simply allows you to change behaviour based on which state you are in.
Working with rigidbody.velocity however, you wont need this in this case. State machines are still a very useful tool to have in your toolbelt. For more complex approaches there are also statemachines which allow to be in multiple states at one time and so on, but i'd recommend not to worry about that yet.

Thanks for that explanation! It helps me grasp the use of state machines a little better.
I'm trying to look out for tutorials on state machines on Youtube. I do hope they simplify it to the point i can understand it well haha. I also have to learn to incorporate the use of classes and their inheritance in my coding too. Right now I'm just dumping all my code into a single controller script. Even someone as new as myself can see how that can quickly turn disastrous hahaha.