class_name Water extends Node2D signal water_reached_max_height @onready var player : Player = %Player @export var animation_height : float = 0 @export var radius_base : float = 0 var tsunami_speed : float = 1 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) @export var tsunami_size : float: 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) 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; @export var animation_angle : float = 0 @export var tsunami_base_angle : float @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() var direction = 1; 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() radius_base = rise_from func _process(_delta: float) -> void: check_player_collision() if auto_rise: var time: float = Time.get_unix_time_from_system() if time - start_unix_time > rise_time: auto_rise = false radius_base = rise_to water_reached_max_height.emit() else: radius_base = lerpf(rise_from, rise_to, (time - start_unix_time) / rise_time) tsunami_angle = tsunami_base_angle + animation_angle * direction * tsunami_speed; radius = radius_base + animation_height # direction is -1 for left, +1 for right func create_tsunami(angle : float, dir : int, speed : float): tsunami_speed = speed if direction not in [-1, 1]: push_error("direction must be in {-1, 1}") return direction = dir tsunami_base_angle = angle; $Tsunami.play("tsunami") func rise_water(): await get_tree().create_timer(.03).timeout 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 $ParticleContainer.position += Vector2.ONE $WaterRise.play("water_rise") await $WaterRise.animation_finished radius_base = radius_base + animation_height animation_height = 0