2025-09-18 20:34:11 +02:00
|
|
|
class_name Water extends Node2D
|
2025-09-18 14:49:30 +02:00
|
|
|
|
|
|
|
|
signal water_reached_max_height
|
2025-09-18 19:35:52 +02:00
|
|
|
@onready var player : Player = %Player
|
|
|
|
|
@export var animation_height : float = 0
|
|
|
|
|
@export var radius_base : float = 0
|
2025-09-18 14:49:30 +02:00
|
|
|
|
|
|
|
|
var radius : float:
|
|
|
|
|
set(new_radius):
|
|
|
|
|
radius = new_radius
|
|
|
|
|
var mesh = get_node_or_null("WaterMesh")
|
|
|
|
|
if !is_instance_valid(mesh):
|
|
|
|
|
return
|
|
|
|
|
update_scale(mesh)
|
|
|
|
|
mesh.material.set_shader_parameter("radius", radius)
|
|
|
|
|
|
|
|
|
|
@export var amplitude : float:
|
|
|
|
|
set(new_amplitude):
|
|
|
|
|
amplitude = new_amplitude
|
|
|
|
|
var mesh = get_node_or_null("WaterMesh")
|
|
|
|
|
if !is_instance_valid(mesh):
|
|
|
|
|
return
|
|
|
|
|
update_scale(mesh)
|
|
|
|
|
mesh.material.set_shader_parameter("amplitude", amplitude)
|
|
|
|
|
|
2025-09-18 15:43:44 +02:00
|
|
|
@export var tsunami_size : float:
|
2025-09-18 14:49:30 +02:00
|
|
|
set(new_size):
|
|
|
|
|
tsunami_size = new_size
|
|
|
|
|
var mesh = get_node_or_null("WaterMesh")
|
|
|
|
|
if !is_instance_valid(mesh):
|
|
|
|
|
return
|
|
|
|
|
update_scale(mesh)
|
|
|
|
|
mesh.material.set_shader_parameter("tsunami_size", tsunami_size)
|
|
|
|
|
|
|
|
|
|
var tsunami_angle : float:
|
|
|
|
|
set(new_angle):
|
|
|
|
|
tsunami_angle = new_angle
|
|
|
|
|
var mesh = get_node_or_null("WaterMesh")
|
|
|
|
|
if !is_instance_valid(mesh):
|
|
|
|
|
return
|
|
|
|
|
update_scale(mesh)
|
|
|
|
|
mesh.material.set_shader_parameter("tsunami_angle", tsunami_angle)
|
2025-09-18 19:35:52 +02:00
|
|
|
|
|
|
|
|
func check_player_collision():
|
|
|
|
|
var pos = player.position
|
|
|
|
|
var angle = atan2(pos.y, pos.x)
|
|
|
|
|
var water_height = get_height_at(angle)
|
|
|
|
|
var player_height = sqrt(pos.x * pos.x + pos.y * pos.y)
|
|
|
|
|
if(water_height > player_height - 25):
|
|
|
|
|
if player.hurt(1, Vector2.ZERO):
|
|
|
|
|
player.reset_to_velocity = Vector2(0, -2000)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func get_height_at(angle):
|
|
|
|
|
var TIME : float = Time.get_ticks_usec() / 1000000.;
|
|
|
|
|
var wave1 = amplitude/1. * sin(150. * angle + TIME);
|
|
|
|
|
var wave2 = amplitude/2. * sin(90. * angle + 1.6 * TIME);
|
|
|
|
|
var wave3 = amplitude/3. * sin(55. * angle + 2.3 * TIME);
|
|
|
|
|
var wave4 = amplitude/4. * sin(35. * angle + 3.9 * TIME);
|
|
|
|
|
var wave = wave1 + wave2 + wave3 + wave4;
|
|
|
|
|
|
|
|
|
|
var angle_diff : float = angle - tsunami_angle;
|
|
|
|
|
angle_diff = fmod(angle_diff + PI + TAU, TAU) - PI;
|
|
|
|
|
var sinc : float = (sin(20. * angle_diff) / angle_diff/ 20.);
|
|
|
|
|
var tsunami : float = pow(abs(sinc), 1.5) * tsunami_size * sign(sinc);
|
|
|
|
|
return radius + wave + tsunami;
|
|
|
|
|
|
2025-09-18 14:49:30 +02:00
|
|
|
|
2025-09-18 15:43:44 +02:00
|
|
|
@export var animation_angle : float = 0
|
|
|
|
|
@export var tsunami_base_angle : float
|
|
|
|
|
|
2025-09-18 14:49:30 +02:00
|
|
|
@export var rise_from : float = 2500;
|
|
|
|
|
@export var rise_to : float = 3500;
|
|
|
|
|
@export var rise_time : float = 120; # in seconds
|
|
|
|
|
var auto_rise : bool = true;
|
|
|
|
|
|
|
|
|
|
@onready var start_unix_time : float = Time.get_unix_time_from_system()
|
2025-09-18 15:43:44 +02:00
|
|
|
var direction = 1;
|
2025-09-18 14:49:30 +02:00
|
|
|
|
|
|
|
|
func update_scale(mesh):
|
|
|
|
|
mesh.scale = 2 * (radius + amplitude * 2.1 + tsunami_size) * Vector2.ONE
|
|
|
|
|
|
|
|
|
|
func update_shader():
|
|
|
|
|
radius = radius
|
|
|
|
|
amplitude = amplitude
|
|
|
|
|
tsunami_angle = tsunami_angle
|
|
|
|
|
tsunami_size = tsunami_size
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
|
|
|
|
update_shader()
|
2025-09-18 19:35:52 +02:00
|
|
|
radius_base = rise_from
|
|
|
|
|
|
|
|
|
|
|
2025-09-18 14:49:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
func _process(_delta: float) -> void:
|
2025-09-18 19:35:52 +02:00
|
|
|
check_player_collision()
|
2025-09-18 14:49:30 +02:00
|
|
|
if auto_rise:
|
|
|
|
|
var time: float = Time.get_unix_time_from_system()
|
|
|
|
|
if time - start_unix_time > rise_time:
|
|
|
|
|
auto_rise = false
|
2025-09-18 19:35:52 +02:00
|
|
|
radius_base = rise_to
|
2025-09-18 14:49:30 +02:00
|
|
|
water_reached_max_height.emit()
|
|
|
|
|
else:
|
2025-09-18 19:35:52 +02:00
|
|
|
radius_base = lerpf(rise_from, rise_to, (time - start_unix_time) / rise_time)
|
2025-09-18 15:43:44 +02:00
|
|
|
|
2025-09-18 19:35:52 +02:00
|
|
|
tsunami_angle = tsunami_base_angle + animation_angle * direction;
|
|
|
|
|
radius = radius_base + animation_height
|
2025-09-18 15:43:44 +02:00
|
|
|
|
|
|
|
|
# direction is -1 for left, +1 for right
|
|
|
|
|
func create_tsunami(angle : float, dir : int):
|
|
|
|
|
if direction not in [-1, 1]:
|
|
|
|
|
push_error("direction must be in {-1, 1}")
|
|
|
|
|
return
|
|
|
|
|
direction = dir
|
|
|
|
|
tsunami_base_angle = angle;
|
|
|
|
|
|
|
|
|
|
$Tsunami.play("tsunami")
|
2025-09-18 19:35:52 +02:00
|
|
|
|
|
|
|
|
func rise_water():
|
2025-09-18 22:56:04 +02:00
|
|
|
await get_tree().create_timer(.03).timeout
|
2025-09-18 20:13:48 +02:00
|
|
|
auto_rise = false
|
|
|
|
|
$ParticleContainer.scale = Vector2.ONE * radius/3000
|
|
|
|
|
var pos = player.position
|
|
|
|
|
var angle = atan2(pos.y, pos.x)
|
|
|
|
|
$ParticleContainer.rotation = angle + PI/2
|
2025-09-18 22:56:04 +02:00
|
|
|
$ParticleContainer.position += Vector2.ONE
|
|
|
|
|
$WaterRise.play("water_rise")
|
2025-09-18 19:35:52 +02:00
|
|
|
await $WaterRise.animation_finished
|
2025-09-18 20:13:48 +02:00
|
|
|
radius_base = radius_base + animation_height
|
2025-09-18 19:35:52 +02:00
|
|
|
animation_height = 0
|