From 7c78a088a091638b06233333f390e00d15859236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?sijcdu=E7=9A=84=E6=B8=B8=E6=88=8F?= Date: Wed, 7 Oct 2026 21:04:58 +0800 Subject: [PATCH] Add diamond collection and a level-clear door The three diamonds and both doors were painted as tiles in TerrainBase, which cannot act as pickups or triggers. Replaced them with real prefabs that reuse the same atlas tiles (diamond = (7,3), doors = (10,6) and (11,5)) and erase their placeholder tile on ready. Collecting all three diamonds unlocks the door; touching it fades to black, pauses the tree and shows the level-clear screen with a next-level button (currently reloads the level, as there is only one). HUD now shows the diamond count. --- scenes/hud.tscn | 28 +++++++-- scenes/level_clear.tscn | 56 ++++++++++++++++++ scenes/main.tscn | 32 ++++++++++- scenes/prefabs/collectibles/diamond.tscn | 23 ++++++++ scenes/prefabs/interactables/door.tscn | 23 ++++++++ scripts/diamond.gd | 26 +++++++++ scripts/door.gd | 54 ++++++++++++++++++ scripts/hud.gd | 18 ++++-- scripts/level_clear.gd | 72 ++++++++++++++++++++++++ scripts/player_controller.gd | 15 +++++ 10 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 scenes/level_clear.tscn create mode 100644 scenes/prefabs/collectibles/diamond.tscn create mode 100644 scenes/prefabs/interactables/door.tscn create mode 100644 scripts/diamond.gd create mode 100644 scripts/door.gd create mode 100644 scripts/level_clear.gd diff --git a/scenes/hud.tscn b/scenes/hud.tscn index 9d6817d..842420d 100644 --- a/scenes/hud.tscn +++ b/scenes/hud.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=6 format=3] +[gd_scene load_steps=7 format=3] [ext_resource type="Texture2D" path="res://assets/game/tilesets/kenney_tiles_atlas.png" id="1_atlas"] [ext_resource type="Texture2D" path="res://assets/game/collectibles/coin_gold_round.png" id="2_coin"] @@ -12,6 +12,10 @@ region = Rect2(72, 36, 18, 18) atlas = ExtResource("1_atlas") region = Rect2(108, 36, 18, 18) +[sub_resource type="AtlasTexture" id="AtlasTexture_diamond"] +atlas = ExtResource("1_atlas") +region = Rect2(126, 54, 18, 18) + [node name="HUD" type="CanvasLayer"] script = ExtResource("3_hud") full_heart_texture = SubResource("AtlasTexture_heart_full") @@ -54,11 +58,27 @@ theme_override_colors/font_color = Color(1, 1, 1, 1) theme_override_font_sizes/font_size = 12 text = "x0" +[node name="DiamondIcon" type="TextureRect" parent="."] +offset_left = 9.0 +offset_top = 45.0 +offset_right = 27.0 +offset_bottom = 63.0 +texture = SubResource("AtlasTexture_diamond") + +[node name="DiamondLabel" type="Label" parent="."] +offset_left = 30.0 +offset_top = 44.0 +offset_right = 130.0 +offset_bottom = 64.0 +theme_override_colors/font_color = Color(1, 1, 1, 1) +theme_override_font_sizes/font_size = 12 +text = "0 / 3" + [node name="ShieldLabel" type="Label" parent="."] offset_left = 8.0 -offset_top = 46.0 -offset_right = 160.0 -offset_bottom = 66.0 +offset_top = 64.0 +offset_right = 170.0 +offset_bottom = 84.0 theme_override_colors/font_color = Color(0.55, 0.9, 1, 1) theme_override_font_sizes/font_size = 12 text = "" diff --git a/scenes/level_clear.tscn b/scenes/level_clear.tscn new file mode 100644 index 0000000..649f398 --- /dev/null +++ b/scenes/level_clear.tscn @@ -0,0 +1,56 @@ +[gd_scene load_steps=4 format=3] + +[ext_resource type="Script" path="res://scripts/level_clear.gd" id="1_clear"] + +[sub_resource type="SystemFont" id="SystemFont_cjk"] +font_names = PackedStringArray("Microsoft YaHei UI", "Microsoft YaHei", "SimHei", "Noto Sans CJK SC", "sans-serif") + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_button"] +bg_color = Color(0.16, 0.62, 0.36, 1) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 +content_margin_left = 18.0 +content_margin_top = 6.0 +content_margin_right = 18.0 +content_margin_bottom = 6.0 + +[node name="LevelClear" type="CanvasLayer" groups=["level_clear"]] +process_mode = 3 +layer = 20 +script = ExtResource("1_clear") + +[node name="Fade" type="ColorRect" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 +color = Color(0, 0, 0, 0) + +[node name="Center" type="CenterContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 2 + +[node name="VBox" type="VBoxContainer" parent="Center"] +theme_override_constants/separation = 10 + +[node name="Title" type="Label" parent="Center/VBox"] +theme_override_colors/font_color = Color(1, 0.85, 0.3, 1) +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 26 +text = "过关!" +horizontal_alignment = 1 + +[node name="Subtitle" type="Label" parent="Center/VBox"] +theme_override_colors/font_color = Color(0.8, 0.95, 0.85, 1) +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 13 +text = "钻石 3 / 3" +horizontal_alignment = 1 + +[node name="NextButton" type="Button" parent="Center/VBox"] +theme_override_fonts/font = SubResource("SystemFont_cjk") +theme_override_font_sizes/font_size = 14 +theme_override_styles/normal = SubResource("StyleBoxFlat_button") +text = "进入下一关 (R)" diff --git a/scenes/main.tscn b/scenes/main.tscn index e549c73..df84708 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -14,6 +14,9 @@ [ext_resource type="PackedScene" path="res://scenes/hud.tscn" id="21_hud"] [ext_resource type="PackedScene" path="res://scenes/death_screen.tscn" id="22_death"] [ext_resource type="PackedScene" path="res://scenes/prefabs/hazards/spikes_grey.tscn" id="23_spikesgrey"] +[ext_resource type="PackedScene" path="res://scenes/prefabs/collectibles/diamond.tscn" id="24_diamond"] +[ext_resource type="PackedScene" path="res://scenes/prefabs/interactables/door.tscn" id="25_door"] +[ext_resource type="PackedScene" path="res://scenes/level_clear.tscn" id="26_clear"] [node name="Main" type="Node2D" unique_id=2061129075] @@ -21,6 +24,8 @@ [node name="DeathScreen" parent="." unique_id=1952687359 instance=ExtResource("22_death")] +[node name="LevelClear" parent="." instance=ExtResource("26_clear")] + [node name="Level" type="Node2D" parent="." unique_id=1678372922] [node name="Background" type="Node2D" parent="Level" unique_id=702011751] @@ -155,7 +160,7 @@ script = ExtResource("19_hidden") [node name="TerrainBase" type="TileMapLayer" parent="Level/TerrainTileMaps" unique_id=91115499] position = Vector2(9, 9) -tile_map_data = PackedByteArray("AAAAAAEAAAABAAUAAAAEAAEAAAABAAUAAAAFAAEAAAACAAUAAAAGAAEAAAADAAUAAAAMAAEAAAARAAAAAAANAAEAAAASAAAAAAAOAAEAAAATAAAAAAAAAAIAAAAEAAUAAAADAAIAAAABAAUAAAAEAAIAAAAEAAUAAAAFAAIAAAAEAAAAAAAGAAIAAAADAAcAAAALAAIAAAARAAAAAAAMAAIAAAASAAEAAAANAAIAAAASAAEAAAAOAAIAAAATAAEAAAAAAAMAAAACAAYAAAADAAMAAAACAAcAAAAEAAMAAAACAAcAAAAFAAMAAAADAAcAAAALAAMAAAARAAIAAAAMAAMAAAASAAEAAAANAAMAAAASAAEAAAAOAAMAAAATAAEAAAAVAAMAAAANAAcAAAAWAAMAAAAPAAcAAAAAAAQAAAACAAYAAAAEAAQAAAAJAAMAAAAMAAQAAAARAAEAAAANAAQAAAASAAEAAAAOAAQAAAATAAEAAAAEAAUAAAAJAAQAAAAMAAUAAAARAAIAAAANAAUAAAARAAQAAAAOAAUAAAATAAIAAAAWAAUAAAALAAUAAAAEAAYAAAAJAAQAAAAIAAYAAAAJAAEAAAANAAYAAAAQAAQAAAAQAAYAAAANAAcAAAARAAYAAAAOAAcAAAASAAYAAAAPAAcAAAAUAAYAAAALAAIAAAAWAAYAAAALAAYAAAAXAAYAAAAFAAcAAAACAAcAAAABAAEAAAAEAAcAAAAJAAUAAAAGAAcAAAAIAAQAAAANAAcAAAAQAAUAAAAUAAcAAAALAAMAAAAVAAcAAAABAAUAAAAWAAcAAAACAAUAAAAXAAcAAAADAAUAAAAYAAcAAAAGAAUAAAAZAAcAAAAGAAUAAAACAAgAAAABAAYAAAADAAgAAAACAAYAAAAEAAgAAAACAAEAAAAFAAgAAAACAAEAAAAGAAgAAAADAAEAAAAKAAgA//8HAAEAAAAMAAgAAAASAAUAAAANAAgAAAARAAUAAAAOAAgAAAATAAQAABAPAAgAAAASAAQAABAUAAgAAAALAAMAAAAVAAgAAAABAAYAAAAWAAgAAAACAAYAAAAXAAgAAAAEAAEAAAAYAAgAAAACAAUAAAAZAAgAAAACAAUAAAAAAAkAAAACAAEAAAABAAkAAAACAAEAAAACAAkAAAAFAAEAAAADAAkAAAACAAYAAAAEAAkAAAACAAYAAAAFAAkAAAACAAYAAAAGAAkAAAADAAYAAAANAAkAAAAQAAUAAAASAAkAAAAGAAcAAAAUAAkAAAABAAUAAAAVAAkAAAAFAAEAAAAWAAkAAAAEAAUAAAAXAAkAAAACAAYAAAAYAAkAAAACAAYAAAAZAAkAAAACAAYAAAAAAAoAAAAEAAUAAAABAAoAAAACAAYAAAACAAoAAAACAAYAAAADAAoAAAACAAYAAAAEAAoAAAAEAAUAAAAFAAoAAAACAAYAAAAGAAoAAAAEAAEAAAAHAAoAAAADAAEAAAAIAAoAAAAGAAUAAAANAAoAAAARAAYAAAAPAAoAAAAHAAYAAAARAAoAAAAKAAUAAAATAAoAAAAEAAcAAAAUAAoAAAABAAYAAAAVAAoAAAACAAYAAAAWAAoAAAACAAYAAAAXAAoAAAACAAYAAAAYAAoAAAACAAYAAAAZAAoAAAACAAYAAAAAAAsAAAAEAAUAAAABAAsAAAACAAYAAAACAAsAAAAEAAUAAAADAAsAAAAEAAUAAAAEAAsAAAACAAYAAAAFAAsAAAAEAAUAAAAGAAsAAAACAAYAAAAHAAsAAAAEAAEAAAAIAAsAAAADAAEAAAAKAAsAAAAEAAYAAAAMAAsAAAABAAEAAAANAAsAAAACAAEAAAAOAAsAAAACAAMAAAAPAAsAAAADAAMAAAARAAsAAAAKAAYAAAATAAsAAAABAAUAAAAUAAsAAAAFAAEAAAAVAAsAAAACAAYAAAAWAAsAAAAEAAUAAAAXAAsAAAAEAAUAAAAYAAsAAAAEAAUAAAAZAAsAAAACAAYAAAAAAAwAAAACAAYAAAABAAwAAAACAAYAAAACAAwAAAACAAYAAAADAAwAAAAEAAUAAAAEAAwAAAACAAYAAAAFAAwAAAAEAAUAAAAGAAwAAAAEAAUAAAAHAAwAAAAEAAUAAAAIAAwAAAAEAAEAAAAJAAwAAAACAAEAAAAKAAwAAAACAAEAAAALAAwAAAACAAEAAAAMAAwAAAAFAAEAAAANAAwAAAAEAAUAAAAOAAwAAAAEAAUAAAAPAAwAAAAEAAEAAAAQAAwAAAACAAMAAAARAAwAAAACAAMAAAASAAwAAAACAAMAAAATAAwAAAAFAAEAAAAUAAwAAAACAAYAAAAVAAwAAAAEAAUAAAAWAAwAAAACAAYAAAAXAAwAAAAEAAUAAAAYAAwAAAAEAAUAAAAZAAwAAAACAAYAAAAAAA0AAAAEAAUAAAABAA0AAAACAAYAAAACAA0AAAAEAAUAAAADAA0AAAACAAYAAAAEAA0AAAACAAYAAAAFAA0AAAAEAAUAAAAGAA0AAAACAAYAAAAHAA0AAAACAAYAAAAIAA0AAAAEAAUAAAAJAA0AAAACAAYAAAAKAA0AAAAEAAUAAAALAA0AAAAEAAUAAAAMAA0AAAACAAYAAAANAA0AAAACAAYAAAAOAA0AAAAEAAUAAAAPAA0AAAAEAAUAAAAQAA0AAAAEAAUAAAARAA0AAAACAAYAAAASAA0AAAACAAYAAAATAA0AAAAEAAUAAAAUAA0AAAACAAYAAAAVAA0AAAACAAYAAAAWAA0AAAACAAYAAAAXAA0AAAAEAAUAAAAYAA0AAAACAAYAAAAZAA0AAAAEAAUAAAAAAA4AAAACAAYAAAABAA4AAAACAAYAAAACAA4AAAAEAAUAAAADAA4AAAACAAYAAAAEAA4AAAAEAAUAAAAFAA4AAAACAAYAAAAGAA4AAAAEAAUAAAAHAA4AAAAEAAUAAAAIAA4AAAAEAAUAAAAJAA4AAAAEAAUAAAAKAA4AAAAEAAUAAAALAA4AAAAEAAUAAAAMAA4AAAACAAYAAAANAA4AAAACAAYAAAAOAA4AAAACAAYAAAAPAA4AAAACAAYAAAAQAA4AAAAEAAUAAAARAA4AAAACAAYAAAASAA4AAAACAAYAAAATAA4AAAACAAYAAAAUAA4AAAACAAYAAAAVAA4AAAACAAYAAAAWAA4AAAAEAAUAAAAXAA4AAAAEAAUAAAAYAA4AAAACAAYAAAAZAA4AAAAEAAUAAAD//wkAAAACAAEAAAD//woAAAAEAAAAAAD//wsAAAAEAAAAAAD//wwAAAAFAAAAAAD//wQAAAAFAAAAAAD//wIAAAAFAAAAAAD//wMAAAAFAAAAAAD//wEAAAACAAUAAAAAAAUAAAACAAcAAAD//wUAAAACAAcAAAD//w0AAAAEAAEAAAD//w4AAAAEAAEAAAD//wYAAAAJAAAAAAD//wcAAAAJAAAAAAD//wgAAAAJAAAAAAAKAAkAAAAJAAEAAAAVAAIAAAAKAAAAAAABAAUAAAADAAcAAAABAAQAAAADAAUAAAADAAcAAAADAAEAAAANAAAAAAAIAAMAAAAOAAAAAAAIAAMAAAA=") +tile_map_data = PackedByteArray("AAAAAAEAAAABAAUAAAAEAAEAAAABAAUAAAAFAAEAAAACAAUAAAAGAAEAAAADAAUAAAAMAAEAAAARAAAAAAANAAEAAAASAAAAAAAOAAEAAAATAAAAAAAAAAIAAAAEAAUAAAADAAIAAAABAAUAAAAEAAIAAAAEAAUAAAAFAAIAAAAEAAAAAAAGAAIAAAADAAcAAAALAAIAAAARAAAAAAAMAAIAAAASAAEAAAANAAIAAAASAAEAAAAOAAIAAAATAAEAAAAAAAMAAAACAAYAAAADAAMAAAACAAcAAAAEAAMAAAACAAcAAAAFAAMAAAADAAcAAAALAAMAAAARAAIAAAAMAAMAAAASAAEAAAANAAMAAAASAAEAAAAOAAMAAAATAAEAAAAVAAMAAAANAAcAAAAWAAMAAAAPAAcAAAAAAAQAAAACAAYAAAAEAAQAAAAJAAMAAAAMAAQAAAARAAEAAAANAAQAAAASAAEAAAAOAAQAAAATAAEAAAAEAAUAAAAJAAQAAAAMAAUAAAARAAIAAAANAAUAAAARAAQAAAAOAAUAAAATAAIAAAAWAAUAAAALAAUAAAAEAAYAAAAJAAQAAAAIAAYAAAAJAAEAAAANAAYAAAAQAAQAAAAQAAYAAAANAAcAAAARAAYAAAAOAAcAAAASAAYAAAAPAAcAAAAUAAYAAAALAAIAAAAWAAYAAAALAAYAAAACAAcAAAABAAEAAAAEAAcAAAAJAAUAAAAGAAcAAAAIAAQAAAANAAcAAAAQAAUAAAAUAAcAAAALAAMAAAAVAAcAAAABAAUAAAAWAAcAAAACAAUAAAAXAAcAAAADAAUAAAAYAAcAAAAGAAUAAAAZAAcAAAAGAAUAAAACAAgAAAABAAYAAAADAAgAAAACAAYAAAAEAAgAAAACAAEAAAAFAAgAAAACAAEAAAAGAAgAAAADAAEAAAAMAAgAAAASAAUAAAANAAgAAAARAAUAAAAOAAgAAAATAAQAABAPAAgAAAASAAQAABAUAAgAAAALAAMAAAAVAAgAAAABAAYAAAAWAAgAAAACAAYAAAAXAAgAAAAEAAEAAAAYAAgAAAACAAUAAAAZAAgAAAACAAUAAAAAAAkAAAACAAEAAAABAAkAAAACAAEAAAACAAkAAAAFAAEAAAADAAkAAAACAAYAAAAEAAkAAAACAAYAAAAFAAkAAAACAAYAAAAGAAkAAAADAAYAAAANAAkAAAAQAAUAAAASAAkAAAAGAAcAAAAUAAkAAAABAAUAAAAVAAkAAAAFAAEAAAAWAAkAAAAEAAUAAAAXAAkAAAACAAYAAAAYAAkAAAACAAYAAAAZAAkAAAACAAYAAAAAAAoAAAAEAAUAAAABAAoAAAACAAYAAAACAAoAAAACAAYAAAADAAoAAAACAAYAAAAEAAoAAAAEAAUAAAAFAAoAAAACAAYAAAAGAAoAAAAEAAEAAAAHAAoAAAADAAEAAAAIAAoAAAAGAAUAAAANAAoAAAARAAYAAAAPAAoAAAAHAAYAAAARAAoAAAAKAAUAAAATAAoAAAAEAAcAAAAUAAoAAAABAAYAAAAVAAoAAAACAAYAAAAWAAoAAAACAAYAAAAXAAoAAAACAAYAAAAYAAoAAAACAAYAAAAZAAoAAAACAAYAAAAAAAsAAAAEAAUAAAABAAsAAAACAAYAAAACAAsAAAAEAAUAAAADAAsAAAAEAAUAAAAEAAsAAAACAAYAAAAFAAsAAAAEAAUAAAAGAAsAAAACAAYAAAAHAAsAAAAEAAEAAAAIAAsAAAADAAEAAAAKAAsAAAAEAAYAAAAMAAsAAAABAAEAAAANAAsAAAACAAEAAAAOAAsAAAACAAMAAAAPAAsAAAADAAMAAAARAAsAAAAKAAYAAAATAAsAAAABAAUAAAAUAAsAAAAFAAEAAAAVAAsAAAACAAYAAAAWAAsAAAAEAAUAAAAXAAsAAAAEAAUAAAAYAAsAAAAEAAUAAAAZAAsAAAACAAYAAAAAAAwAAAACAAYAAAABAAwAAAACAAYAAAACAAwAAAACAAYAAAADAAwAAAAEAAUAAAAEAAwAAAACAAYAAAAFAAwAAAAEAAUAAAAGAAwAAAAEAAUAAAAHAAwAAAAEAAUAAAAIAAwAAAAEAAEAAAAJAAwAAAACAAEAAAAKAAwAAAACAAEAAAALAAwAAAACAAEAAAAMAAwAAAAFAAEAAAANAAwAAAAEAAUAAAAOAAwAAAAEAAUAAAAPAAwAAAAEAAEAAAAQAAwAAAACAAMAAAARAAwAAAACAAMAAAASAAwAAAACAAMAAAATAAwAAAAFAAEAAAAUAAwAAAACAAYAAAAVAAwAAAAEAAUAAAAWAAwAAAACAAYAAAAXAAwAAAAEAAUAAAAYAAwAAAAEAAUAAAAZAAwAAAACAAYAAAAAAA0AAAAEAAUAAAABAA0AAAACAAYAAAACAA0AAAAEAAUAAAADAA0AAAACAAYAAAAEAA0AAAACAAYAAAAFAA0AAAAEAAUAAAAGAA0AAAACAAYAAAAHAA0AAAACAAYAAAAIAA0AAAAEAAUAAAAJAA0AAAACAAYAAAAKAA0AAAAEAAUAAAALAA0AAAAEAAUAAAAMAA0AAAACAAYAAAANAA0AAAACAAYAAAAOAA0AAAAEAAUAAAAPAA0AAAAEAAUAAAAQAA0AAAAEAAUAAAARAA0AAAACAAYAAAASAA0AAAACAAYAAAATAA0AAAAEAAUAAAAUAA0AAAACAAYAAAAVAA0AAAACAAYAAAAWAA0AAAACAAYAAAAXAA0AAAAEAAUAAAAYAA0AAAACAAYAAAAZAA0AAAAEAAUAAAAAAA4AAAACAAYAAAABAA4AAAACAAYAAAACAA4AAAAEAAUAAAADAA4AAAACAAYAAAAEAA4AAAAEAAUAAAAFAA4AAAACAAYAAAAGAA4AAAAEAAUAAAAHAA4AAAAEAAUAAAAIAA4AAAAEAAUAAAAJAA4AAAAEAAUAAAAKAA4AAAAEAAUAAAALAA4AAAAEAAUAAAAMAA4AAAACAAYAAAANAA4AAAACAAYAAAAOAA4AAAACAAYAAAAPAA4AAAACAAYAAAAQAA4AAAAEAAUAAAARAA4AAAACAAYAAAASAA4AAAACAAYAAAATAA4AAAACAAYAAAAUAA4AAAACAAYAAAAVAA4AAAACAAYAAAAWAA4AAAAEAAUAAAAXAA4AAAAEAAUAAAAYAA4AAAACAAYAAAAZAA4AAAAEAAUAAAD//wkAAAACAAEAAAD//woAAAAEAAAAAAD//wsAAAAEAAAAAAD//wwAAAAFAAAAAAD//wQAAAAFAAAAAAD//wIAAAAFAAAAAAD//wMAAAAFAAAAAAD//wEAAAACAAUAAAAAAAUAAAACAAcAAAD//wUAAAACAAcAAAD//w0AAAAEAAEAAAD//w4AAAAEAAEAAAD//wYAAAAJAAAAAAD//wcAAAAJAAAAAAD//wgAAAAJAAAAAAAKAAkAAAAJAAEAAAABAAUAAAADAAcAAAABAAQAAAADAAUAAAADAAcAAAADAAEAAAANAAAAAAAIAAMAAAAOAAAAAAAIAAMAAAAWAAIAAAAHAAMAAAAEAAAAAAAHAAMAAAAOAAcAAAAHAAMAAAA=") tile_set = ExtResource("5_4etix") [node name="TerrainDetailsA" type="TileMapLayer" parent="Level/TerrainTileMaps" unique_id=1513560262] @@ -192,11 +197,11 @@ position = Vector2(270, 216) z_index = 5 position = Vector2(216, 216) -[node name="SpikesGrey_01" parent="Level/PrefabInstances/Hazards" instance=ExtResource("23_spikesgrey")] +[node name="SpikesGrey_01" parent="Level/PrefabInstances/Hazards" unique_id=214833071 instance=ExtResource("23_spikesgrey")] z_index = 5 position = Vector2(252, 18) -[node name="SpikesGrey_02" parent="Level/PrefabInstances/Hazards" instance=ExtResource("23_spikesgrey")] +[node name="SpikesGrey_02" parent="Level/PrefabInstances/Hazards" unique_id=458791480 instance=ExtResource("23_spikesgrey")] z_index = 5 position = Vector2(270, 18) @@ -206,6 +211,15 @@ position = Vector2(270, 18) z_index = 5 position = Vector2(325, 108) +[node name="Door_01" parent="Level/PrefabInstances/Interactables" instance=ExtResource("25_door")] +z_index = 5 +position = Vector2(324, 216) + +[node name="Door_02" parent="Level/PrefabInstances/Interactables" instance=ExtResource("25_door")] +z_index = 5 +position = Vector2(414, 108) +atlas_region = Rect2(198, 90, 18, 18) + [node name="Collectibles" type="Node2D" parent="Level/PrefabInstances" unique_id=2086540192] [node name="CoinGoldRound_01" parent="Level/PrefabInstances/Collectibles" unique_id=926105584 instance=ExtResource("17_rmlt8")] @@ -224,4 +238,16 @@ position = Vector2(315, 63) z_index = 5 position = Vector2(126, 144) +[node name="Diamond_01" parent="Level/PrefabInstances/Collectibles" instance=ExtResource("24_diamond")] +z_index = 5 +position = Vector2(90, 18) + +[node name="Diamond_02" parent="Level/PrefabInstances/Collectibles" instance=ExtResource("24_diamond")] +z_index = 5 +position = Vector2(414, 54) + +[node name="Diamond_03" parent="Level/PrefabInstances/Collectibles" instance=ExtResource("24_diamond")] +z_index = 5 +position = Vector2(270, 144) + [node name="Signs" type="Node2D" parent="Level/PrefabInstances" unique_id=113197076] diff --git a/scenes/prefabs/collectibles/diamond.tscn b/scenes/prefabs/collectibles/diamond.tscn new file mode 100644 index 0000000..2cc0ea0 --- /dev/null +++ b/scenes/prefabs/collectibles/diamond.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=5 format=3] + +[ext_resource type="Texture2D" path="res://assets/game/tilesets/kenney_tiles_atlas.png" id="1_atlas"] +[ext_resource type="Script" path="res://scripts/diamond.gd" id="2_diamond"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_diamond"] +atlas = ExtResource("1_atlas") +region = Rect2(126, 54, 18, 18) + +[sub_resource type="CircleShape2D" id="Shape_diamond"] +radius = 7.0 + +[node name="Diamond" type="Area2D" groups=["diamond"]] +collision_layer = 16 +collision_mask = 2 +script = ExtResource("2_diamond") + +[node name="Sprite" type="Sprite2D" parent="."] +texture_filter = 1 +texture = SubResource("AtlasTexture_diamond") + +[node name="PickupArea" type="CollisionShape2D" parent="."] +shape = SubResource("Shape_diamond") diff --git a/scenes/prefabs/interactables/door.tscn b/scenes/prefabs/interactables/door.tscn new file mode 100644 index 0000000..6f668f8 --- /dev/null +++ b/scenes/prefabs/interactables/door.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=5 format=3] + +[ext_resource type="Texture2D" path="res://assets/game/tilesets/kenney_tiles_atlas.png" id="1_atlas"] +[ext_resource type="Script" path="res://scripts/door.gd" id="2_door"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_door"] +atlas = ExtResource("1_atlas") +region = Rect2(180, 108, 18, 18) + +[sub_resource type="RectangleShape2D" id="Shape_door"] +size = Vector2(18, 18) + +[node name="Door" type="Area2D" groups=["door"]] +collision_layer = 8 +collision_mask = 2 +script = ExtResource("2_door") + +[node name="Sprite" type="Sprite2D" parent="."] +texture_filter = 1 +texture = SubResource("AtlasTexture_door") + +[node name="TriggerArea" type="CollisionShape2D" parent="."] +shape = SubResource("Shape_door") diff --git a/scripts/diamond.gd b/scripts/diamond.gd new file mode 100644 index 0000000..d1edea3 --- /dev/null +++ b/scripts/diamond.gd @@ -0,0 +1,26 @@ +extends Area2D + +## 钻石:走过去自动收集,集齐后碰门过关 +@export var erase_placeholder_tile: bool = true + + +func _ready() -> void: + body_entered.connect(_on_body_entered) + if erase_placeholder_tile: + _erase_placeholder_tile() + + +func _on_body_entered(body: Node2D) -> void: + if body.has_method("add_diamond"): + body.add_diamond() + queue_free() + + +func _erase_placeholder_tile() -> void: + var root: Node = owner if owner != null else get_parent() + if root == null: + return + for layer in root.find_children("*", "TileMapLayer", true, false): + var cell: Vector2i = layer.local_to_map(layer.to_local(global_position)) + if layer.get_cell_source_id(cell) != -1: + layer.erase_cell(cell) diff --git a/scripts/door.gd b/scripts/door.gd new file mode 100644 index 0000000..1d9676d --- /dev/null +++ b/scripts/door.gd @@ -0,0 +1,54 @@ +extends Area2D + +## 门:集齐钻石后碰到就过关;没集齐则闪一下红色提示。 +@export var required_diamonds: int = 3 +## 门贴图在图集里的区域(不同门可以不一样) +@export var atlas_region: Rect2 = Rect2(180, 108, 18, 18) +## 开场时擦掉脚下的占位地砖 +@export var erase_placeholder_tile: bool = true + +const ATLAS := preload("res://assets/game/tilesets/kenney_tiles_atlas.png") + +var _sprite: Sprite2D = null + + +func _ready() -> void: + body_entered.connect(_on_body_entered) + _sprite = get_node_or_null("Sprite") + if _sprite != null: + var tex := AtlasTexture.new() + tex.atlas = ATLAS + tex.region = atlas_region + _sprite.texture = tex + if erase_placeholder_tile: + _erase_placeholder_tile() + + +func _on_body_entered(body: Node2D) -> void: + if not body.has_method("add_diamond"): + return + if int(body.diamonds) < required_diamonds: + _flash_locked() + return + var clear := get_tree().get_first_node_in_group("level_clear") + if clear != null: + clear.show_clear() + + +func _flash_locked() -> void: + if _sprite == null: + return + _sprite.modulate = Color(1.0, 0.45, 0.45) + await get_tree().create_timer(0.4).timeout + if is_instance_valid(_sprite): + _sprite.modulate = Color.WHITE + + +func _erase_placeholder_tile() -> void: + var root: Node = owner if owner != null else get_parent() + if root == null: + return + for layer in root.find_children("*", "TileMapLayer", true, false): + var cell: Vector2i = layer.local_to_map(layer.to_local(global_position)) + if layer.get_cell_source_id(cell) != -1: + layer.erase_cell(cell) diff --git a/scripts/hud.gd b/scripts/hud.gd index ddf5030..9d0e990 100644 --- a/scripts/hud.gd +++ b/scripts/hud.gd @@ -1,6 +1,6 @@ extends CanvasLayer -## 左上角的状态显示:3 颗心 + 回血道具数量 + 护盾剩余时间。 +## 左上角的状态显示:3 颗心 + 回血道具数量 + 钻石数量 + 护盾剩余时间。 ## 每帧从场景里找带 "player" 组的玩家读取状态。 @export var full_heart_texture: Texture2D @@ -9,6 +9,7 @@ extends CanvasLayer var _player: Node = null var _hearts: Array = [] var _count_label: Label = null +var _diamond_label: Label = null var _shield_label: Label = null @@ -18,6 +19,7 @@ func _ready() -> void: if heart != null: _hearts.append(heart) _count_label = get_node_or_null("CountLabel") + _diamond_label = get_node_or_null("DiamondLabel") _shield_label = get_node_or_null("ShieldLabel") @@ -37,9 +39,15 @@ func _process(_delta: float) -> void: _count_label.text = "x%d" % items _count_label.modulate = Color.WHITE if items > 0 else Color(1.0, 1.0, 1.0, 0.4) + if _diamond_label != null: + var got: int = int(_player.diamonds) + var total: int = maxi(int(_player.diamond_total), got) + _diamond_label.text = "%d / %d" % [got, total] + if total > 0 and got >= total: + _diamond_label.modulate = Color(1.0, 0.9, 0.35) + else: + _diamond_label.modulate = Color.WHITE + if _shield_label != null: var shield: float = float(_player.shield_left) - if shield > 0.0: - _shield_label.text = "SHIELD %.1fs" % shield - else: - _shield_label.text = "" + _shield_label.text = ("SHIELD %.1fs" % shield) if shield > 0.0 else "" diff --git a/scripts/level_clear.gd b/scripts/level_clear.gd new file mode 100644 index 0000000..57dfab7 --- /dev/null +++ b/scripts/level_clear.gd @@ -0,0 +1,72 @@ +extends CanvasLayer + +## 过关界面:集齐钻石后碰到门显示。 +## 显示时把整棵树暂停,所以这一层的 process_mode 设成 ALWAYS(见 .tscn), +## 不然暂停后自己的动画和按钮也会停。 + +@export var fade_time: float = 0.8 +@export var button_delay: float = 0.3 + +var _fade: ColorRect = null +var _center: CenterContainer = null +var _button: Button = null +var _title: Label = null +var _subtitle: Label = null +var _elapsed: float = 0.0 +var _showing: bool = false + + +func _ready() -> void: + visible = false + _fade = get_node_or_null("Fade") + _center = get_node_or_null("Center") + _button = get_node_or_null("Center/VBox/NextButton") + _title = get_node_or_null("Center/VBox/Title") + _subtitle = get_node_or_null("Center/VBox/Subtitle") + if _button != null: + _button.pressed.connect(next_level) + if _fade != null: + _fade.color = Color(0.0, 0.0, 0.0, 0.0) + if _center != null: + _center.visible = false + + +func show_clear() -> void: + if _showing: + return + _showing = true + visible = true + _elapsed = 0.0 + if _title != null: + _title.text = "过关!" + if _subtitle != null: + var player := get_tree().get_first_node_in_group("player") + var n: int = 0 if player == null else int(player.diamonds) + _subtitle.text = "钻石 %d / %d" % [n, n] + get_tree().paused = true + + +func _process(delta: float) -> void: + if not _showing: + return + _elapsed += delta + if _fade != null: + _fade.color = Color(0.0, 0.0, 0.0, clampf(_elapsed / maxf(fade_time, 0.01), 0.0, 1.0)) + if _center != null and _elapsed >= fade_time + button_delay: + _center.visible = true + + +func _unhandled_input(event: InputEvent) -> void: + if not _showing: + return + var key := event as InputEventKey + if key != null and key.pressed and not key.echo: + if key.physical_keycode == KEY_R or key.physical_keycode == KEY_ENTER: + next_level() + + +## 目前项目里只有一关,所以"下一关"先做成重新加载本关。 +## 以后真加了第二关,把这里换成 change_scene_to_file("res://scenes/level2.tscn") 即可。 +func next_level() -> void: + get_tree().paused = false + get_tree().reload_current_scene() diff --git a/scripts/player_controller.gd b/scripts/player_controller.gd index a23ac5b..d9310bd 100644 --- a/scripts/player_controller.gd +++ b/scripts/player_controller.gd @@ -60,6 +60,10 @@ var hurt_count: int = 0 var health: int = 3 ## 身上的回血道具数量(捡到的小球) var heal_items: int = 0 +## 已收集的钻石数量 +var diamonds: int = 0 +## 关卡里钻石总数(开场自动数一遍) +var diamond_total: int = 0 ## 无敌盾剩余时间,给 HUD 显示用 var shield_left: float = 0.0 ## 生命值归零后进入死亡状态:不能操作,交给死亡界面 @@ -84,6 +88,12 @@ func _ready() -> void: _measure_feet_offset() _spawn_point = global_position health = max_health + # 等一帧再数钻石,确保关卡里所有钻石节点都已经 _ready + _count_diamond_total.call_deferred() + + +func _count_diamond_total() -> void: + diamond_total = get_tree().get_nodes_in_group("diamond").size() func _physics_process(delta: float) -> void: @@ -182,6 +192,11 @@ func add_heal_item() -> void: heal_items += 1 +## 由钻石调用 +func add_diamond() -> void: + diamonds += 1 + + ## 按 Z:消耗一个回血道具,回一颗心并获得无敌盾 func use_heal_item() -> bool: if is_dead or heal_items <= 0: