docs: CHARACTER.md 角色设定文档 基于 3 层楼场景房间 + 11 种 NPC 素材 + 玩家角色,完整角色设定: 角色总览表(12 个角色实体:1 玩家 + 4 护士 + 3 医生 + 2 辅助 + 2 患者外观) 玩家医生白(观察者身份,特殊帧格式) 4 种护士(分诊/急救/住院/检验科):身份/颜色/楼层/房间/帧/LLM 角色/行为 3 种医生(急诊红/急诊绿/手术):含红色=抢救/绿色=普通的色彩语义 2 种辅助岗(检验员蓝/质控员灰):暂无 LLM prompt,待策划 2 种患者(绿/蓝):含 walk_flip up/down 特殊帧格式 + 5 个预设病例 角色-房间映射矩阵(3 层楼所有房间 + 驻守/流经角色) 素材清单(14 个源 PNG + 11 个切片帧目录 + 网格映射图) 通用行为规则(移动/对话/记忆/状态机/资源调度) 扩展建议(缺失 prompt/缺失流程/角色关系/日程换班) 附录:急诊分诊四级色彩语义对照表
docs: CHARACTER.md 角色设定文档
基于 3 层楼场景房间 + 11 种 NPC 素材 + 玩家角色,完整角色设定:
Godot 4.7 2D 俯视角医院模拟。NPC 由 LLM (DeepSeek-V4-Flash) 实时驱动对话、分诊、移动。玩家自主操控角色在急诊科探索。
核心架构:Godot → Gitee AI (HTTP)。无 Python 后端,无进程管理。
# 直接打开 project.godot,按 F5 运行 godot project.godot
NPC 自主对话、移动、分诊,不需要手动启动任何服务。
godot --headless --audio-driver Dummy --export-release Web build/web/index.html cd build\web && python -m http.server 8080
在线版:https://so-cean.github.io/MedSquad-/
玩家扮演来急诊就诊的患者,在真实医院流程中被分诊、检查、治疗、转归。所有医护人员由 LLM 驱动,有独立人格、专业知识和记忆。
玩家到达急诊 ↓ 护士分诊问诊(LLM对话:问症状→追问→判断→指示) ↓ 按护士指示去对应区域(NPC自主寻路) ↓ 医生检查问诊(LLM对话:查体→开检查) ↓ 去检查科室(CT/检验/影像) ↓ 回诊室看结果(LLM对话:诊断→治疗方案) ↓ 转归:住院/出院/留观
多对一:护士同时处理多个AI患者NPC,按病情优先级排序。NPC完全自主——对话、移动、状态切换不需要玩家干预。
Godot F5 └─ DialogueTest.tscn (测试场景,含完整地图+碰撞+NPC) ├─ NpcManager (autoload) — 上帝视角:自动发现NPC + 自主对话循环 + 动态spawn/discharged │ ├─ ConversationContext — 多对一对话编排 (prompt + 记忆路由 + conversation_done) │ └─ NPC_FSM (无状态) — request(id, prompt) → action_ready │ └─ HTTPRequest → Gitee AI (DeepSeek-V4-Flash) ├─ MapSystem (autoload) — NavigationRegion2D + 路径查询 + 区域触发器 ├─ HospitalMapData (autoload) — 命名位置→Vector2,3个楼层 ├─ MemoryStore (per-NPC, class_name) — 对话历史 + 按伙伴分组检索 + 磁盘持久化 └─ DialogueManager (autoload) — 气泡池 + 自动轮询 + 气泡不重叠 + 播完自动销毁
NpcManager
ConversationContext
npc_fsm.gd
MemoryStore
DialogueManager
DialogueBubble
MapSystem
HospitalMapData
scripts/dialogue/dialogue_manager.gd
scripts/edmas/npc_manager.gd
scripts/edmas/map_system.gd
scripts/edmas/hospital_map_data.gd
护士一次LLM调用处理多个患者,返回结构化response:
{ "think": "腹痛2级危重,头痛3级急症,优先处理P2", "responses": [ {"target": "patient_001", "utterances": ["您先在候诊区等"], "conversation_done": false}, {"target": "patient_002", "utterances": ["马上跟我进抢救室"], "conversation_done": true} ] }
get_context_for_partner(patient_id)
患者走近护士(approach_and_face → walk_to + 到达后面对面) ↓ 患者说主诉 → 护士追问 → 患者补充 → 护士判断 → 给指示 → conversation_done ↓ 患者walk_to目标房间(候诊区/抢救室/诊室) ↓ 护士切换下一个患者
LLM调用和气泡显示重叠:
response到达 → 显示bubble + 立即发下一个LLM调用 ↓ bubble播放中 ↓ LLM在飞 bubble完 → 下个response已到 → 直接显示
show_entry(entry) ├─ THINK: 蓝色文字 typewriter (0.035s/字) │ → 完成后暂停0.4s → 颜色过渡到黑色 └─ UTTERANCE: utterances[] 逐条追加显示 → 每条显示时间 = max(字数/10, 1.2s) → 全部播完 → done() → 自动fade_out
详见 scripts/dialogue/README.md。
scripts/dialogue/README.md
MemoryStore (class_name, per-NPC) ├─ add_dialogue(speaker, listener, think, text, importance, keywords) ├─ get_context_str(count) — 最近N条格式化字符串 ├─ get_context_for_partner(partner_id, count) — 按对话伙伴过滤 └─ 磁盘持久化: user://npc_memories/{node_name}/nodes.json
重要:用节点名(唯一)做文件路径,不用display_name。两个同名NPC不会共享记忆。
跨NPC记忆路由:患者发言→存入护士记忆(标注patient_id),护士回应→按target路由到对应患者。
MapSystem (autoload, 解耦) ├─ NavigationRegion2D — 从墙体CollisionPolygon自动构建navmesh ├─ query_path(from, location) — 路径查询 ├─ ensure_nav_agent(body) — 给任意CharacterBody2D自动创建NavigationAgent2D ├─ Area触发器 — 从Marker2D自动生成Area2D (60px半径) │ ├─ body_entered → npc_arrived信号 │ └─ body_exited → npc_left_area信号 └─ change_floor(id) — 切换楼层场景
不依赖任何其他系统 — 不知道NpcManager、ConversationContext、DialogueSystem、LLM。
NPC导航:npc.walk_to("TRIAGE") → 自动创建NavAgent + 寻路 + 沿路径移动 + 到达信号。 NPC不做物理碰撞(穿墙移动),导航路径基于碰撞体绕墙。
npc.walk_to("TRIAGE")
BaseNpc.NpcState: ARRIVED → WAITING → GOING_TO_ROOM → BEING_EXAMINED → DISCHARGED
get_state_name()
set_state(GOING_TO_ROOM, "候诊区")
face_toward(pos)
approach_and_face(npc, 60)
arrived_at
NPC移动速度90px/s,无物理碰撞,沿navmesh路径移动。
NpcManager发射的事件信号:
patient_arrived
triage_started
triage_done
npc_arrived_at
all_triage_done
patient_discharged
scens/edmas/DialogueTest.tscn — 完整地图 + 碰撞 + NPC自主分诊
scens/edmas/DialogueTest.tscn
NpcManager自动发现3个NPC → start_auto_loop() ↓ P1走近护士 → 对话 → 分诊完成 → P1 walk_to候诊区 ↓ P2走近护士 → 对话 → 分诊完成 → P2 walk_to诊室 ↓ 全部分诊完成 → print_status() → 测试结束
打开 project.godot 按 F5 运行。
project.godot
Floor_ED_Core.tscn
Floor_Diagnostics.tscn
Floor_Downstream.tscn
按 E 上楼、Q 下楼。
scripts/ ├── edmas/ │ ├── npc_fsm.gd 无状态LLM代理 (HTTP + JSON + 智能fallback) │ ├── conversation_context.gd 多对一对话编排 (prompt + 记忆路由 + conversation_done) │ ├── npc_manager.gd 上帝视角NPC管理 + 自主对话循环 + 事件总线 (autoload) │ ├── map_system.gd NavigationRegion2D + 路径查询 + 区域触发器 (autoload) │ ├── hospital_map_data.gd 命名位置 + 楼层坐标 (autoload) │ ├── map_npc.gd 楼层NPC (支持walk_to + can_wander) │ └── npc_interaction_zone.gd 交互区触发器 ├── dialogue/ │ ├── dialogue_manager.gd 气泡池 + 不重叠 + 自动回收 (autoload) │ ├── dialogue_bubble.gd 气泡UI (think+utterance共用, 3行滚动, 自动fade) │ ├── dialogue_entry.gd 数据格式 (think + utterances[]) │ ├── memory_store.gd per-NPC记忆 (class_name, 按伙伴分组, 磁盘持久化) │ └── conversation_manager.gd (备用) └── ui/virtual_joystick.gd 触控摇杆 scens/edmas/ ├── DialogueTest.tscn 主场景 (完整地图+碰撞+NPC) └── Floor_*.tscn 楼层场景 assets/maps/ ├── normalized/ 地图图 (1672×941) ├── collision/ 墙体碰撞多边形 └── masks/ 可走区域mask
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
MedSquad — 急诊科多智能体模拟
Godot 4.7 2D 俯视角医院模拟。NPC 由 LLM (DeepSeek-V4-Flash) 实时驱动对话、分诊、移动。玩家自主操控角色在急诊科探索。
核心架构:Godot → Gitee AI (HTTP)。无 Python 后端,无进程管理。
启动
NPC 自主对话、移动、分诊,不需要手动启动任何服务。
网页版
在线版:https://so-cean.github.io/MedSquad-/
游戏大纲
玩家扮演来急诊就诊的患者,在真实医院流程中被分诊、检查、治疗、转归。所有医护人员由 LLM 驱动,有独立人格、专业知识和记忆。
多对一:护士同时处理多个AI患者NPC,按病情优先级排序。NPC完全自主——对话、移动、状态切换不需要玩家干预。
操作指南
架构
四层分离
NpcManager+ConversationContextnpc_fsm.gd(无状态)MemoryStore(class_name)DialogueManager+DialogueBubbleMapSystem+HospitalMapDataAutoload
DialogueManagerscripts/dialogue/dialogue_manager.gdNpcManagerscripts/edmas/npc_manager.gdMapSystemscripts/edmas/map_system.gdHospitalMapDatascripts/edmas/hospital_map_data.gdLLM 模型
多对一对话
护士一次LLM调用处理多个患者,返回结构化response:
get_context_for_partner(patient_id)只看跟某患者的对话分诊问诊流程
管道模式
LLM调用和气泡显示重叠:
对话系统
详见
scripts/dialogue/README.md。记忆系统
重要:用节点名(唯一)做文件路径,不用display_name。两个同名NPC不会共享记忆。
跨NPC记忆路由:患者发言→存入护士记忆(标注patient_id),护士回应→按target路由到对应患者。
地图系统
不依赖任何其他系统 — 不知道NpcManager、ConversationContext、DialogueSystem、LLM。
NPC导航:
npc.walk_to("TRIAGE")→ 自动创建NavAgent + 寻路 + 沿路径移动 + 到达信号。 NPC不做物理碰撞(穿墙移动),导航路径基于碰撞体绕墙。NPC状态机
get_state_name()— 返回中文状态描述(用于LLM prompt)set_state(GOING_TO_ROOM, "候诊区")— 设置状态 + 自动walk_toface_toward(pos)— 面朝某方向(对话时用)approach_and_face(npc, 60)— 走近NPC + 到达后面朝taarrived_at信号 — 到达命名位置时发射NPC移动速度90px/s,无物理碰撞,沿navmesh路径移动。
事件总线
NpcManager发射的事件信号:
patient_arrivedtriage_startedtriage_donenpc_arrived_atall_triage_donepatient_discharged测试场景
scens/edmas/DialogueTest.tscn— 完整地图 + 碰撞 + NPC自主分诊打开
project.godot按 F5 运行。楼层场景
Floor_ED_Core.tscnFloor_Diagnostics.tscnFloor_Downstream.tscn按 E 上楼、Q 下楼。
项目结构