water-testing/scripts/droplet.gd

89 lines
3.0 KiB
GDScript

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)