feature/whaletown-developer-extra-feature #19

Merged
moyin merged 9 commits from feature/whaletown-developer-extra-feature into main 2026-03-11 18:23:00 +08:00
4 changed files with 114 additions and 19 deletions
Showing only changes of commit fa38b75d8f - Show all commits

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=40 format=4 uid="uid://5cc0c6cpnhe8"]
[gd_scene load_steps=41 format=4 uid="uid://5cc0c6cpnhe8"]
[ext_resource type="Script" uid="uid://b43tvo8cykfrq" path="res://scenes/Maps/BaseLevel.gd" id="1_m4als"]
[ext_resource type="Texture2D" uid="uid://baa5wkuyqouh6" path="res://assets/sprites/environment/standard_brick_128_128.jpg" id="1_rb5kq"]
@@ -19,6 +19,7 @@
[ext_resource type="PackedScene" uid="uid://bvfyllcy5fi8o" path="res://scenes/Maps/datawhale_home.tscn" id="16_m4als"]
[ext_resource type="PackedScene" uid="uid://rdmrm7j4iokr" path="res://scenes/prefabs/items/notice_board.tscn" id="16_rixdf"]
[ext_resource type="Script" uid="uid://d2od22agputjt" path="res://scenes/prefabs/items/WelcomeBoard.gd" id="16_u1t8b"]
[ext_resource type="PackedScene" path="res://scenes/characters/crayfish_npc.tscn" id="17_crayfish"]
[ext_resource type="Script" uid="uid://rlkavptfhr4y" path="res://scenes/Maps/DoorTeleport.gd" id="18_0xqio"]
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_7nixu"]
@@ -1082,6 +1083,9 @@ position = Vector2(0, 320)
[node name="NPC" parent="." instance=ExtResource("15_0xqio")]
position = Vector2(-81, -64)
[node name="CrayfishNpc" parent="." instance=ExtResource("17_crayfish")]
position = Vector2(88, 286)
[node name="DataWhaleHome" parent="." instance=ExtResource("16_m4als")]
position = Vector2(8, -128)

View File

@@ -1,29 +1,55 @@
extends CharacterBody2D
signal interaction_happened(text)
# ============================================================================
# 文件名: NPCController.gd
# 作用: 通用 NPC 控制器,负责角色待机表现与交互对话
#
# 主要功能:
# - 播放 NPC 待机动画
# - 响应玩家射线交互
# - 触发聊天气泡与 NPC 对话事件
#
# 依赖: EventSystem, EventNames, ChatBubble
# 作者: Codex
# 创建时间: 2026-03-10
# ============================================================================
signal interaction_happened(text: String)
const CHAT_BUBBLE_SCENE: PackedScene = preload("res://scenes/ui/ChatBubble.tscn")
@export var npc_name: String = "NPC"
@export var dialogue: String = "欢迎来到WhaleTown我是镇长范鲸晶"
@export_multiline var dialogue: String = "欢迎来到WhaleTown我是镇长范鲸晶"
func _ready():
$Sprite2D.texture = preload("res://assets/characters/npc_286_241.png")
$Sprite2D.hframes = 4
$Sprite2D.vframes = 4
@onready var animation_player: AnimationPlayer = $AnimationPlayer
# Start Idle Animation
if has_node("AnimationPlayer"):
$AnimationPlayer.play("idle")
func _ready() -> void:
# 播放场景里配置好的待机动画,让不同 NPC 可以复用同一个控制器。
if animation_player.has_animation("idle"):
animation_player.play("idle")
# Ensure interaction layer
collision_layer = 3 # Layer 1 & 2 (Blocking)
# 保持 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)

View File

@@ -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")
}