Changing the gravity using Physics2D and vectors

Greetings everyone.

I’m trying to create a 2D puzzle game where the gravity changes when you rotate. The default and inverted gravity works fine, but the sideways (90 and 270 degrees) is not working. It doens affect the player, but the player is falling slowly and can move in the air. The player will continuously move, without stopping, when I press one of the movement keys.

The checkQR code is checking how many times the Q or E button has been pressed. Instead of checking the players currently degree, I’m just checking how many times the player has pressed the buttons.

I have the following code to change the gravity.

//Rotate
        if (Input.GetKeyDown(KeyCode.Q)) {
            checkQR -= 1;
            transform.localEulerAngles += new Vector3(0.0F, 0.0F, 90.0F);

            if (checkQR == -4) {
                checkQR = 0;

            }


            Debug.Log(checkQR);
        }

       
        if (Input.GetKeyDown(KeyCode.E)) {
            checkQR += 1;
            transform.localEulerAngles -= new Vector3(0.0F, 0.0F, 90.0F);

            if (checkQR == 4) {
                QRReset();
            }

            Debug.Log(checkQR);
        }
       
        //90 Clockwise
        if (checkQR == -1 || checkQR == 3 && grounded) {
            rotateSide = 1;
            Physics2D.gravity = new Vector2(10, 0);

        }
        //inverted
        else if (checkQR == -2 || checkQR == 2 && grounded) {
            rotateSide = 2;
           
            Physics2D.gravity = new Vector2(0, -10);        
        }
        //90 counter clockwise
        else if (checkQR == -3 || checkQR == 1 && grounded) {
            rotateSide = 3;
            Physics2D.gravity = new Vector2(-10, 0);        
        }
        //Standard
        else {
            //Debug.Log("rotate = " + rotate + "; leaving gravity alone.");
            rotateSide = 0;
            Physics2D.gravity = new Vector2(0, -10); 
        }

Why does checkQR need to go from -4 to 4? Can you increment “rotateSide” instead and check that?

You may be able to clean up your implementation a bit to help you debug.

Idk if this is exactly what you’re trying to do, but here’s another way to implement this type of control:

int rotateSide = 0;
int gravity = 10;
if(Input.GetKeyDown(KeyCode.Q)) {
    rotateSide -= 1;
    transform.Rotate(Vector3.forward, 90f);

    if(rotateSide < 0) {
        rotateSide = 3;
    }
}


if(Input.GetKeyDown(KeyCode.E)) {
    rotateSide += 1;
    transform.Rotate(Vector3.forward, -90f);

    if(rotateSide > 3) {
        rotateSide = 0;
    }
}

if(grounded) {
    switch(rotateSide) {
        case 0:
            Physics2D.gravity = Vector2.down * gravity;
            break;
        case 1:
            Physics2D.gravity = Vector2.left * gravity;
            break;
        case 2:
            Physics2D.gravity = Vector2.up * gravity;
            break;
        case 3:
            Physics2D.gravity = Vector2.right * gravity;
            break;

    }
} else {
    rotateSide = 0;
    Physics2D.gravity = Vector2.down * gravity;
}

you could also make the gravity always face the transform.down direction, which is the object’s local downward vector. So as you rotate the object, the gravity is always pointing “down” with respect to the object’s rotation.

Maybe this will work?

int gravity = 10;

if(Input.GetKeyDown(KeyCode.Q)) {
    transform.Rotate(Vector3.forward, 90f);
    UpdateGravity();
}

if(Input.GetKeyDown(KeyCode.E)) {
    transform.Rotate(Vector3.forward, -90f);
    UpdateGravity();
}

private void UpdateGravity(){
    Physics2D.gravity = -transform.up * gravity;
}
1 Like

Thanks for your reply and sorry for my late response. I’d appreciate your help, but it did not work. The player keeps falling slowly while being able to move in the air, and the left and right movement is constant, which means the player wont stop moving 1 direction until I change it

How do you have your player movement coded?

Thansk for your quick reply.

I use this code for right and the lft is just adding a - to the “moveSpeed”.

GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed, GetComponent<Rigidbody2D>().velocity.y);

But if you wish to see it all in context it is this:

 //Move Right
        if (Input.GetKey(KeyCode.D)) {
            //GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed, GetComponent<Rigidbody2D>().velocity.y);
            switch (rotateSide) {
                case 0:
                    moveVelocity = moveSpeed;
                    break;
                case 1:
                    GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, moveSpeed);
                    break;
                case 2:
                    moveVelocity = -moveSpeed;
                    break;
                //270
                case 3:
                    GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, moveSpeed);
                    break;
                default:
                    Debug.Log("D error");
                    break;
            }
        }

I have tried to remove all the cases and only keeping the default.

It probably has something to do with the fact that you’re directly setting “velocity” everywhere, which will override the force of gravity, which could be in any direction.

If I were you I would only use AddForce(force, ForceMode2D.Impulse) to move your character, that way all the forces in the physics simulation will be combined and the physics engine will determine the final velocity for you.

So if your character rotates at all, use his local axes for movement. The “force” will always be “direction * speed”, so the force required move your character along his local positive X axis would be “playerTransform.right * moveSpeed”. And be sure to handle physics updates in FixedUpdate.

1 Like

Thank you very much. I will give that a try :slight_smile: I will let you know if it succeeded. ^^

I have tried different ways with your suggestion, but I haven’t succeeded yet. I’m still new and learning, so that might be the problem for me.

I creating the right movement with vectors:

private void MoveRight() {
        GetComponent<Rigidbody2D>().AddForce(new Vector2(transform.eulerAngles.x*moveSpeed, 0), ForceMode2D.Impulse);

Is your character rotated? If you want to add a force along your character’s X axis taking into account rotation, you should use “AddForce(transform.right * moveSpeed, ForceMode2D.Impulse)”.

If you want to always move him towards the right side of the screen, regardless of rotation, you can use “AddForce(Vector2.right * moveSpeed, ForceMode2D.Impulse)”.

1 Like

Thanks for your reply. I got confused from your previous reply, but you have made it clearly now. The movement is working on all the axes, but the player does ignore the gravity/ground at 90 and 270 degrees. The player is able to move in the air, but will be forced back.

I have created a 17 second video to illustrate the problem. I have recorded with screencast-o-matic
http://screencast-o-matic.com/watch/cDjObQiWJA

I’m not entirely sure what I am looking for in that video. From what I see gravity is indeed acting on the character in all rotations. Do you want the gravity to always pull to the bottom of the screen? If so, you don’t need to change gravity at all for each rotation. How are you doing your jumping / ground check? What do you mean by “forced back”? It may help if you post the full player code as you have it right now so I can look through it without wondering what else could be going on. If you’re not comfortable posting the whole thing here you can send it to me in a private message.

1 Like

For future reference the problem was that the player+camera were rotating together, and the directional movement forces and gravity needed to use the local right and up vectors of the player+camera, and the all the forces needed to use AddForce to play nicely together.

1 Like