` I’m working on an fps game, and am trying to add crates that the player can carry, and move around the world, I’ve got the crate moving with the player, but it currently doesn’t follow the mouse, or interact with other objects. Just wondering what methods I could use to achieve this. The code blocks and video are below:
Crate Script:
xtends RigidBody3D
var item_name = "Crate"
var is_held = false
@onready var player = $"../Player"
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
if is_held == true:
self.reparent(player.carry_point)
elif is_held == false:
self.reparent(player.get_parent())
func hold():
is_held = !is_held
Player Interact Script:
func _physics_process(delta):
if collider.is_in_group("hold"):
if collider.is_held == false:
prompt.text = "[F] Grab " + str(collider.item_name)
else:
prompt.text = ""
if Input.is_action_just_pressed("interact"):
collider.hold()
Setting freeze = true and the freeze_mode = FreezeMode.FREEZE_MODE_KINEMATIC on the crate when it is held should make it correctly interact with other physics objects as its moved around.
Edit: You can probably set the freeze_mode in the property inspector, as you shouldn’t need to keep switching it back and forth. Then you could do:
Hey, I tried this, and the crate still doesn’t interact with the static objects like buildings, which are all StaticBody3D’s, and it pushes the enemy models away, which I don’t want to happen, as I want it to be not able to push things.
Ah, because you are essentially forcing the position of the crate to update by moving its parent, Godot’s physics can’t stop it from moving into static objects.
From my current understanding, moving physics objects manually can cause desync problems with the physics servers. Saying that, I’m not actually sure at all if moving the physics objects parent counts as manually moving a physics object? Perhaps that case is correctly handled by the physics server?
As you can probably tell, your problem might be a little out of my knowledge, so sorry I’m not sure I’ll be able to give you any concrete help or fixes. However these are some things I thought of (in no specific order)
Use a CharacterBody3D instead of a RigidBody3D for your crates and make use of its move_and_slide method.
Continue using RigidBody3D but instead of just attaching the carry_point use it’s physic methods (apply_*) to move it around
Manually check collisions and stop the position from updating, possibly in _integrate_forces method
Hi,
I followed your advice, and made the crate a CharacterBody3D, don’t know why I didn’t think of that earlier! The crate is now moving as expected, and colliding with other objects, however it now won’t fall when I let it go. I’m hoping you can help me with that.
Here’s the current code snippet:
Apparently get_gravity() got implemented in 4.3, so if you’re using 4.2 you will not have it. I recommend you to upgrade Godot to the latest 4.3 or 4.4 versions, if that’s feasible for you, but if not, then you can grab the gravity from ProjectSettings instead:
var gravity_force: float = ProjectSettings.get_setting("physics/3d/default_gravity")
var gravity_vector: Vector3 = ProjectSettings.get_setting("physics/3d/default_gravity_vector")
var gravity: Vector3 = gravity_force * gravity_vector
Thank you for your assistance, I downloaded Godot 4.3, and the boxes are falling now, although when I stack boxes on top of each other, then take the bottom one away, the one above doesn’t fall, and remains floating, any idea what causes this? Here is the code snippet:
f is_held == false:
self.reparent(player.get_parent())
if !is_on_floor():
velocity += get_gravity()/1.8
move_and_slide()
elif is_on_floor():
velocity = Vector3.ZERO
Returns true if the body collided with the floor on the last call of move_and_slide. Otherwise, returns false. The up_direction and floor_max_angle are used to determine whether a surface is “floor” or not.
What it means is that is_on_floor() updates only when you call move_and_slide(). In your code, when the crate is on the floor, you just set the velocity to 0, and then you never call move_and_slide() again, so the is_on_floor() will also never be updated, so your crate is stuck mid-air.
elif is_on_floor():
velocity = Vector3.ZERO
Put all your move_and_slide() method calls outside of the if blocks, just at the complete end of the _physics_process() function (change it from _process() to _physics_process() by the way, I forgot to mention that before).
Within the if blocks you should only change the velocity, but the move_and_slide() should ideally be called every physics frame regardless of what the velocity is. If the velocity is 0, then it will just not move.
Edit: I think you don’t even need to separate the is_on_floor vs !is_on_floor scenarios, just apply the gravity all the time, that’s how it works in real world physics anyway, right? Maybe if you have hundreds of these calls in your scenes that may impact the performance, but I think the Engine should be optimized enough to handle it for you - you shouldn’t worry about it until you have a real issue with performance.
Thanks, I did that, but the crates seem to have a hard time cooperating, I might just make a Area3D above the box that checks if there’s something above it, like another box or the player then won’t get picked up if there is. Thank you so much for all of your help!
I’m glad @wchc was able to help, I’ve never actually used CharacterBody3D myself so wouldn’t have known the issues!
Glad you got something working at least, and your game is looking pretty cool by the way!