That’s an interesting problem. It’s probably the fact that your mouse is moving too fast and the first frame it’s below the item and the next frame it’s way above item, so godot never detects the the mouse has entered an area.
Something you could try is to store the mouse position the frame before and then the next frame do a raycast from the mouse position the frame before to the current mouse position and see if there are any collisions.
It’s a little more involved code wise than your signal approach. Here’s the docs for Raycasts: Ray-casting — Godot Engine (stable) documentation in English
For the below script, a main scene has this script attached and then the Rigidbody2Ds are children of it. (At least in my test project). You can try the raycast approach because it’s easier to set up, but note that a intersect_ray call only hits 1 object per frame, whereas the intersect_shape will hit many, but takes longer to set up. If your issue really is the mouse moving faster than the frame checks, you probably want the
var previous_mouse_pos: Vector2
var mouse_pos: Vector2 = get_global_mouse_position()
previous_mouse_pos = mouse_pos
# only run raycast when mouse is pressed
# OPTION 1: make a raycast, this will only hit one object this frame
var space_state = get_world_2d().direct_space_state
var rayhit = space_state.intersect_ray(previous_mouse_pos, mouse_pos)
# you could do rayhit.collider.queue_free()
# OPTION 2: build segment shape to be sure you hit all objects between a and b in one frame
var segment_shape = SegmentShape2D.new()
segment_shape.a = previous_mouse_pos
segment_shape.b = mouse_pos
# build the shape query for the intersect_shape method
# there are a lot more options you can set like masks on this
var query = Physics2DShapeQueryParameters.new()
var hits = space_state.intersect_shape(query)
if hits.size() > 0:
for hit in hits:
# Always store previous_mouse_pos for the next frame calculation
# even if mouse is not pressed
previous_mouse_pos = mouse_pos
If you don’t want to get that involved you could try messing around with your physics framerate and seeing if it’s just low for some reason, or try turning on continuous_cd on your Rigidbody2D “fruits.”
Good luck, I’d be interested to see what solution you come up with!
It was indeed much more complicated compared to my “If mouse detected → delete”, but it worked, and also I learned something new!
First, I tried to tick continuous_cd as the easiest solution, but it did not seem to make a difference. I’ve decided to leave the FPS counter in peace because I don’t think it is the most efficient solution, so ray/shapecasting it was.
Raycasting was fine enough for me (you could always make an excuse that not every fruit got destroyed with one swing because the player’s knife wasn’t sharpened enough!), but in case I wanted to spawn more fruits simultaneously (and also just for the sake of learning) I tried shapecasting, and now everything works perfectly!
P.S. In Physics2DShapeQueryParameters I can specify the collision layers. I have a single collision layer to check, so I specified it, but I wonder if it makes any difference performance wise. To me, it sounds like checking one collision layer should take less time than checking the default value of “2147483647” layers, but is that really the case, or is the speed difference so small that it’s neglectable?
KitePZ | 2023-05-17 15:13
I’m by no means an expert, but I’d guess checking one collision layer will probably be more performant. It’s hard for me to say by how much. But my guess is if your game is small enough with only the one swiping interaction, it’s probably negligible. Layers use bitmasks which are pretty performant anyway. So, you probably won’t notice it in your game. I’d say the bigger value would be if you want like two different kinds of knives, one that can slice fruits and the other that slices rocks, you could use the masks to make sure your rock knife doesn’t detect and delete fruits.
Tom Mertz | 2023-05-17 17:49