85 lines
2.7 KiB
GDScript
85 lines
2.7 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
|
|
# sinker: new droplet sinks, pile grows outward
|
|
# stick mode: piles tightly, very calm
|
|
# wip mode: interesting, the base stays together, and the new one jumps into place
|
|
enum Mode { DEFAULT, BOUNCE, SINKER, RICE, WIP }
|
|
var MODE: Mode
|
|
|
|
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.SINKER:
|
|
bounce = 0
|
|
friction = 0.1
|
|
elif mode == Mode.RICE:
|
|
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.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))
|
|
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)
|