How to let players control a 3D character's local gravity at runtime?

Godot Version

4.2.2

Question

Hello all,

I am fairly new to Godot (and programming in general), and I’m struggling to find a solution to change the player’s gravity during runtime. So far, I’ve found solutions for changing global gravity and creating gravity fields with Area3D objects, but I have not found a way to change the local gravity for the player or specific objects.

I am building a 3D platformer, and the player needs to be able to switch to one of three predefined gravity directions with their controller: Down (-Y), to the Left (-X), or the right (+X).

Part of my issue is that I still don’t exactly know what I should look for in the engine or online. Any direction or assistance would be greatly appreciated.

Are you using a RigidBody3D or a CharacterBody3D? A character would need to be scripted with a gravity direction variable, make sure to set the up_direction too.

I am still considering which would be best to use. Maybe you have input? I am responsible to build a small prototype of the gravity switching mechanic to share with my team.

I need to build the gravity switching, ground movement, air movement with reduced speed, a jump, fall damage, and a camera controller to prove the concept.

Would you recommend RigidBody3D or CharacterBody3D?

CharacterBody3D for 99% cases, RigidBody3D if the player is a marble (mostly controlled by physics)

1 Like

I’ve played with stuff like this before.

Using a RigidBody3D will yield the quickest results and be the easiest to set up. GDQuest actually has a tutorial on how to do just this.

The problem with using RigidBody as a player-controllable character is that it’s so much harder to fine tune it to get it exactly how you want. You really have to tweak and adjust all the different parameters and forces to get it to behave somewhat how you want. And if you decide to just code in your own movement functionality, perhaps using move_and_collide, that removes the reason of using the RigidBody to begin with.

What I’d recommend is using a CharacterBody3D node and writing all your movement and gravity physics from scratch. It will be more work up front, but you’ll have far more control over how the final product feels. I’d wager that this is the approach Nintendo used when creating Super Mario Galaxy.

To actually change the gravity direction of the CharacterBody, rotate it manually and change its up_direction to match the rotation. (global_transform.basis.y) With this approach, you’d also need to come up with a custom solution for defining what direction is “down.” For a sphere gravity area, just calculate the direction to the center of the sphere, and that will be your gravity vector. But if your game only has three predefined gravity directions, this would be unnecessary.

Hope this helps!

1 Like

Thank you for the reply.

I watched the GDQuest video yesterday, but that doesn’t appear to be the solution I need. However, I may misunderstand the underlying principle. I wish the video were a little more in-depth, if not a little hand-holding.

I’ve changed object gravity based on Area3D (which gives you that Mario Galaxy planet effect that GDQuest is mimicking). But I need to find a solution where only the player is affected by gravity (no other rigidbodies) and throughout the entire map.

For example, the player could have sideways gravity, while a rigidbody crate would maintain normal gravity. The player would be able to stand sideways on the “wall” of the crate, sitting on the room floor.

In some sense, I think it’s easier than spherical gravity. I need to make the player fall down (-Y), to the left (-X), and to the right (+X), but I’m at a loss for where to start messing with a single object’s gravity.

Are there any resources I could read to understand how Godot handles gravity on a more fundamental level?

You should use a CharacterBody3D, with a CharacterBody3D godot doesn’t handle gravity, it’s all done by your scripts.

Godot’s physics system handles gravity like most other physics engines. As far as I’m aware, gravity is just a constant that’s applied to all simulated bodies.

If you need something that’s applied only to one object and not the entire physics world, a CharacterBody3D is definitely the way to go. To change the gravity, you could do something like this: (Code is untested)

enum GRAVITY_DIRECTIONS {
	DOWN,
	LEFT,
	RIGHT,
}

const GRAVITY = 9.8
var gravity_direction = GRAVITY_DIRECTIONS.DOWN


func _physics_process(delta) -> void:
	# We want the up direction to be the opposite of the gravity direction
	match gravity_direction:
		GRAVITY_DIRECTIONS.DOWN:
			up_direction = Vector3.UP 
		GRAVITY_DIRECTIONS.LEFT:
			up_direction = Vector3.RIGHT 
		GRAVITY_DIRECTIONS.RIGHT:
			up_direction = Vector3.LEFT

	velocity += -up_direction * GRAVITY

To change the gravity direction, just set the gravity_direction variable. You’d have to handle rotating the character to match the gravity direction, also.

2 Likes