#rigid body gravity with area3d
235 messages · Page 1 of 1 (latest)
You're manually setting the linear velocity. Do not recommend.
This will override gravity and causes a myriad of headaches.
Instead, apply forces over time to move the player
ah so it's my code then LOL
apply_central_force( _velocity )
RigidBody3D doesn't like to be moved directly, unlike CharacterBody3D which does nothing but
right
that's my fault I couldn't really find much about rigidbody player controllers
so do I even need the lerp for acceleration?
Yeah, documentation could use an update there
(this is also like my third day with godot, i am very at fault)
Lerp shouldn't be needed since it'll accelerate on its own
Might want to give it more mass though
You might need to amp up the forces used. Right now they're small numbers for a RigidBody3D
Multiply the velocity by a scalar (float) until it's at a level you're happy with
ok you lost me again
i removed the lerp and now i'm applying force to target velolcity
By velocity I mean _velocity not linear_velocity
Then apply the central force to move the object
Basically yes. Move speed might need changing though since the method of movement is less direct
Yep. That's why you might want more mass, and perhaps more friction
It's a physics body so it'll act like any object in a physical way
right hang on
is there an is_on_floor check for this or do i need a sphere raycast
oh my friction is zero
There's no is_on_floor for RigidBody3D unfortunately.
You'll have to do any checks manually.
god dammit
do I just need to add a bunch of mass so it doesn't keep sliding after i'm not on the input
A simple Raycast3D pointed towards the floor would usually suffice
Mass helps it accelerate slower. Friction helps it slow down faster
You probably don't want immediate acceleration, so a small increase to mass can help there. Friction helps you stop in a timely manner. Friction of 1.0 basically means you're an immovable object
You probably want it reasonably high. I'd start with 0.7 and see how that goes
ok i can tweak that later, when i get into the area 3d how do i orient the character to match the gravity direction
You need the gravity direction first ... Here's where the fun begins
why am i going backwards
this is so frustrating haha
press w
goes backwards
crazy
why aren't there tutorials for this
func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
DownVector = state.total_gravity.normalized()```
This way you always know which way is down
where does total_gravity come from
oh
# Get input direction
var direction = Vector3.ZERO
if Input.is_action_just_pressed("jump"):
apply_impulse(Vector3.UP * JUMP_FORCE, Vector3.ZERO)
if Input.is_action_pressed("forward"):
direction.z -= 1
if Input.is_action_pressed("backward"):
direction.z += 1
if Input.is_action_pressed("left"):
direction.x -= 1
if Input.is_action_pressed("right"):
direction.x += 1
# Normalize the direction to ensure consistent speed when moving diagonally
if direction.length() > 0:
direction = direction.normalized()
#_velocity = _velocity.rotated(Vector3.UP, head.rotation.y)
# Calculate the target velocity
_velocity = direction * MOVE_SPEED
# Apply the final velocity
apply_central_force(_velocity)
i have this now which just doesnt work in the slighest for whatever reason
As in it doesn't move or...?
wait I have it moving again
ok
well there' gravity working in that i come back down from a jump
A good start
ok other than the fact i move in the wrong bloody direction it works
it moves in different directions every time i run the same thing what the hel
can i disable a node
Depends what you mean by disable.
You can pause nodes, but I'm guessing you want something more targeted and specific?
no that's alright i don't need to do that
ok os how does a down vector help me
i set the transform basis y to the down vector?
It's always pointing at where your 'feet' should be. You can use it to rotate the player appropriately
can you add a max speed to the forces
when you strafe is it getting stacked or somethng
its defo stacking speed or soemthing
sorry I really suck i appreciate all your help
okay jumping makes the movement speed so much quicker lol
To limit the speed you can either set a drag factor to be realistic. Or for a more arcade feel you can clamp the linear_velocity in the _integrate_forces function
Don't do this anywhere else though
Eg:
linear_velocity = linear_velocity.normalized() * max_speed```
If you want to separate gravitational and horizontal movement that's a whole other ball game
what happened to not changing linear_velocity LOL
I just can't seem to get a good balance between mass friction and movement speed at the minute it all just feels weird
You don't usually want to do this. If you ever do, it should only be inside the _integrate_forces function. Nowhere else
Otherwise you get weird results
It's a rollercoaster for sure
even with a friction of 0.9 it feels like I don't stop for ages
Does the target surface also have friction?
Check the physics material it's using
Then add one and set the friction to at least 0.1
Static body also uses a physics material. All collision bodies do except for areas
yeah i'm not seeing a physics material area
i can only add standard or shader
am i stupid
it doesn't matter cus the box is for testing
the planet will have friction
ok so down vector rotation
yeah thats my fault it wasnt in a static body
DownVector = state.total_gravity.normalized()
rotation_degrees.z = DownVector.z```
is tis not just how to do it
no it is not i just fly off
ok i am literally never going to figure this out i haet spheres
@uncut rain am i meant to rotate it to be perpendicular to down vector but then the movement forecs will eb jank
You should rotate the visual elements, not the rigidbody itself
So, basically the mesh
And of course, any Raycast3D you're using to check the ground collisions on
Ideally you want to avoid that since it'll mess with the physics
uhhhhhhh
was setting the z to down vector z even correct
like i have to rotaet the head and the mesh and the collision anyway?
No. The default direction for an object is to face forward. Getting a downward vector and matching the rotation would only give make you face towards the floor. Probably not what you wanted
But, if you know the down direction you can calculate the correct rotation using quaternions
Quaternions are a form of abstraction for 3d rotation. You should ideally avoid using direct changes to rotation as it can lead to something called Gimbal lock
You'll need to cross this bridge eventually for working in 3D. These are fairly common issues.
Only the visual elements. Personally, I'd put them all on a single node and just rotate that single node rather than iterate through them all
Yeah but if I rotate only the mesh then the camera won't be correct no?
You might also need to rotate the collision shape if it's not uniform
You can parent a camera to the mesh which will allow it to track it and rotate with it
Or, if you're using the add on, set the mesh as the object to follow instead of the rigidbody
if I only rotate the mesh the collisions will be wrong anyway?
i dont get why i can't just rotate the rigidbody
That's why I mentioned the collision shape.
That's not always needed, in the case of a sphere for example
Yeah so I have to rotate everything anyway, so why not the parent?
oh thta's what you meant by uniform
unless the collision shape can also be a child of the mesh
You can rotate the parent, but you'd need to be smart about it. The variable you want is angular velocity. But like with linear velocity you should avoid setting it directly
So you can add angular momentum in the direction of the turn instead
ok but can collision shapes be a child of the mesh
that's not gonna break anything
so i have to calculate the correct rotation with a quaternion given the down direction and then set the mesh rotation to thta
can this be done with a CharacterBody3D even
?
cant be as simple as that
Collision shapes need to be a direct child of the parent collider
so that's a no
CharacterBody3D is a different beast to a RigidBody3D. You'll need to calculate gravity forces manually if you switch
ok i won't do that then
is this at least correct
can i just set transform basis y to rotation quaternion now
Not quite. You need to invert the y so add a minus symbol first
var down_vector = state.total_gravity.normalized()
var rotation_quaternion = Quaternion(-state.transform.basis.y, -down_vector)
$PlayerMesh.transform.rotation = Basis(rotation_quaternion)
$PlayerCollision.transform.rotation = Basis(rotation_quaternion)```
am i cooking
Oh wait, sorry I didn't realise you were already inverting the gravity. That's on me. Yeah, only one needs inverting not both
So just the gravity. Remove the one you added for the basis
I thought so haha
am I alright to just use the basis like that i've seen it before
nevermind thats an error
is transform.rotation not a thing
unity syntax oops
i guess i'm just changiong the transofmr basis.y on both then?
Try this:
func rotate_to_ground() -> void:
var gravity = down_vector. normalized()
var current_down = -global_transform.basis.y
var target_down = gravity
var rotation_axis = current_down.cross(target_down)
var angle = acos(clamp(current_down.dot(target_down), -1.0, 1.0))
if rotation_axis.length_squared() > 0.0001 and angle > 0.001:
rotation_axis = rotation_axis.normalized()
# Scale the torque by angle and align_speed
var torque = rotation_axis * angle * align_speed
apply_torque(torque)```
Should allow a smooth gradual rotation rather than snapping
Call it in physics process
For the first frame, down vector should default to Vector3.DOWN
So be sure to add the default
apply_torque is a function of the RigidBody3D
What issues are you having?
i don't think its rotating anything
Try increasing the speed. It's set fairly low.
is there a way i can view the game scene from a different camera?
it might rotate the character itself, but the camera and stuff isnt reflecting that
which is why i dont think it rotates
yeah, if i go to the bottom of the planet my head is touching the bottom and not my feet
if i set the align speed to much higehr i start bouncing off the planet
which is quite interesting
I'd need access to my pc to run some tests to be honest. I think I've hit the limit of what I can help with without being able to test it directly
You can set the bounce to absorbent if you want to avoid that
I'll revisit this later once I'm back home rather than at work. Might have some more juicy stuff to play with
current_dwown doesnt seem to change at all with these print statements
is it meant to chagne lol
It's mostly in case it started out at a non zero value
So if you rotated it in the scene editor for example, it'll take the new rotation into account
i think its keeping me upside down? lol
me on the bottom of the planet with it above my head? lol
probably some negative needed
One more try. After that I'll tap out until I've had a chance to test it myself.
@export var align_speed: float = 5.0
func rotate_to_ground() -> void:
get_gravity_area()
var gravity_center = gravity_area.global_transform.origin
var gravity_direction = (gravity_center - global_transform.origin).normalized()
var current_down = -global_transform.basis.y
var target_down = gravity_direction
var rotation_axis = current_down.cross(target_down)
var angle = acos(clamp(current_down.dot(target_down), -1.0, 1.0))
if rotation_axis.length_squared() > 0.0001 and angle > 0.001:
rotation_axis = rotation_axis.normalized()
var torque = rotation_axis * angle * align_speed
apply_torque(torque)
for area in get_overlapping_areas():
var gravity_center = Vector3.ZERO
var nearest_area: Area3D = null
var min_distance: float = INF
if area.is_in_group("GravityZone"): # Put your gravity Areas in a "GravityZone" group
var center = area.global_transform.origin
var distance = global_transform.origin.distance_squared_to(center)
if distance < min_distance:
min_distance = distance
gravity_center = center
nearest_area = area
gravity_area = nearest_area```
ok so - the code you sent doesn't work, or i'm doing something wrong
this is what i'm trying now:
extends CharacterBody3D
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _process(delta):
gravity_direction = (planet.global_transform.origin - global_transform.origin).normalized()
set_up_direction(-gravity_direction)
print("Gravity Direction:", -gravity_direction)
print("Is on floor:", is_on_floor())
func _unhandled_input(event):
if event is InputEventMouseMotion:
head.rotate_y(-event.relative.x * SENSITIVITY)
camera.rotate_x(-event.relative.y * SENSITIVITY)
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-40), deg_to_rad(60))
func _physics_process(delta):
if not is_on_floor():
velocity += gravity_direction * gravity * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity += -gravity_direction * JUMP_VELOCITY
var input_dir = Input.get_vector("left", "right", "forward", "backward")
var direction = (head.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if is_on_floor():
if direction:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
else:
velocity.x = lerp(velocity.x, direction.x * speed, delta * 7.0)
velocity.z = lerp(velocity.z, direction.z * speed, delta * 7.0)
else:
velocity.x = lerp(velocity.x, direction.x * speed, delta * 3.0)
velocity.z = lerp(velocity.z, direction.z * speed, delta * 3.0)
var target_transform = transform.looking_at(global_transform.origin + gravity_direction, Vector3.UP)
var current_quat = transform.basis.get_rotation_quaternion()
var target_quat = target_transform.basis.get_rotation_quaternion()
transform.basis = Basis(current_quat.slerp(target_quat, delta * ROTATION_SPEED))
move_and_slide()```
it works but the rotation is a bit wrong so idk why
i am so so lost
its defo something like this ```f rotation_axis.length_squared() > 0.0001 and angle > 0.001:
rotation_axis = rotation_axis.normalized()
# Scale the torque by angle and align_speed
var torque = rotation_axis * angle * align_speed
apply_torque(torque)```
but for the character controller
i'll probably need you for thta
Working on a demo you can pull apart later. Might need to adapt it to your needs though
I'll post it when it's ready
thank u !!! i feel really close with this rn but so far
hopefully I can get the bare bones just working
any update on this?
Had a play around and I've got something that mostly works. Had an emergency I had to take care of, so wasn't able to complete it, so I hope to post the whole thing later today assuming no more surprises.
Oh please don't worry too much I totally understand! I'll kep hacking away at it for now anyway and see if I can't come up with a solution
I feel like I am so close
var gravity_direction = (planet.global_position - global_position).normalized()
var target_rotation_quaternion = Quaternion(global_transform.basis.z, -gravity_direction)
var current_rotation_quaternion = global_transform.basis.get_rotation_quaternion()
transform.basis = Basis(current_rotation_quaternion.slerp(target_rotation_quaternion, delta * ROTATION_SPEED))
set_up_direction(-gravity_direction)```
I tried this and it almost works but the movement and gravity stuff is a bti buggy. I guess I'll just wait for your demo atp
Are you using CharacterBody3D or RigidBody3D. I know you were making some changes recently
This is me trying with a CharacterBody3D
I'm going to have one last try using self.rotation to see if that works, if not I'm truly stumped and doing something catastrophically wron
const speed = 20.0
const JUMP_VELOCITY = 10
const SENSITIVITY = 0.004
const ROTATION_SPEED = 15
const gravity = 9.8
var gravity_direction = Vector3.DOWN
@export var planet: Marker3D
@onready var head = $PlayerHead
@onready var camera = $PlayerHead/Camera3D
# Hide cursor when game loads
func _ready():
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _process(delta):
var gravity_direction = (planet.global_position - global_position).normalized()
var relative_up = -gravity_direction
set_up_direction(relative_up)
# Handles camera movement
func _unhandled_input(event):
if event is InputEventMouseMotion:
head.rotate_y(-event.relative.x * SENSITIVITY)
camera.rotate_x(-event.relative.y * SENSITIVITY)
camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-40), deg_to_rad(60))
func _physics_process(delta):
if not is_on_floor():
# Add gravity while in the air
velocity += gravity_direction * gravity * delta
# Add jump velocity in the opposite direction of gravity
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity += -gravity_direction * JUMP_VELOCITY
var input_dir = Input.get_vector("left", "right", "forward", "backward")
var direction = (head.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if is_on_floor():
if direction:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
else:
velocity.x = lerp(velocity.x, direction.x * speed, delta * 7.0)
velocity.z = lerp(velocity.z, direction.z * speed, delta * 7.0)
else:
velocity.x = lerp(velocity.x, direction.x * speed, delta * 3.0)
velocity.z = lerp(velocity.z, direction.z * speed, delta * 3.0)
move_and_slide()
Yeah at this point I can't get beyond this at all. I'll just wait for the demo
Since you're now using CharacterBody3D you might want to try the following. Mesh in this instance refers to the character mesh. Collider refers to the collisionshape you're using (so that collisions match the character).
var down_vector: Vector3 = -get_gravity().normalized()
mesh.transform.basis.y = down_vector
mesh.transform.basis.x = -mesh.transform.basis.z.cross(down_vector)
mesh.transform.basis = mesh.transform.basis.orthonormalized()
collider.transform.basis.y = -down_vector
collider.transform.basis.x = -collider.transform.basis.z.cross(down_vector)
collider.transform.basis = collider.transform.basis.orthonormalized()```
Just call it after your move_and_slide() and it should snap to the gravity.
Yeah that's not working either, I found a reddit post that had this code:
var left_axis = -current_gravity_dir.cross(transform.basis.z) # left_axis is left hand side for player
var my_z = global_transform.basis.z # Don't change z
transform.basis = Basis(left_axis, current_gravity_dir, my_z).orthonormalized() # Current player rotation
up_direction = transform.basis.y # Change up direction```
but I can't get this to work either, I don't know anymore
Okay I think I have it almost working now
var target_transform = Transform3D()
target_transform.origin = global_position
# Find the left hand side of the player
var left_axis = -gravity_direction.cross(transform.basis.z)
# Keep the z axis the same
var my_z = global_transform.basis.z
# Set target rotation
target_transform.basis = Basis(left_axis, -gravity_direction, my_z).orthonormalized()
var current_rotation = global_transform.basis.get_rotation_quaternion()
var target_rotation = target_transform.basis.get_rotation_quaternion()
# Lerp between the two quaternions
var interpolated_rotation = current_rotation.slerp(target_rotation, delta * 10.0)
global_transform.basis = Basis(interpolated_rotation)```
I have this
Just trying to figure out how to get te oriented input direction for mvoement
okaaaaaaaaay
var input_dir = Input.get_vector("left", "right", "forward", "backward")
# Get the camera's global transform basis
var camera_basis = camera.global_transform.basis
# The horizontal plane's basis vectors are perpendicular to the gravity direction
# We can construct them by taking the cross product of the gravity direction with
# the camera's right and forward vectors. This guarantees they lie on the plane.
var horizontal_right = gravity_direction.cross(camera_basis.y).normalized()
var horizontal_forward = gravity_direction.cross(-camera_basis.x).normalized()
# Combine the directions
var direction = (horizontal_right * input_dir.x + horizontal_forward * input_dir.y).normalized()
return direction
i don't know what i;m doing anymore
sometimes i press forward and i go upwards so this isnt quite right
ok i think this get oriented input is all I ned help with now - im trying to simplify donw:
var input_dir = Input.get_vector("left", "right", "backward", "forward")
# Get the camera's global transform basis
var camera_basis = camera.global_transform.basis
# Orient the input direction using the camera's basis
var direction = camera_basis.x * input_dir.x + camera_basis.z * (-input_dir.y)
return direction.normalized() # Important to normalize the direction```
@uncut rain is there anyway i can just. rotate the sphere?