water-testing/scripts/droplet.gd

85 lines
2.7 KiB
GDScript3
Raw Normal View History

2026-05-02 23:08:42 +00:00
class_name Droplet extends RigidBody2D
2026-05-03 04:34:46 +00:00
# default mode: a bit sluggish, tendency to pile
# bounce mode: doesn't settle down at all, but keeps flat surface
2026-05-03 05:13:12 +00:00
# sinker: new droplet sinks, pile grows outward
2026-05-03 04:34:46 +00:00
# stick mode: piles tightly, very calm
# wip mode: interesting, the base stays together, and the new one jumps into place
2026-05-03 05:13:12 +00:00
enum Mode { DEFAULT, BOUNCE, SINKER, RICE, WIP }
var MODE: Mode
2026-05-03 04:34:46 +00:00
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
2026-05-03 05:13:12 +00:00
elif mode == Mode.SINKER:
bounce = 0
2026-05-03 04:34:46 +00:00
friction = 0.1
2026-05-03 05:13:12 +00:00
elif mode == Mode.RICE:
2026-05-03 04:34:46 +00:00
bounce = 0.1
friction = 0.3
else: # WIP
bounce = 0.1
friction = 1
2026-05-02 23:08:42 +00:00
func _ready():
2026-05-03 04:34:46 +00:00
var config = DropletConfig.new(MODE)
var mat = PhysicsMaterial.new()
2026-05-03 04:34:46 +00:00
mat.bounce = config.bounce
mat.friction = config.friction
physics_material_override = mat
2026-05-03 04:34:46 +00:00
linear_damp = config.linear_damp
angular_damp = config.angular_damp
# setup body entered signal, seems to also matter for STICK mode
2026-05-03 04:34:46 +00:00
if not MODE == Mode.DEFAULT:
contact_monitor = true
max_contacts_reported = 10
2026-05-03 05:13:12 +00:00
# body_entered.connect(_on_body_entered)
2026-05-02 23:08:42 +00:00
func _physics_process(delta):
2026-05-03 04:34:46 +00:00
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):
2026-05-03 04:34:46 +00:00
# this is probably overkill since we are overriding the default physics engine
2026-05-03 05:13:12 +00:00
if MODE == Mode.RICE:
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))
2026-05-03 05:13:12 +00:00
elif MODE == Mode.SINKER:
# only contribute to the target rigid bodies, let source droplet handle it's own bounce
var v = state.linear_velocity
for i in range(state.get_contact_count()):
var body = state.get_contact_collider_object(i)
var normal = state.get_contact_local_normal(i)
if body is RigidBody2D:
var impact_speed = v.dot(-normal)
if impact_speed > 0:
var boost = normal * impact_speed * 1
body.apply_central_impulse(boost)