From fa38b75d8f4eda97c51cde2a052e90412873372e Mon Sep 17 00:00:00 2001 From: xiangwang Date: Tue, 10 Mar 2026 22:51:38 +0800 Subject: [PATCH] feat: add crayfish npc to square map --- assets/characters/crayfish_npc_256_256.png | Bin 0 -> 8794 bytes scenes/Maps/square.tscn | 6 +- scenes/characters/NPCController.gd | 62 ++++++++++++++------ scenes/characters/crayfish_npc.tscn | 65 +++++++++++++++++++++ 4 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 assets/characters/crayfish_npc_256_256.png create mode 100644 scenes/characters/crayfish_npc.tscn diff --git a/assets/characters/crayfish_npc_256_256.png b/assets/characters/crayfish_npc_256_256.png new file mode 100644 index 0000000000000000000000000000000000000000..6af8dd6a36a4a59cd619e112c10f36d1697998f9 GIT binary patch literal 8794 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 void: + # 播放场景里配置好的待机动画,让不同 NPC 可以复用同一个控制器。 + if animation_player.has_animation("idle"): + animation_player.play("idle") + + # 保持 NPC 可被玩家射线与角色碰撞识别。 + collision_layer = 3 collision_mask = 3 -func interact(): +# 处理玩家交互,展示气泡并向全局事件系统广播。 +func interact() -> void: show_bubble(dialogue) + EventSystem.emit_event(EventNames.NPC_TALKED, { + "npc": self, + "npc_name": npc_name, + "dialogue": dialogue + }) interaction_happened.emit(dialogue) - return null -func show_bubble(text): - var bubble = preload("res://scenes/ui/ChatBubble.tscn").instantiate() +# 在 NPC 头顶生成一次性聊天气泡。 +# +# 参数: +# text: String - 要展示的对话内容 +func show_bubble(text: String) -> void: + var bubble: Control = CHAT_BUBBLE_SCENE.instantiate() as Control + if bubble == null: + return add_child(bubble) - bubble.set_text(text) + if bubble.has_method("set_text"): + bubble.call("set_text", text) diff --git a/scenes/characters/crayfish_npc.tscn b/scenes/characters/crayfish_npc.tscn new file mode 100644 index 0000000..3f20bb1 --- /dev/null +++ b/scenes/characters/crayfish_npc.tscn @@ -0,0 +1,65 @@ +[gd_scene load_steps=7 format=3] + +[ext_resource type="Texture2D" path="res://assets/characters/crayfish_npc_256_256.png" id="1_texture"] +[ext_resource type="Script" path="res://scenes/characters/NPCController.gd" id="2_script"] + +[sub_resource type="RectangleShape2D" id="1_shape"] +size = Vector2(44, 22) + +[sub_resource type="Animation" id="2_reset"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [0] +} + +[sub_resource type="Animation" id="3_idle"] +resource_name = "idle" +length = 1.2 +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0.0333333, 0.26666665, 0.4666667, 0.8, 1), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1), +"update": 1, +"values": [2, 1, 0, 4, 5] +} + +[sub_resource type="AnimationLibrary" id="4_library"] +_data = { +&"RESET": SubResource("2_reset"), +&"idle": SubResource("3_idle") +} + +[node name="CrayfishNpc" type="CharacterBody2D"] +script = ExtResource("2_script") +npc_name = "虾小满" +dialogue = "欢迎来到 WhaleTown!我是虾小满,负责看着喷泉边的水路和码头消息。想找热闹的地方,顺着水边走就对啦。" + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("1_texture") +hframes = 4 +vframes = 4 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +light_mask = 5 +visibility_layer = 5 +shape = SubResource("1_shape") + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +&"": SubResource("4_library") +}