class_name Droplet extends RigidBody2D # default mode: a bit sluggish, tendency to pile # bounce mode: doesn't settle down at all, but keeps flat surface # bounce_wip: wonky AF, probably due to extra compute # stick mode: piles tightly, very calm # wip mode: interesting, the base stays together, and the new one jumps into place enum Mode { DEFAULT, BOUNCE, BOUNCE_WIP, STICK, WIP } const MODE: Mode = Mode.WIP class DropletConfig: var bounce var friction var linear_damp var angular_damp func _init(mode): linear_damp = ProjectSettings.get_setting("physics/2d/default_linear_damp") angular_damp = ProjectSettings.get_setting("physics/2d/default_angular_damp") if mode == Mode.DEFAULT: bounce = 0 friction = 0.1 elif mode == Mode.BOUNCE: bounce = 0.5 friction = 0.1 elif mode == Mode.BOUNCE_WIP: bounce = 0.5 friction = 0.1 elif mode == Mode.STICK: bounce = 0.1 friction = 0.3 else: # WIP bounce = 0.1 friction = 1 func _ready(): var config = DropletConfig.new(MODE) var mat = PhysicsMaterial.new() mat.bounce = config.bounce mat.friction = config.friction physics_material_override = mat linear_damp = config.linear_damp angular_damp = config.angular_damp # setup body entered signal, seems to also matter for STICK mode if not MODE == Mode.DEFAULT: contact_monitor = true max_contacts_reported = 10 body_entered.connect(_on_body_entered) func _physics_process(delta): if MODE == Mode.WIP: for body in get_colliding_bodies(): if body is RigidBody2D: var dir = global_position - body.global_position var dist = dir.length() if dist < 64: ## IIUC: should act to keep close droplets together var force = -dir.normalized() * (1.0 - dist / 64.0) body.apply_central_force(force * 100) func _integrate_forces(state): # this is probably overkill since we are overriding the default physics engine if MODE == Mode.STICK: var v = state.linear_velocity var contacts = state.get_contact_count() for i in range(contacts): var body = state.get_contact_collider_object(i) var normal = state.get_contact_local_normal(i) var self_damp = .9 var other_damp = 1 - self_damp v = v.bounce(normal) * self_damp state.linear_velocity = v # self bounce if body is RigidBody2D: # other body body.apply_central_impulse(normal * v.length() * (other_damp/contacts)) func _on_body_entered(body): if MODE == Mode.BOUNCE_WIP: # trying to elicit stronger response from rigidBody that was struck # ends up being kind of erratic # at damp_factor .75: settles laterally, but erratic past half-full # at damp_factor of .5, it's pretty calm, but then can't overfill (expected?) var vel = get_linear_velocity() const damp_factor = 0.7 var normal = (body.global_position - global_position).normalized() # reflect velocity across collision direction var bounced = vel.bounce(normal) # reflection set_linear_velocity(bounced * damp_factor) if body is RigidBody2D: body.apply_central_impulse(-bounced * damp_factor)