From b71ea391555d0b7ac29fe65cec84a361b0cadf97 Mon Sep 17 00:00:00 2001 From: Meik <2212733@stud.hs-mannheim.de> Date: Sat, 27 Jun 2026 16:25:57 +0200 Subject: [PATCH] added achievement popup in game --- assets/music&sfx/sfx/achievement_unlock.wav | Bin 0 -> 27885 bytes .../sfx/achievement_unlock.wav.import | 24 ++++ scripts/achievement_manager.gd | 14 +- scripts/achievement_popup.gd | 122 ++++++++++++++++++ scripts/achievement_popup.gd.uid | 1 + scripts/stats_manager.gd | 2 + 6 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 assets/music&sfx/sfx/achievement_unlock.wav create mode 100644 assets/music&sfx/sfx/achievement_unlock.wav.import create mode 100644 scripts/achievement_popup.gd create mode 100644 scripts/achievement_popup.gd.uid diff --git a/assets/music&sfx/sfx/achievement_unlock.wav b/assets/music&sfx/sfx/achievement_unlock.wav new file mode 100644 index 0000000000000000000000000000000000000000..a8c8781898b7415358cf3b487a976b447e720c69 GIT binary patch literal 27885 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 Dyqh(( literal 0 HcmV?d00001 diff --git a/assets/music&sfx/sfx/achievement_unlock.wav.import b/assets/music&sfx/sfx/achievement_unlock.wav.import new file mode 100644 index 0000000..6c22e63 --- /dev/null +++ b/assets/music&sfx/sfx/achievement_unlock.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://c7x1rtkae66k4" +path="res://.godot/imported/achievement_unlock.wav-9a9f9e013cd33e691b8d6734dd2cf61a.sample" + +[deps] + +source_file="res://assets/music&sfx/sfx/achievement_unlock.wav" +dest_files=["res://.godot/imported/achievement_unlock.wav-9a9f9e013cd33e691b8d6734dd2cf61a.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=0 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=2 diff --git a/scripts/achievement_manager.gd b/scripts/achievement_manager.gd index 42fa77d..2612c38 100644 --- a/scripts/achievement_manager.gd +++ b/scripts/achievement_manager.gd @@ -1,6 +1,7 @@ extends Node const SAVE_PATH = "user://achievements.json" +const _POPUP_SCRIPT = preload("res://scripts/achievement_popup.gd") var achievements: Array = [] func _ready() -> void: @@ -123,15 +124,22 @@ func _define() -> void: ] func check_all() -> void: - var changed = false + var newly_unlocked: Array = [] for ach in achievements: if ach.unlocked: continue if _meets(ach): ach.unlocked = true - changed = true - if changed: + newly_unlocked.append(ach) + if not newly_unlocked.is_empty(): _save() + for ach in newly_unlocked: + _show_popup(ach) + +func _show_popup(ach: Dictionary) -> void: + var popup = _POPUP_SCRIPT.new() + get_tree().root.add_child(popup) + popup.show_unlock(ach) func _meets(ach: Dictionary) -> bool: var d = StatsManager.data diff --git a/scripts/achievement_popup.gd b/scripts/achievement_popup.gd new file mode 100644 index 0000000..c37f2d2 --- /dev/null +++ b/scripts/achievement_popup.gd @@ -0,0 +1,122 @@ +extends CanvasLayer + +const _VP_W := 1280.0 +const _VP_H := 720.0 +const _MARGIN := 16.0 +const _SFX_PATH := "res://assets/music&sfx/sfx/achievement_unlock.wav" + +var _font = preload("res://assets/fonts/slkscre.ttf") +var _panel: PanelContainer + +func _ready() -> void: + layer = 100 + process_mode = Node.PROCESS_MODE_ALWAYS + + _panel = PanelContainer.new() + _panel.custom_minimum_size = Vector2(310.0, 76.0) + _panel.mouse_filter = Control.MOUSE_FILTER_IGNORE + + var style := StyleBoxFlat.new() + style.bg_color = Color(0.04, 0.04, 0.12, 0.96) + style.border_width_left = 2 + style.border_width_top = 2 + style.border_width_right = 2 + style.border_width_bottom = 2 + style.border_color = Color(0.78, 0.62, 0.18, 1.0) + style.corner_radius_top_left = 3 + style.corner_radius_top_right = 3 + style.corner_radius_bottom_right = 3 + style.corner_radius_bottom_left = 3 + style.content_margin_left = 8.0 + style.content_margin_top = 8.0 + style.content_margin_right = 12.0 + style.content_margin_bottom = 8.0 + _panel.add_theme_stylebox_override("panel", style) + + _panel.position = Vector2(_VP_W + 8.0, _VP_H - 76.0 - _MARGIN) + add_child(_panel) + + +func show_unlock(ach: Dictionary) -> void: + var hbox := HBoxContainer.new() + hbox.add_theme_constant_override("separation", 10) + hbox.mouse_filter = Control.MOUSE_FILTER_IGNORE + _panel.add_child(hbox) + + # Icon square + var icon_wrap := Control.new() + icon_wrap.custom_minimum_size = Vector2(52, 52) + icon_wrap.mouse_filter = Control.MOUSE_FILTER_IGNORE + hbox.add_child(icon_wrap) + + var icon_bg := ColorRect.new() + icon_bg.color = ach.color + icon_bg.mouse_filter = Control.MOUSE_FILTER_IGNORE + icon_bg.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + icon_wrap.add_child(icon_bg) + + var icon_lbl := Label.new() + icon_lbl.text = ach.icon_char + icon_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + icon_lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER + icon_lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE + icon_lbl.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + icon_lbl.add_theme_font_override("font", _font) + icon_lbl.add_theme_font_size_override("font_size", 22) + icon_lbl.add_theme_color_override("font_color", Color(1.0, 1.0, 0.88)) + icon_lbl.add_theme_color_override("font_outline_color", Color(0.0, 0.0, 0.0, 0.8)) + icon_lbl.add_theme_constant_override("outline_size", 2) + icon_wrap.add_child(icon_lbl) + + # Text block + var vbox := VBoxContainer.new() + vbox.size_flags_vertical = Control.SIZE_SHRINK_CENTER + vbox.mouse_filter = Control.MOUSE_FILTER_IGNORE + hbox.add_child(vbox) + + var header := Label.new() + header.text = "Achievement Unlocked!" + header.mouse_filter = Control.MOUSE_FILTER_IGNORE + header.add_theme_font_override("font", _font) + header.add_theme_font_size_override("font_size", 13) + header.add_theme_color_override("font_color", Color(0.78, 0.62, 0.18, 1.0)) + vbox.add_child(header) + + var title_lbl := Label.new() + title_lbl.text = ach.title + title_lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE + title_lbl.add_theme_font_override("font", _font) + title_lbl.add_theme_font_size_override("font_size", 20) + title_lbl.add_theme_color_override("font_color", Color(1.0, 0.95, 0.8, 1.0)) + vbox.add_child(title_lbl) + + _play_sound() + # Wait one frame so the panel has its final size before animating + await get_tree().process_frame + _animate() + + +func _play_sound() -> void: + if not ResourceLoader.exists(_SFX_PATH): + return + var sfx := AudioStreamPlayer.new() + sfx.stream = load(_SFX_PATH) + sfx.volume_db = -2.0 + sfx.process_mode = Node.PROCESS_MODE_ALWAYS + add_child(sfx) + sfx.play() + sfx.finished.connect(sfx.queue_free) + +func _animate() -> void: + var pw := _panel.size.x + var target_x := _VP_W - pw - _MARGIN + _panel.position.x = _VP_W + 8.0 + + var tween := create_tween() + tween.set_pause_mode(Tween.TWEEN_PAUSE_PROCESS) + tween.tween_property(_panel, "position:x", target_x, 0.4)\ + .set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_QUART) + tween.tween_interval(3.5) + tween.tween_property(_panel, "position:x", _VP_W + 8.0, 0.3)\ + .set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_QUART) + tween.tween_callback(queue_free) diff --git a/scripts/achievement_popup.gd.uid b/scripts/achievement_popup.gd.uid new file mode 100644 index 0000000..07351b9 --- /dev/null +++ b/scripts/achievement_popup.gd.uid @@ -0,0 +1 @@ +uid://dsitid33q7lcx diff --git a/scripts/stats_manager.gd b/scripts/stats_manager.gd index ade85ac..77c4fae 100644 --- a/scripts/stats_manager.gd +++ b/scripts/stats_manager.gd @@ -50,10 +50,12 @@ func end_run(died: bool) -> void: func on_kill(enemy_type: String) -> void: if data["kills"].has(enemy_type): data["kills"][enemy_type] += 1 + AchievementManager.call_deferred("check_all") func on_spell_cast(spell_type: String) -> void: if data["spells_cast"].has(spell_type): data["spells_cast"][spell_type] += 1 + AchievementManager.call_deferred("check_all") func _save() -> void: var file = FileAccess.open(SAVE_PATH, FileAccess.WRITE)