diff --git a/assets/shaders/screen_low_hp.gdshader b/assets/shaders/screen_low_hp.gdshader new file mode 100644 index 0000000..92e25c4 --- /dev/null +++ b/assets/shaders/screen_low_hp.gdshader @@ -0,0 +1,39 @@ +shader_type canvas_item; + +uniform sampler2D screen_texture : hint_screen_texture; +uniform float damage_amount : hint_range(0.0, 1.0) = 0.0; +uniform float noise_strength : hint_range(0.0, 1.0) = 0.3; +uniform float pulse_strength : hint_range(0.0, 1.0) = 0.2; +uniform float time; + +// TODO: uniform vec2 player_uv; // use this to calculate player offset to camera + +float random(vec2 uv) { + return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +void fragment() { + // Distance from screen center + vec2 center = vec2(0.5, 0.5); + float dist = distance(SCREEN_UV, center); + float edge_factor = smoothstep(0.4, 0.7, dist); // stronger at edges + float edge_factor_gray = smoothstep(0.0, 1.0-damage_amount, dist); + + // Noise flicker + float n = random(SCREEN_UV * 200.0 + time * 2.0); + float noise = (n - 0.5) * noise_strength; + + // Pulsing intensity + float pulse = sin(time * 5.0) * pulse_strength; + + // Final intensity + float final_amount = damage_amount * edge_factor + noise + pulse; + final_amount = clamp(final_amount, 0.0, 1.0); + + vec4 base = texture(screen_texture, SCREEN_UV); + float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114)); + base.rgb = mix(base.rgb, vec3(gray), edge_factor_gray * damage_amount); + + vec4 red_tint = vec4(1.0, 0.0, 0.0, 1.0); + COLOR = mix(base, red_tint, final_amount); +} diff --git a/assets/shaders/screen_low_hp.gdshader.uid b/assets/shaders/screen_low_hp.gdshader.uid new file mode 100644 index 0000000..34ed7c3 --- /dev/null +++ b/assets/shaders/screen_low_hp.gdshader.uid @@ -0,0 +1 @@ +uid://dnwiwj1ak1bu5 diff --git a/global_const.gd b/global_const.gd index 47e5fbf..8e09a29 100644 --- a/global_const.gd +++ b/global_const.gd @@ -12,6 +12,10 @@ signal sig_debug_stats_set(key: String, value: String) signal sig_stop_spawning(value: bool) @warning_ignore("unused_signal") signal sig_set_spawn_rate(value: float) +@warning_ignore("unused_signal") +signal sig_on_player_hp_change(hp: float, max_hp: float) +@warning_ignore("unused_signal") +signal sig_toggle_low_hp_shader(toggled_on: float) const GROUP_ENEMY = "enemy" const GROUP_DAMAGEABLE = "damagable" diff --git a/scenes/enemies/enemy_base.gd b/scenes/enemies/enemy_base.gd index 69a2e60..a26aa2f 100644 --- a/scenes/enemies/enemy_base.gd +++ b/scenes/enemies/enemy_base.gd @@ -56,6 +56,10 @@ func do_movement(delta: float) -> void: _do_simple_movement() else: _do_nav_agent_movement() + if velocity.x < 0: + sprite_2d.flip_h = true + else: + sprite_2d.flip_h = false func _has_direct_path(): diff --git a/scenes/managers/ui/main_ui.gd b/scenes/managers/ui/main_ui.gd index 1b88e42..dbbb5ba 100644 --- a/scenes/managers/ui/main_ui.gd +++ b/scenes/managers/ui/main_ui.gd @@ -5,9 +5,35 @@ extends Control @onready var player_ui: PlayerUI = $CanvasLayer/PlayerUI @onready var debug_ui: DebugUI = $CanvasLayer/DebugUI @onready var level_up_ui: LevelUpUI = $CanvasLayer/LevelUpUI +@onready var low_hp_indicator: ColorRect = $CanvasLayer/LowHPIndicator + +var elapsed_time: float func _ready() -> void: pause_ui.visible = false player_ui.visible = true level_up_ui.visible = false + low_hp_indicator.visible = false + GlobalConst.sig_on_player_hp_change.connect(_on_player_hp_change) + GlobalConst.sig_toggle_low_hp_shader.connect(_on_toggle_low_hp_shader) + + +func _process(delta: float) -> void: + elapsed_time += delta + if low_hp_indicator.visible: + low_hp_indicator.material.set_shader_parameter("time", elapsed_time) + + +func _on_player_hp_change(hp: float, max_hp: float): + print_debug("got sig") + var percent_hp = hp / max_hp * 100 + if percent_hp < 40: + low_hp_indicator.visible = true + low_hp_indicator.material.set_shader_parameter("damage_amount", 1 - (percent_hp / 100)) + else: + low_hp_indicator.visible = false + + +func _on_toggle_low_hp_shader(toggled_on: bool): + low_hp_indicator.visible = !low_hp_indicator.visible diff --git a/scenes/managers/ui/main_ui.tscn b/scenes/managers/ui/main_ui.tscn index a396a82..97d4342 100644 --- a/scenes/managers/ui/main_ui.tscn +++ b/scenes/managers/ui/main_ui.tscn @@ -1,11 +1,19 @@ -[gd_scene load_steps=6 format=3 uid="uid://b18uib08hvdpq"] +[gd_scene load_steps=8 format=3 uid="uid://b18uib08hvdpq"] [ext_resource type="Script" uid="uid://dcxc70fvu7kl2" path="res://scenes/managers/ui/main_ui.gd" id="1_3a826"] [ext_resource type="Script" uid="uid://sjnxf0hj3egp" path="res://scenes/managers/ui/pause_ui.gd" id="1_lke1m"] +[ext_resource type="Shader" uid="uid://dnwiwj1ak1bu5" path="res://assets/shaders/screen_low_hp.gdshader" id="2_lcbsd"] [ext_resource type="Script" uid="uid://dbq74tvxtpfjc" path="res://scenes/managers/ui/player_ui.gd" id="3_gaipe"] [ext_resource type="Script" uid="uid://d2o6tqnqg2o25" path="res://scenes/managers/ui/debug_ui.gd" id="4_217l8"] [ext_resource type="PackedScene" uid="uid://isg7vt4l7eem" path="res://scenes/managers/ui/level_up_ui.tscn" id="5_cfhdr"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_cg7ol"] +shader = ExtResource("2_lcbsd") +shader_parameter/damage_amount = 0.5 +shader_parameter/noise_strength = 0.2 +shader_parameter/pulse_strength = 0.05 +shader_parameter/time = 0.0 + [node name="MainUI" type="Control"] layout_mode = 3 anchors_preset = 15 @@ -17,6 +25,14 @@ script = ExtResource("1_3a826") [node name="CanvasLayer" type="CanvasLayer" parent="."] +[node name="LowHPIndicator" type="ColorRect" parent="CanvasLayer"] +material = SubResource("ShaderMaterial_cg7ol") +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + [node name="PauseUI" type="Control" parent="CanvasLayer"] layout_mode = 3 anchors_preset = 15 diff --git a/scenes/player.gd b/scenes/player.gd index a03ec1b..d8e2ea8 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -51,6 +51,7 @@ func take_damage(value: float) -> void: dm.damage_taken = value dm.player_damage = false add_child(dm) + GlobalConst.sig_on_player_hp_change.emit(current_hp, max_hp) main_ui.player_ui.update_hp() if player_stats.current_health <= 0: die()