I followed this tutorial for a rigidbody that can be “picked up” by the mouse and dropped back down. The problem is that you can move past the walls and drop the body into the void beyond the edge of the screen. How can constrain this object/the mouse cursor to keep everything contained within the window or within a custom box?
This tutorial ignores the physics calculations and just sets the transform of the RigidBody2D directly. If you want it to collide with a wall, then you need to use the physics functions exposed for RigidBody2D, like apply_force() (which you apply a force in the direction of your mouse cursor relative to the RigidBody2D).
I see, if I only wanted it to collide with some walls (i.e just the window borders but not my “container”) how would I do that? I’m looking into Physics layers but I don’t really understand how/when to use them.
Well the window borders don’t have actual collision shapes in the game so you would have to move some collision shapes to always be where the window borders are.
Physics layers match physics masks. So an area with the “3” mask will only look for other bodies / areas on the “3” layer.
So the I could have the object on two masks testing for the container vs borders, and turn off the container one when picked up? How should I control this with code then - instead of via inspector?
Sorry to bother again, especially since I thought it was solved, but I’m having a slight issue with the apply force part. Getting the position of the mouse and subtracting it from the object position no longer works, as the force applied is too weak. I tried apply_impulse as seen below, but now the object acts like it’s tethered to the mouse instead of being dragged directly.
This results in the object bobbing up and down and being able to be swung really fast - glitching outside the walls I put up.
func _physics_process(delta):
if held:
apply_central_impulse(get_global_mouse_position()-global_transform.origin)
I thought about using clamp, but i’m not sure what I would set the min/max values as, and the slingy movement would still be an issue.
Hi, the docs say to not use the central impulse function like that.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force.
What I think you should do is apply a force each frame in the direction of the mouse. As in, not the position of the mouse subtracted from the object position, but the direction multiplied by a force.
var drag_force := 400 # or a different value that suits you
# other code in between goes here
func _physics_process(delta):
if held:
var dir = global_position.direction_to(get_global_mouse_position())
var dir_force := dir * drag_force
apply_central_force(dir)
If the object moves too slowly in the up direction compared to the other directions, you can set gravity_scale to 0 for the duration of the hold.
This gets it pretty close and I might just leave it, but the bobbing/fast velocity still happens if you drag the mouse away from the object. Ideally the object would not be able to get flung around while holding because I’m trying to simulate a hand grabbing it. Any thoughts?
I ended up doing this. I ended up using central impulse even though I know I shouldn’t, as it’s jank but works, and shouldn’t be affected too much since I’m using delta_t as well (I think that’s how it works). Using forces, I always ended up with the bobbing unless the force is unbearably small. Thanks for the help though, I’ll probably rework things next game when I have more time.
if held:
var canvas = get_canvas_transform()
var topleft = -canvas.origin / canvas.get_scale()
var canvas_size = get_viewport_rect().size / canvas.get_scale()
var mouse_pos = get_global_mouse_position()
mouse_pos.x = clamp(mouse_pos.x,topleft.x,topleft.x+canvas_size.x)
mouse_pos.y = clamp(mouse_pos.y,topleft.y,topleft.y+canvas_size.y)
var dir_force: Vector2 = (mouse_pos-global_position-linear_velocity)*MOUSE_DRAG_FORCE*delta
apply_central_impulse(dir_force)