Struggling with Overlapping PhysicBody2Ds

Godot Version

Godot v4.4.1

Background

I am building a Sushishot clone as a learning exercise (still pretty new to Godot) and also because my partner loves that game and would like to play a personalised version.

The core mechanic is merging of items into bigger items when they collide. Here is the approach i have taken.

  1. The playable area is boxed in by 4 x StaticBody2Ds (wall) and each item is a RigidBody2D
  2. When a collision is detected, a new Item is instanced at the point of collision between 2 items
  3. The new item is scaled from 0 to the desired size to avoid overlapping with other items and the walls.

Problem

When the collision point is too close to the walls (StaticBody2D) or another item, the new item scales into them and they end up overlapping. This causes all sorts of weird jittering or items getting “stuck” together or to walls.

Here is what i’ve tried with no luck on solving this issue:

  1. Scaling the RigidBody2D instead of the CollisionShape2D - did not help at all!
  2. Setting up an Area2D to detect overlap and applying a small force to the overlapping item back out - helped in some cases to help slide the item back out but doesn’t work if overlap is too much
  3. Adjusting the rotation of the new item to minimize the changes of overlap - helps a bit but doesn’t solve my core issue.

Question

What is the best practice when it comes to scaling RigidBody2Ds? I’ve found a couple older threads suggesting not to do this but doesn’t offer any viable alternatives.

Image and code snippet for scaling for reference:

Screenshot

func _ready() -> void:
	# attach item to a game intance
	_set_game_instance()
	
	# set all children to scale from 0 to desired size
	var children: Array = get_children()
	for child in children:
		# if it can be scaled (i.e not a timer node)
		if child is Node2D:
			child.scale = Vector2.ZERO
			var tween: Tween = create_tween()
			if child is Sprite2D:
				tween.tween_property(child, "scale", target_scale, sprite_scale_duration)
			else:
				tween.tween_property(child, "scale", target_scale, collision_scale_duration)

Can you show a video of your issue? I tried recreating it by scaling the CollisionShape2D, like you did in your code snippet, but it worked fine, even with a big scale difference, the object just pushed itself out of the wall. It overlapped for a few frames, but in the end, it always goes out, I couldn’t make it to stick or behave weird.

I’m new on the forum so have to upload it externally until i have a few more posts, let me know if the link doesn’t work.

This clip shows both problems

  1. You can see the “meat” item getting stuck with the “broth” item and drags it up. (FYI - there is a constant upward force for all items)
  2. later the merge happens and the “ramen” item spawns over the wall and gets stuck.

https://imgur.com/a/0pRuz6S

Could you try adding this to your script and then reuploading the video?

func _ready():
    Engine.time_scale = 0.1

it should make it easier to identify the issue although i suspect the way it scales might be an issue (it looks almost instant)

the beefs collide and scaling starts:

the next frame the ramen seems to overlap slightly with the wall.

In a single frame the ramen is collisionbody is almost full size. Maybe the collisionbody just dosent have the time to adjust because the scaling is almost instant?

in your video it looks like the sprite scales the same way that WCHC example (a lot more gradually).

i dont really know why the beef is stuck to the broth though. Hope this helps

I’ve had a play with how fast the collision shape scales and slowing it down seems to have “fixed” the problem. The shapes still overlap but now it gradually gets pushed out.

It doesn’t entirely solve my issue because now the game feels less poppy with the slower expansion. I am masking this by making the sprite scale quickly first to give the visual feel of a pop as the collision shape expands more slowly in parallel.

Marking this resolved for now. Thank you @jup and @wchc !

2 Likes