From 1037d1343d0c172e665602d5b73adfac6f67c9be Mon Sep 17 00:00:00 2001 From: "m.cirafisi" Date: Tue, 2 Jun 2026 00:05:37 +0200 Subject: [PATCH] improve ui and bug fix --- core/game_state/game_state.gd | 8 ++ core/main_scene_ui/center_hole.gdshader | 19 ++++ core/main_scene_ui/center_hole.gdshader.uid | 1 + core/main_scene_ui/hole_mask.gdshader | 10 +++ core/main_scene_ui/hole_mask.gdshader.uid | 1 + core/main_scene_ui/main_scene_ui.gd | 85 ++++++++++++++++-- core/main_scene_ui/main_scene_ui.tscn | 50 ++++++++++- core/main_scene_ui/photo_taken.gd | 26 ++++++ core/main_scene_ui/photo_taken.gd.uid | 1 + core/main_scene_ui/photo_taken.tscn | 48 ++++++++++ core/photo_mode/assets/reticolo.png | Bin 10736 -> 5571 bytes .../photo_mode/managers/collection_manager.gd | 7 +- .../runtime/photo_mode_controller.gd | 25 ++++-- 13 files changed, 262 insertions(+), 19 deletions(-) create mode 100644 core/main_scene_ui/center_hole.gdshader create mode 100644 core/main_scene_ui/center_hole.gdshader.uid create mode 100644 core/main_scene_ui/hole_mask.gdshader create mode 100644 core/main_scene_ui/hole_mask.gdshader.uid create mode 100644 core/main_scene_ui/photo_taken.gd create mode 100644 core/main_scene_ui/photo_taken.gd.uid create mode 100644 core/main_scene_ui/photo_taken.tscn diff --git a/core/game_state/game_state.gd b/core/game_state/game_state.gd index 8478080..ff0d9de 100644 --- a/core/game_state/game_state.gd +++ b/core/game_state/game_state.gd @@ -10,6 +10,14 @@ signal on_photo_highlighted(teture: Texture) signal on_enable_photo_mode_request @warning_ignore("unused_signal") signal on_disable_photo_mode_request +@warning_ignore("unused_signal") +signal on_photo_taken_started +@warning_ignore("unused_signal") +signal on_photo_taken_making +@warning_ignore("unused_signal") +signal on_photo_taken_finished +@warning_ignore("unused_signal") +signal on_photo_taken_prepare const SAVE_PATH: String = "user://savegame.json" diff --git a/core/main_scene_ui/center_hole.gdshader b/core/main_scene_ui/center_hole.gdshader new file mode 100644 index 0000000..d7dae3a --- /dev/null +++ b/core/main_scene_ui/center_hole.gdshader @@ -0,0 +1,19 @@ +shader_type canvas_item; + +// Dimensione del rettangolo vuoto al centro (in proporzione allo schermo) +// Esempio: vec2(0.6, 0.6) significa che il buco occuperà il 60% dello schermo. +// Puoi modificare questi valori direttamente dall'Inspector di Godot! +uniform vec2 hole_size = vec2(0.6, 0.6); + +void fragment() { + // Calcoliamo la distanza dal centro esatto dello schermo (0.5, 0.5) + vec2 center = vec2(0.5, 0.5); + vec2 d = abs(UV - center); + vec2 half_size = hole_size / 2.0; + + // Se il pixel si trova all'interno delle dimensioni del buco, + // impostiamo l'Alpha a 0.0 (rendendolo totalmente trasparente). + if (d.x < half_size.x && d.y < half_size.y) { + COLOR.a = 0.0; + } +} diff --git a/core/main_scene_ui/center_hole.gdshader.uid b/core/main_scene_ui/center_hole.gdshader.uid new file mode 100644 index 0000000..d9ae04e --- /dev/null +++ b/core/main_scene_ui/center_hole.gdshader.uid @@ -0,0 +1 @@ +uid://dudbt51v33tt7 diff --git a/core/main_scene_ui/hole_mask.gdshader b/core/main_scene_ui/hole_mask.gdshader new file mode 100644 index 0000000..8c30cbf --- /dev/null +++ b/core/main_scene_ui/hole_mask.gdshader @@ -0,0 +1,10 @@ +shader_type canvas_item; + +uniform sampler2D mask_texture; + +void fragment() { + vec4 mask_color = texture(mask_texture, UV); + // Sottrae l'alpha della maschera dall'alpha del pannello. + // Dove la maschera è opaca (alpha = 1), il pannello diventerà trasparente (alpha = 0). + COLOR.a = max(COLOR.a - mask_color.a, 0.0); +} diff --git a/core/main_scene_ui/hole_mask.gdshader.uid b/core/main_scene_ui/hole_mask.gdshader.uid new file mode 100644 index 0000000..ab71663 --- /dev/null +++ b/core/main_scene_ui/hole_mask.gdshader.uid @@ -0,0 +1 @@ +uid://44y4fig1hi4y diff --git a/core/main_scene_ui/main_scene_ui.gd b/core/main_scene_ui/main_scene_ui.gd index 3ebbfac..c24a62c 100644 --- a/core/main_scene_ui/main_scene_ui.gd +++ b/core/main_scene_ui/main_scene_ui.gd @@ -9,11 +9,21 @@ enum Weather {RAIN, SNOW} @onready var collectible_icon_button: Button = $%CollectibleIconButton @onready var resume_button: Button = $GameMenuPanel/GameMenu/Pages/Page3/OptionMenu/VBoxContainer/ResumeButton @onready var weather_row: HBoxContainer = $%WeatherRow +@onready var time_of_day_row: HBoxContainer = $%TimeOfDayRow +@onready var photo_mode_texture_panel: Panel = $%PhotoModeTexturePanel @onready var photo_mode_texture_mask: TextureRect = $%PhotoModeTextureMask +@onready var photo_mode_black_screen: ColorRect = $%PhotoModeBlackScreen +@onready var collection_options: VBoxContainer = $%CollectionOptions +@onready var audio_player: Control = $%AudioPlayer + +var cycle = false func _ready() -> void: GameState.on_enable_photo_mode_request.connect(_on_enable_photo_mode) GameState.on_disable_photo_mode_request.connect(_on_disable_photo_mode) + GameState.on_photo_taken_started.connect(_on_photo_taken_started) + GameState.on_photo_taken_finished.connect(_on_photo_taken_finished) + GameState.on_photo_taken_prepare.connect(_on_photo_capture_prepare) menu_icon_button.pressed.connect(_on_menu_icon_button_pressed) photo_icon_button.pressed.connect(_on_photo_icon_button_pressed) collectible_icon_button.pressed.connect(_on_collectible_icon_button_pressed) @@ -36,8 +46,8 @@ func _on_collectible_icon_button_pressed() -> void: TweenFX.fold_in(game_menu) func _on_resume_button_pressed() -> void: - TweenFX.fold_out(game_menu) - await TweenFX.fold_out(game_menu).finished + var tween = TweenFX.fold_out(game_menu) + await tween.finished game_menu_panel.hide() GameState.resume_game() @@ -47,10 +57,11 @@ func _on_time_of_day_row_on_option_changed(data: String) -> void: UIEvents.time_option_item_changed.emit(0) "Day": UIEvents.time_option_item_changed.emit(1) - "Sunset": - UIEvents.time_option_item_changed.emit(2) "Night": UIEvents.time_option_item_changed.emit(3) + "Cycle": + cycle = !cycle + UIEvents.toggle_pause_daytime.emit(cycle) _: pass @@ -80,11 +91,71 @@ func pick_random_weather() -> void: weather_row.on_icon_pressed_changed(random_button) func _on_enable_photo_mode() -> void: + hide_ui_for_photo_mode() photo_mode_texture_mask.scale = Vector2(1,1) - photo_mode_texture_mask.show() + photo_mode_texture_mask.modulate.a = 0.0 + photo_mode_texture_panel.show() + + var mat = photo_mode_texture_panel.material as ShaderMaterial + if mat: + mat.set_shader_parameter("hole_size", Vector2(0.72, 0.0)) + var tween = create_tween() + tween.tween_property(mat, "shader_parameter/hole_size", Vector2(0.72, 0.806), 0.3).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT) + + var alpha_tween = create_tween() + alpha_tween.tween_property(photo_mode_texture_mask, "modulate:a", 1.0, 0.3).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT) + TweenFX.fold_in(photo_mode_texture_mask) func _on_disable_photo_mode() -> void: - TweenFX.fold_out(photo_mode_texture_mask) - await TweenFX.fold_out(photo_mode_texture_mask).finished + show_ui_for_photo_mode() + var mat = photo_mode_texture_panel.material as ShaderMaterial + if mat: + var mat_tween = create_tween() + mat_tween.tween_property(mat, "shader_parameter/hole_size", Vector2(0.72, 0.0), 0.3).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_IN) + + var alpha_tween = create_tween() + alpha_tween.tween_property(photo_mode_texture_mask, "modulate:a", 0.0, 0.3).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN) + + var tween = TweenFX.fold_out(photo_mode_texture_mask) + await tween.finished + photo_mode_texture_panel.hide() + +func _on_photo_capture_prepare() -> void: + photo_mode_texture_panel.hide() photo_mode_texture_mask.hide() + +func _on_photo_taken_started() -> void: + photo_mode_texture_panel.show() + photo_mode_texture_mask.show() + + photo_mode_black_screen.scale = Vector2(1,1) + photo_mode_black_screen.show() + var tween = TweenFX.fade_in(photo_mode_black_screen, 0.06) + await tween.finished + await RenderingServer.frame_post_draw + GameState.on_photo_taken_making.emit() + +func _on_photo_taken_finished() -> void: + var tween = TweenFX.fade_out(photo_mode_black_screen, 0.06) + await tween.finished + photo_mode_black_screen.hide() + +func hide_ui_for_photo_mode() -> void: + TweenFX.fade_out(weather_row, 0.25) + TweenFX.fade_out(time_of_day_row, 0.25) + TweenFX.fade_out(menu_icon_button, 0.25) + TweenFX.fade_out(collection_options, 0.25) + TweenFX.fade_out(audio_player, 0.25) + +func show_ui_for_photo_mode() -> void: + weather_row.show() + time_of_day_row.show() + menu_icon_button.show() + collection_options.show() + audio_player.show() + TweenFX.fade_in(weather_row, 0.25) + TweenFX.fade_in(time_of_day_row, 0.25) + TweenFX.fade_in(menu_icon_button, 0.25) + TweenFX.fade_in(collection_options, 0.25) + TweenFX.fade_in(audio_player, 0.25) diff --git a/core/main_scene_ui/main_scene_ui.tscn b/core/main_scene_ui/main_scene_ui.tscn index 1c3c3c9..a5461ce 100644 --- a/core/main_scene_ui/main_scene_ui.tscn +++ b/core/main_scene_ui/main_scene_ui.tscn @@ -7,7 +7,13 @@ [ext_resource type="PackedScene" uid="uid://cpeyt1dgrtglc" path="res://core/radio/radio.tscn" id="5_nevjt"] [ext_resource type="AudioStream" uid="uid://70cc8she43re" path="res://docs/gyms/radio/lofi_01.ogg" id="6_kd244"] [ext_resource type="PackedScene" uid="uid://dg4f3v0ukpmay" path="res://core/main_scene_ui/audio_player.tscn" id="7_lapqe"] +[ext_resource type="PackedScene" uid="uid://cifadwamy04ko" path="res://core/main_scene_ui/photo_taken.tscn" id="8_t1xop"] [ext_resource type="Texture2D" uid="uid://dcsy5yawnlxhq" path="res://core/photo_mode/assets/reticolo.png" id="9_4cc8f"] +[ext_resource type="Shader" uid="uid://dudbt51v33tt7" path="res://core/main_scene_ui/center_hole.gdshader" id="10_shader"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_hole"] +shader = ExtResource("10_shader") +shader_parameter/hole_size = Vector2(0.72, 0.806) [node name="MainSceneUi" type="Control" unique_id=1359391222] process_mode = 3 @@ -30,6 +36,7 @@ offset_right = 160.0 grow_vertical = 0 [node name="TimeOfDayRow" parent="VBoxContainer" unique_id=1734127019 instance=ExtResource("2_4cc8f")] +unique_name_in_owner = true layout_mode = 2 [node name="IconButton2" parent="VBoxContainer/TimeOfDayRow" index="1" unique_id=638856991] @@ -39,10 +46,10 @@ data = "Sunrise" data = "Day" [node name="IconButton4" parent="VBoxContainer/TimeOfDayRow" index="3" unique_id=1375190490] -data = "Sunset" +data = "Night" [node name="IconButton5" parent="VBoxContainer/TimeOfDayRow" index="4" unique_id=315412403] -data = "Night" +data = "Cycle" [node name="ShowContainerTween" parent="VBoxContainer/TimeOfDayRow" index="5" unique_id=160227524] tween_types = Array[String](["impact_land", "fade_in"]) @@ -93,6 +100,7 @@ offset_left = -160.0 grow_horizontal = 0 [node name="CollectionOptions" type="VBoxContainer" parent="." unique_id=542153805] +unique_name_in_owner = true layout_mode = 1 anchors_preset = 6 anchor_left = 1.0 @@ -114,6 +122,7 @@ unique_name_in_owner = true layout_mode = 2 [node name="AudioPlayer" parent="." unique_id=425192018 node_paths=PackedStringArray("radio") instance=ExtResource("7_lapqe")] +unique_name_in_owner = true layout_mode = 1 anchors_preset = 3 anchor_left = 1.0 @@ -142,9 +151,19 @@ grow_vertical = 2 unique_name_in_owner = true layout_mode = 1 -[node name="PhotoModeTextureMask" type="TextureRect" parent="." unique_id=1377788813] +[node name="PhotoModeTexturePanel" type="Panel" parent="." unique_id=901556197] unique_name_in_owner = true visible = false +material = SubResource("ShaderMaterial_hole") +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="PhotoModeTextureMask" type="TextureRect" parent="PhotoModeTexturePanel" unique_id=1377788813] +unique_name_in_owner = true layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -153,6 +172,31 @@ grow_horizontal = 2 grow_vertical = 2 pivot_offset_ratio = Vector2(0.5, 0.5) texture = ExtResource("9_4cc8f") +stretch_mode = 3 +metadata/_edit_use_anchors_ = true + +[node name="PhotoModeBlackScreen" type="ColorRect" parent="." unique_id=1928591477] +unique_name_in_owner = true +visible = false +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 1) + +[node name="PhotoTaken" parent="." unique_id=683693112 instance=ExtResource("8_t1xop")] +visible = false +layout_mode = 1 +anchor_left = 0.465625 +anchor_top = 0.4287037 +anchor_right = 0.534375 +anchor_bottom = 0.5712963 +offset_right = 0.0 +offset_bottom = 0.0 +grow_horizontal = 2 +grow_vertical = 2 [node name="Radio" parent="." unique_id=1234112225 instance=ExtResource("5_nevjt")] playlist = Array[AudioStream]([ExtResource("6_kd244")]) diff --git a/core/main_scene_ui/photo_taken.gd b/core/main_scene_ui/photo_taken.gd new file mode 100644 index 0000000..1f1e789 --- /dev/null +++ b/core/main_scene_ui/photo_taken.gd @@ -0,0 +1,26 @@ +extends Control + +@onready var photo_texture: TextureRect = $%PhotoTexture + +func _ready() -> void: + GameState.on_photo_taken_prepare.connect(_hide_photo_taken) + GameState.on_photo_taken_finished.connect(_show_photo_taken) + CollectionManager.on_photo_saved.connect(_set_photo_taken) + +func _hide_photo_taken() -> void: + hide() + +func _set_photo_taken(file_path) -> void: + var image = Image.load_from_file(file_path) + if image: + var texture = ImageTexture.create_from_image(image) + photo_texture.texture = texture + +func _show_photo_taken() -> void: + scale = Vector2(1,1) + modulate.a = 1.0 + rotation_degrees = 0.0 + show() + var tween = TweenFX.explode(self, 5, 3) + await tween.finished + hide() diff --git a/core/main_scene_ui/photo_taken.gd.uid b/core/main_scene_ui/photo_taken.gd.uid new file mode 100644 index 0000000..342288c --- /dev/null +++ b/core/main_scene_ui/photo_taken.gd.uid @@ -0,0 +1 @@ +uid://dyye4efo503ih diff --git a/core/main_scene_ui/photo_taken.tscn b/core/main_scene_ui/photo_taken.tscn new file mode 100644 index 0000000..77c2c40 --- /dev/null +++ b/core/main_scene_ui/photo_taken.tscn @@ -0,0 +1,48 @@ +[gd_scene format=3 uid="uid://cifadwamy04ko"] + +[ext_resource type="Script" uid="uid://dyye4efo503ih" path="res://core/main_scene_ui/photo_taken.gd" id="1_1n86s"] + +[node name="PhotoTaken" type="Control" unique_id=683693112] +custom_minimum_size = Vector2(132, 154) +layout_mode = 3 +anchor_right = 0.06875 +anchor_bottom = 0.1425926 +offset_right = -132.0 +offset_bottom = -154.0 +pivot_offset_ratio = Vector2(0.5, 0.5) +script = ExtResource("1_1n86s") +metadata/_edit_use_anchors_ = true + +[node name="ColorRect" type="ColorRect" parent="." unique_id=1876357733] +custom_minimum_size = Vector2(132, 154) +layout_mode = 1 +anchors_preset = -1 +anchor_left = 0.465625 +anchor_top = 0.4287037 +anchor_right = 0.534375 +anchor_bottom = 0.5712963 +grow_horizontal = 2 +grow_vertical = 2 +pivot_offset_ratio = Vector2(0.5, 0.5) +mouse_filter = 2 +metadata/_edit_use_anchors_ = true + +[node name="MarginContainer" type="MarginContainer" parent="ColorRect" unique_id=405077013] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 14 +theme_override_constants/margin_top = 15 +theme_override_constants/margin_right = 14 +theme_override_constants/margin_bottom = 50 + +[node name="PhotoTexture" type="TextureRect" parent="ColorRect/MarginContainer" unique_id=1754898569] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +mouse_filter = 2 +expand_mode = 1 +stretch_mode = 6 diff --git a/core/photo_mode/assets/reticolo.png b/core/photo_mode/assets/reticolo.png index 605752dd89974157083d3c3b2c50b552dd973e1f..5c11dadd8e69ae3bb6836ccaa8f45de8d67b5a8f 100644 GIT binary patch literal 5571 zcmeAS@N?(olHy`uVBq!ia0y~yV9jMr#B}J$;0DnGO1GFmbW6uJ5XGRl zXjB>)45Ps^njC=1V5H{~P>C>Xzyu~vZe`t!~`iGw4rRsXH+*i17)M3M*mQIVl9(uDQAmdKI;Vst0HZ~mRR910 literal 10736 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9)PJL4m>3#WAE}&YRm8IhhPa zTo1ZzGgy1)(lxPf2bC)3G@2BAp6>iD>h(^b1`zmB$sf)EVO~&RV1}?|DFhr2qge(V4EPI&BM+4trT6r5@Z=;jGBEVaRbyt0 zJJ$67DLbtTnZg|&4^D482(*;p*q)UP&+qFq#5|(8t)m4cC{2tOl;E5(T9rbAVYHwG zhXekCa>z8c%5OA-+l&Y1lt(-eVw8Zyv4Rr=s6h$@9RdxYLKg^>SQ5ZALj%XCve5t; zO(CE(Fq#)2Wx{CT01k)I(h?jDqtypE7)A?+(ZYdYG%rw)7am-`Cws?$gPBo)M+M{tg8mFU!Z=-o( zw62GwfziA$0`h|XzPc3*44kV$YXN}XrAmcrwni%c3f`egn3b sb%K1fVg#isY-xXVDj1yKxVGi~X1sh+s&iG2$~2IOr>mdKI;Vst0N3>fEC2ui diff --git a/core/photo_mode/managers/collection_manager.gd b/core/photo_mode/managers/collection_manager.gd index 3d3a2b3..2b61537 100644 --- a/core/photo_mode/managers/collection_manager.gd +++ b/core/photo_mode/managers/collection_manager.gd @@ -31,9 +31,10 @@ func get_all_collectibles() -> Array[CollectibleResource]: func get_unlocked_collectible_ids() -> Array[StringName]: return unlocked_collectibles_ids -func save_photo_to_disk_async() -> void: - await RenderingServer.frame_post_draw - var image = get_viewport().get_texture().get_image() +func save_photo_to_disk_async(image: Image) -> void: + if not image: + return + if not DirAccess.dir_exists_absolute("user://photos"): DirAccess.make_dir_absolute("user://photos") diff --git a/core/photo_mode/runtime/photo_mode_controller.gd b/core/photo_mode/runtime/photo_mode_controller.gd index 9111676..fddc15b 100644 --- a/core/photo_mode/runtime/photo_mode_controller.gd +++ b/core/photo_mode/runtime/photo_mode_controller.gd @@ -21,9 +21,13 @@ var previous_camera: Camera3D var initial_local_pos: Vector3 var initial_local_basis: Basis +var is_making_photo = false +var captured_image: Image + func _ready() -> void: GameState.on_enable_photo_mode_request.connect(enable_photo_mode) GameState.on_disable_photo_mode_request.connect(disable_photo_mode) + GameState.on_photo_taken_making.connect(take_photo_async) initial_local_pos = position initial_local_basis = basis @@ -50,13 +54,23 @@ func _input(event: InputEvent) -> void: if not is_active: GameState.on_enable_photo_mode_request.emit() else: - GameState.on_disable_photo_mode_request.emit() + if not is_making_photo: + GameState.on_disable_photo_mode_request.emit() if event is InputEventMouseMotion and is_active: total_yaw -= event.relative.x * rotation_speed if event.is_action_pressed("take_photo"): - take_photo_async() + if !is_active or is_making_photo: + return + is_making_photo = true + + GameState.on_photo_taken_prepare.emit() + + await RenderingServer.frame_post_draw + captured_image = get_viewport().get_texture().get_image() + + GameState.on_photo_taken_started.emit() func _process(delta: float) -> void: if not is_active: @@ -81,13 +95,10 @@ func _process(delta: float) -> void: basis = rotated_basis.orthonormalized() func take_photo_async() -> void: - if !is_active: - return - var targets = get_tree().get_nodes_in_group("collectible") var space_state = get_world_3d().direct_space_state - await CollectionManager.save_photo_to_disk_async() + await CollectionManager.save_photo_to_disk_async(captured_image) for target in targets: if not target.collectible_data: @@ -104,3 +115,5 @@ func take_photo_async() -> void: CollectionManager.unlock_collectible(target.collectible_data.id) GameState.save_game() + GameState.on_photo_taken_finished.emit() + is_making_photo = false