godot-parkour/addons/qodot/game_definitions/worldspawn_layers/liquid.gd

82 lines
2.3 KiB
GDScript

class_name LiquidLayer extends Area3D
@export var buoyancy_factor: float = 10.0
@export var lateral_damping_factor: float = 0.0
@export var vertical_damping_factor: float = 0.0
var buoyancy_dict := {}
func _init() -> void:
body_shape_entered.connect(_on_body_shape_entered)
body_shape_exited.connect(_on_body_shape_exited)
func _on_body_shape_entered(body_id, body: Node, body_shape_idx: int, self_shape_idx: int) -> void:
if not body is RigidBody3D:
return
var self_collision_shape = shape_owner_get_owner(shape_find_owner(self_shape_idx))
var body_collision_shape = body.shape_owner_get_owner(body.shape_find_owner(body_shape_idx))
var self_shape = self_collision_shape.get_shape()
var body_shape = body_collision_shape.get_shape()
var self_aabb = create_shape_aabb(self_shape)
var body_aabb = create_shape_aabb(body_shape)
buoyancy_dict[body] = {
"entry_point": body.global_transform.origin, "self_aabb": self_aabb, "body_aabb": body_aabb
}
func _on_body_shape_exited(body_id, body: Node, body_shape_idx: int, self_shape_idx: int) -> void:
if body in buoyancy_dict:
buoyancy_dict.erase(body)
func create_shape_aabb(shape: Shape3D) -> AABB:
if shape is ConvexPolygonShape3D:
return create_convex_aabb(shape)
elif shape is SphereShape3D:
return create_sphere_aabb(shape)
return AABB()
func create_convex_aabb(convex_shape: ConvexPolygonShape3D) -> AABB:
var points = convex_shape.get_points()
var aabb = null
for point in points:
if not aabb:
aabb = AABB(point, Vector3.ZERO)
else:
aabb = aabb.expand(point)
return aabb
func create_sphere_aabb(sphere_shape: SphereShape3D) -> AABB:
return AABB(-Vector3.ONE * sphere_shape.radius, Vector3.ONE * sphere_shape.radius)
func _physics_process(delta: float) -> void:
for body in buoyancy_dict:
var buoyancy_data = buoyancy_dict[body]
var self_aabb = buoyancy_data["self_aabb"]
self_aabb.position += global_transform.origin
var body_aabb = buoyancy_data["body_aabb"]
body_aabb.position += body.global_transform.origin
var displacement = self_aabb.end.y - body_aabb.position.y
body.add_central_force(Vector3.UP * displacement * buoyancy_factor)
body.add_central_force(
Vector3(1, 0, 1) * body.get_linear_velocity() * displacement * -lateral_damping_factor
)
body.add_central_force(
Vector3(0, 1, 0) * body.get_linear_velocity() * -vertical_damping_factor
)