I would like to create a controllable character which can react to impacts by deforming slightly. And the answer is probably that I need a softbody. The thing is, a softbody is unpredictable for me. I mean, of course I tried the godot-softbody2d addon, which is great, but probably not for my purpose. I spent a lot of time tweaking settings in the addon, but didn't get a satisfying result, and I felt like this is an overcomplicated solution for the purpose...
It can't be an AnimatedSprite2D, like on the reference image, because it needs to react to impacts and deform at different parts.
The question is: What are my options?
Ideally, it would strive to stay.. round, but under gravity it would be forced to be like on the gif, even if the gravity gets inverted. It doesn't need to bend over obstacles or stuff like that. Mostly just handle impacts at different points and stay an oval (?).
As for someone who hasn't done similar things, I don't know even where to start.
I know that it can be done via some complex vertex shader deformations, but if I go that way, I need something to start with.
Solution (thoughts): I highly recommend to check the video in the answer, it might give you some ideas. Also check other videos which are mentioned there. Basically, if you are looking for softbody-like behavior, and you are mostly dumb like me, it's still achievable through using things like joints. I started playing with it, and it turned out to not be that hard. You can make a lot of cool stuff by just playing with it, and then applying a texture. You don't need to write your own physics for that, although this way it might be even more.. perfect. But games are not about perfectly simulating a softbody, they are mostly about being fun.
If you look at the Softbody2D addon source code, you will see that it indeed does something similar, and it also uses kind of its own Rigidbody, as well as Polygon2D and bones to deform the polygon and the texture. This is an overkill for me. It's easier when you understand your own solution and can tweak it to your needs.
I started by using 4 rigidbodies and DampedSpringJoint2Ds, each RB being connected to the 3 other RBs. It worked fine, behaves mostly as I would like it to. Then increased the number of RBs, to make it more round. That's what I suggest you to do. Find an optimal configuration.
And also think about automating some stuff, because Godot does not have a built-in way to connect two bodies via DampedSpringJoint2D perfectly (their centers). You might find this tool script useful:
spring_connector.gd
@tool
extends DampedSpringJoint2D
# Editor button trigger
@export var connect_centers: bool = false:
set(value):
connect_centers = value
if value:
_connect_centers()
connect_centers = false
func _connect_centers():
var body_a: Node2D = get_node_or_null(node_a)
var body_b: Node2D = get_node_or_null(node_b)
if not is_instance_valid(body_a) or not is_instance_valid(body_b):
return
var direction: Vector2 = body_b.global_position - body_a.global_position
global_position = body_a.global_position
# The minus PI/2 because duck it. Something to do with how DampedSpringJoint2D is rotated initially.
global_rotation = direction.angle() - PI/2
length = direction.length()
What you're trying to do seems very similar to this game's character: Little Slime Blows Up. The creator of the video talks about the technique used there.
Essentially you distribute circular rigidbodies in a circle and connect them all with spring joints (desired distance based on circle positions).
It's almost the same as a regular softbody, but implementing it yourself will allow you to tweak it until it matches your desired behaviour.
To overcome the intersection problem mentioned, you could add a Polygon2D collider based on the poisitions. Just make sure to disable collisions between it and the outer circles.