地图与场景切换
一张玩家能点的地图:选森林,场景就移到森林。AI 拿到森林的氛围,音乐淡到森林的曲子,AI 的下一次回复描写抵达的过程。用一个变量、条件设定、音乐规则和玩家界面上的按钮搭出来,不用写代码。
你要做的东西
- 一个地图页,四个地点:村庄、森林、山洞、集市
- 标出当前所在的地点,它的按钮不能再点
- 点一个地点,场景就移过去:位置变了,那个地点的设定发给 AI,玩家的一句「(我前往森林)」发进聊天,AI 就会描写抵达
- 每个地点有自己的音乐,一首淡到下一首
怎么运作
玩家在地图上点了「森林」
→ 按钮把 Location 设成 森林,回到聊天,
再替玩家说一句「(我前往森林)」
→ 设定「森林」(条件:Location 是 森林)现在会发给 AI;「村庄」不再发
→ 森林的音乐规则对上了:村庄的曲子淡出,森林的曲子淡入
→ AI 带着森林的氛围回复「(我前往森林)」变的只有这个变量。设定和音乐盯着它,自己就跟上了。
一步一步来
第 1 步:建变量
点卡底下 还可以加 里的 + 变量。
| 字段 | 值 |
|---|---|
| 名称 | Location |
| 类型 | 文字 |
| 初始值 | 村庄 |
| 行为规则 | 玩家现在在哪:村庄、森林、山洞或集市。玩家明确去了其中一个地方时改它。 |
如果 AI 也可以在故事里带玩家走(「你顺着小溪走进了森林」),AI 权限 就保持 AI 可读可写。只想让地图来移动玩家的话,设成 AI 只读。
第 2 步:每个地点写一条设定
每个地点加一条设定。然后把 Location 拖到每条设定上,点那根线,设好条件:Location 等于 村庄(其余依此类推)。这些设定会挪到条件设定那一块,只有当前地点那条会发给 AI。
村庄
[地点:村庄]
玩家在村子里。描写场景时带上这些:
- 一个安静的小村子,石子路在木房子之间绕来绕去
- 烟囱冒着烟,空气里是新烤面包和炖菜的味道
- 村民在井边聊天,铁匠铺里传来锤子声
- 麦田一直铺到远处,随风起伏
- 气氛温暖,过日子的样子森林
[地点:森林]
玩家在森林里。描写场景时带上这些:
- 老树把大半个天空都遮住了,光一块一块落在青苔上
- 空气潮湿,有泥土、松脂和野花的味道
- 四面八方都是鸟叫,时不时有树枝咔嚓一声
- 灌木丛里可能藏着兔子、鹿,或者更糟的东西
- 越往里走,树越密,光越暗
- 气氛古老、荒野,说不准会遇到什么山洞
[地点:山洞]
玩家在山洞里。描写场景时带上这些:
- 岩壁上的发光菌类透出淡淡的蓝绿色光
- 钟乳石往下滴水,每一滴都有回声
- 空气又冷又湿,有一股矿石的味道
- 地面又滑又不平,再往里的隧道漆黑一片
- 有时下面会传来低低的吼声,或者岩石移动的碎裂声
- 气氛昏暗、压抑集市
[地点:集市]
玩家在集市上。描写场景时带上这些:
- 一排排鲜艳的摊位和帐篷,堆满了各种货物
- 商贩吆喝着自家的东西,讨价还价声此起彼伏
- 香料、烤肉、皮革和鲜花的味道混在一起
- 魔法店的橱窗里闪着奇怪的光,角落里有个炼金术士在调东西
- 各色旅人在人群里挤来挤去
- 气氛吵闹、忙碌第 3 步(可选):每个地点配音乐
在 音频 页加四条 BGM 音轨(卡里还没有音频的话,点 还可以加 里的 + 音频):村庄、森林、山洞、集市,每条都打开 循环播放,淡入 (秒) 和 淡出 (秒) 都填 2。把村庄放进 默认播放列表,打开 自动播放。
然后 BGM 播放配置 → 条件 BGM → 添加条件规则,森林、山洞、集市各加一条:
| 字段 | 值 |
|---|---|
| 条件 | 变量条件:Location 等于 森林 |
| 播放 | 森林 |
| 淡入 (秒) / 淡出 (秒) | 3 / 3 |
| 停止上一首 BGM | 打开 |
| 结束时 | 返回默认播放列表 |
玩家回到村庄时,没有规则对得上,结束时 会让播放列表里的村庄音乐回来。
淡入淡出设 3 秒,新旧两首会重叠一小会儿,一首变小声,一首变大声,所以换地点时音乐不会突然断掉。更多见音频设计指南。
第 4 步:做地图页
点顶栏中间的 玩家界面。用 新建一页 加一页(空白页),起名叫「地图」,放一个标题和一句短话,比如「去哪儿?」。
每个地点加一个 按钮(加一个部件 → 按钮)。森林按钮的 按下时,依次做 里:
- 改变量:Location,设为,
森林 - 跳到页面:对话页
- 替玩家说一句:
(我前往森林)
最后一步让 AI 马上描写抵达:就像玩家自己打了这句话。
为了不让玩家去自己已经在的地方,给每个按钮设 什么时候显示 → 变量满足条件时:Location 不等于 森林。在最上面加一个 文字 部件,写 你在:{Location}(用 插入变量的值…)。
再在这一页加一个只负责返回的 按钮(跳到页面 → 对话页),玩家不想走的时候也能关掉地图。对话页上加一个「地图」按钮,跳到页面 → 地图。
把 编辑 关掉,就能点着试,不花额度。
地图模板
模板 → 地图前往(点地点就走过去,还没解锁的点不了)会直接做好一个地图页,带五个示例地点。它会加 所在地 和 能去的地方 两个变量,后者是一个列表,故事让玩家有办法去某个地方时,AI 就把它加进去,所以地点一开始是锁着的,跟着剧情一个个打开。想让地点随剧情解锁、而不是一开始全开着,就用它。
把地点做成情境
当一个地点长成了游戏里独立的一块(有自己的 NPC、规则和变量,也许还有自己的 AI),就把它做成一个情境,而不只是一条设定。把情境的 什么时候用 设成 变量满足条件时,Location = 山洞,里面的一切就只在玩家在那里时生效。也可以把 Location 变量拖到情境上来设这个条件。
第 5 步:试玩
点顶栏的 试玩。
- 村庄的音乐响起。打开 地图:「你在:村庄」,没有村庄按钮
- 点 森林。回到聊天,「(我前往森林)」发了出去,AI 描写森林
- 加了音乐的话,村庄的曲子淡成森林的曲子
- 去山洞,再回村庄:播放列表里的村庄音乐回来了
- 两次出行之间照常聊天;地图随时点一下就能打开
试玩右边的 这回合 能看到 AI 拿到的是哪个地点的设定。
如果出了问题:
| 现象 | 可能的原因 | 怎么改 |
|---|---|---|
| 点地点没反应 | 按钮没有步骤 | 检查 按下时,依次做 |
| 位置变了但 AI 没回复 | 没有 替玩家说一句 这一步 | 加在最后一步 |
| AI 描写的地方不对 | 某条设定的条件和按钮设的值对不上 | 按钮里和条件里的 森林 要一字不差 |
| 两个地方的氛围混在一起 | 有一条设定在每回合都发的那一块 | 检查每条设定的 什么时候发给 AI |
| 两首曲子同时在放 | 停止上一首 BGM 没打开 | 每条地点规则都打开它 |
| 音乐是跳过去的,没有淡入淡出 | 淡入淡出是 0 | 把规则上的 淡入 (秒) 和 淡出 (秒) 设成 2 或 3 |
写代码的做法:带路线的地图面板
如果你自己写界面,下面是一个放在最后一条消息下面的地图面板,它还会限制玩家从当前位置能去哪里。它设的是同一个 Location 变量,发的也是同一句话,所以第 2、3 步的设定和音乐不用改就能用。
面板 → 前端代码 → 打开 index.tsx,把默认的 return <Chat /> 换掉:
export default function MyWorld() {
const api = useYumina();
const current = String(api.variables["Location"] || "村庄");
const msgs = api.messages || [];
const locations = [
{ id: "村庄", icon: "🏘️", color: "#92400e", bg: "#fef3c7", border: "#f59e0b", activeBg: "#f59e0b" },
{ id: "森林", icon: "🌲", color: "#166534", bg: "#dcfce7", border: "#22c55e", activeBg: "#22c55e" },
{ id: "山洞", icon: "🕳️", color: "#3b0764", bg: "#f3e8ff", border: "#a855f7", activeBg: "#a855f7" },
{ id: "集市", icon: "🏪", color: "#9a3412", bg: "#ffedd5", border: "#f97316", activeBg: "#f97316" },
];
// 每个地方能去哪里
const routes = {
"村庄": ["森林", "集市"],
"森林": ["村庄", "山洞"],
"山洞": ["森林"],
"集市": ["村庄"],
};
const reachable = routes[current] || [];
const travel = (loc) => {
api.setVariable("Location", loc.id);
api.sendMessage("(我前往" + loc.id + ")");
};
return (
<Chat renderBubble={(msg) => {
const isLastMsg = msg.messageIndex === msgs.length - 1;
return (
<div>
<div
style={{ color: "#e2e8f0", lineHeight: 1.7 }}
dangerouslySetInnerHTML={{ __html: msg.contentHtml }}
/>
{isLastMsg && !msg.isStreaming && (
<div style={{
marginTop: "16px",
padding: "16px",
background: "rgba(15,23,42,0.6)",
borderRadius: "12px",
border: "1px solid #334155",
}}>
<div style={{ fontSize: "13px", color: "#94a3b8", marginBottom: "12px", fontWeight: "600", letterSpacing: "0.05em" }}>
世界地图
</div>
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px" }}>
{locations.map((loc) => {
const isHere = current === loc.id;
const canGo = reachable.includes(loc.id);
return (
<button
key={loc.id}
onClick={() => { if (!isHere && canGo) travel(loc); }}
style={{
padding: "14px 10px",
background: isHere ? loc.activeBg : loc.bg,
border: `2px solid ${isHere ? loc.activeBg : loc.border}`,
borderRadius: "10px",
color: isHere ? "#ffffff" : loc.color,
fontSize: "14px",
fontWeight: "700",
cursor: isHere ? "default" : canGo ? "pointer" : "not-allowed",
opacity: isHere ? 1 : canGo ? 0.85 : 0.3,
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "6px",
}}
>
<span style={{ fontSize: "28px" }}>{loc.icon}</span>
<span>{loc.id}</span>
{isHere && <span style={{ fontSize: "11px", fontWeight: "500" }}>你在这里</span>}
</button>
);
})}
</div>
</div>
)}
</div>
);
}} />
);
}代码做了什么:
api.variables["Location"]按名字读这个变量routes列出每个地方通向哪里。从这里去不了的地方会变淡,点不了travel()先设好 Location,再用api.sendMessage(...)以玩家的身份发出那句出行的话,这样 AI 回复时提示里已经有新地点的设定了!msg.isStreaming在 AI 还在写的时候把地图藏起来,玩家没法在回复写到一半时出发gridTemplateColumns: "1fr 1fr"把四个地点排成两行两列;想排三列就用"1fr 1fr 1fr"
面板 → 前端代码 里文件旁边的状态应该是绿色的 正常。
不想自己写代码?
点画布右上角的 创作助手,说说你想要什么样的地图。
加一个地点
- 加一条设定「港口」,条件是 Location 等于
港口 - 可以再加一首港口的曲子,配一条 条件 BGM 规则
- 在地图页上加一个港口按钮(或者在
locations数组和routes里各加一行) - 在 Location 的行为规则里加上港口,让 AI 知道有这个地方
已经有的东西都不用改。
速查
| 你想要 | 怎么做 |
|---|---|
| 记录玩家在哪 | 一个文字变量 Location |
| 给 AI 当前地点的氛围 | 每个地点一条设定,条件看 Location |
| 用按钮移动玩家 | 步骤:改变量、跳到页面、替玩家说一句 |
| 让 AI 马上描写抵达 | 替玩家说一句(或者代码里的 api.sendMessage()) |
| 藏起当前所在地点的按钮 | 什么时候显示 → 变量满足条件时,Location 不等于 …… |
| 每个地点配音乐 | 每个地点一条 条件 BGM 规则,打开 停止上一首 BGM |
| 随剧情打开的地点 | 地图前往 模板,配 能去的地方 |
| 自带内容的大地点 | 一个情境,什么时候用 设成 变量满足条件时 |
| 限制地点之间的路线 | 界面代码(见上面写代码的做法) |
自己试试:可导入的演示
下载这个 JSON 导入进去,就能看到能跑的版本:
怎么导入:
- 点左边的 创建,选 空白项目,再选 画布
- 在顶栏点 ⋮ → 导入文件,选下载好的
.json文件。它会替换掉这张新卡里的所有内容 - 点 保存,再点 试玩
演示用行为来开关各地点的设定,地图画在界面代码里。演示里没有音乐,想要声音的话,照第 3 步自己加音轨。
这是食谱 #12
同样的搭法(一个变量,设定和音乐跟着它走)也能用在塔的楼层、房子里的房间、传送门后面的世界。昼夜循环用的是同一套,只是把地点换成了时间,两个还能叠在一起:夜里的森林可以有自己的一条设定,两个条件都写上。
