2026年简单实现一个ChatGPT驱动的游戏

简单实现一个ChatGPT驱动的游戏文丨 Yucheng nbsp Li 0 nbsp 让 LLM 驱动游戏能解决什么问题 游戏界有一种说法 过去 20 年的游戏在核心玩法上的创新是缓慢的 绝大多数的创新发生在技术上 开发者在游戏内提供更大的地图 更精致的画面 庞大的细节 其中的主要目的之一是为玩家提供 沉浸感 当玩家在游戏世界里得到自己所期望的反馈时 会获得庞大的满足感 然而 由于技术的限制

大家好,我是讯享网,很高兴认识大家。




讯享网
文丨Yucheng Li

0

 让LLM驱动游戏能解决什么问题?

游戏界有一种说法:过去20年的游戏在核心玩法上的创新是缓慢的,绝大多数的创新发生在技术上。

开发者在游戏内提供更大的地图,更精致的画面,庞大的细节。其中的主要目的之一是为玩家提供「沉浸感」。当玩家在游戏世界里得到自己所期望的反馈时,会获得庞大的满足感。

然而,由于技术的限制,过去的创新并没有涉足游戏的一个核心方面:世界与NPC的运行逻辑。

当玩家与世界和NPC的互动超出了规则设定的范畴时,玩家将无法获得反馈,从而产生巨大的落差。游戏界称这种体验为Breaking Immersion。

过去的开发者使出了千方百计来避免玩家产生违和感。

以荒野大镖客2为例,由于R星将immersive作为其开发的首要原则,导致其花费了8年时间,为游戏世界添加了无数的逻辑与细节,整个开发花费近5.4亿刀,可见其难度与成本。

大型语言模型(LLM,Large Language Model)的普及可能改变这一现状

大模型可以为游戏世界的运行与NPC的行为提供逻辑,帮助游戏理解玩家的行为,让游戏世界在可信的状态下稳定运行。由此从根本上提升玩家的沉浸感。

1

将LLM用在游戏里需要几步?

我们把LLM在游戏中的应用分为两部分:

·World:与游戏环境的交互

·Agent:与NPC的交互

具体来说:

World中包含:

·游戏的世界观

·地图上具体的地点

Agent则包括:

·Persona:人物性格

·Memory:NPC记忆

·Planning:决定NPC将要采取哪些动作(Action)

2

让LLM理解游戏世界与环境

为了让ChatGPT理解我们游戏的世界观,我们引入一段Prompt:

export const worldHistory =

&nbsp; 你所在的大陆名为“大唐王朝”。这是一个神话与现实交织的世界。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp; 主岛上有五个重要的地点。最大的是“长安城”,是国家的政治、经济和文化中心,城墙之内有各种店铺和庙宇。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp; 接着是“五指山”,孙悟空曾被压在此山下。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp; 此外还有“草庙村”,“高老庄”和“女儿村”,这些地方都是唐僧和他的徒弟们在旅程中遇到的挑战和冒险。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp; 东边的小岛上则是一个隐秘的佛教圣地,称为“灵山”,这是四人取经的终点。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp; 两个岛屿间有一座长长的桥梁,名为“通天河”,是由沙僧的金箍棒变化而成。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;;

export const worldKnowledge = “”;

222: {

&nbsp;&nbsp;&nbsp; description: 位于主岛的西北边缘。西面是汪洋大海,东面则是高原的悬崖。周围有几棵树和一片怪物出没的长草地。往南则是长安城的方向。,

&nbsp;&nbsp;&nbsp; mapId: 222,

&nbsp; },

&nbsp; 254: {

&nbsp;&nbsp;&nbsp; description: 位于主岛的东北边缘。东面是海洋,西面是高原的悬崖。附近有几棵树和常有妖怪出没的长草地。长安城就在南边。,

&nbsp;&nbsp;&nbsp; mapId: 254,

&nbsp; },

&nbsp; 188: {

&nbsp;&nbsp;&nbsp; description: 是高原上的森林区。森林里树木茂密,有几片怪物常出没的长草地。长安城就在南边。,

&nbsp;&nbsp;&nbsp; mapId: 188,

&nbsp; },

&nbsp; 190: {

&nbsp;&nbsp;&nbsp; description: 位于高原的一片森林中。你正站在一个维护得相当好的小木屋前。四周是茂密的树木和怪物常出没的草地。长安城就在南边。,

&nbsp;&nbsp;&nbsp; mapId: 190,

&nbsp; },

&nbsp; 220: {

&nbsp;&nbsp;&nbsp; description: 长安城,主岛上的城镇。,

&nbsp;&nbsp;&nbsp; mapId: 220,

&nbsp; },

…….

上述Prompts为地图的每个块都提供了文字描述,从而得以让ChatGPT理解地图上的每个地点:

[完整地图]

3

让LLM驱动NPC

首先,我们要让LLM知道他现在正在扮演一个NPC:

export const npcSharedPrompt = 你正在扮演“西游记”中的一个角色。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">这是一个2D的神话世界,玩家和你都可以在这片大陆上进行探索。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">你可以与其他的角色交流,如唐僧、孙悟空、猪八戒和沙僧,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">并与妖怪发起战斗、参观村庄或神庙、购买法宝或草药。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">在这个世界里,与妖怪的战斗是旅程的一部分,但目标是取得真经,使世界充满和平。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">妖怪虽然凶恶,但并不是绝对的恶,与他们战斗既是为了保护自己,也是希望能够教化他们。</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">你的角色不知道现实世界的存在,只知道他在这神话的旅程中的使命。;

{

&nbsp;&nbsp;&nbsp; id: 1,

&nbsp;&nbsp;&nbsp; name: “唐僧”,

&nbsp;&nbsp;&nbsp; description: “唐僧,本名唐三藏,是中国古典小说《西游记》中的主要人物之一。他是一个决心强烈、智慧和信念的僧人,出发去西天取经。”,

&nbsp;&nbsp;&nbsp; age: 40,

&nbsp;&nbsp;&nbsp; starSign: “pisces”,

&nbsp;&nbsp;&nbsp; money: 100,

&nbsp;&nbsp;&nbsp; items: [“jingwulian”],

&nbsp;&nbsp;&nbsp; personalHistory: 你是唐僧,一个被派来从印度取经的僧人。你的任务是获取佛教经文,将它们带回中国。,

&nbsp;&nbsp;&nbsp; personalKnowledge: “你知道你的三个徒弟:孙悟空、猪八戒和沙和尚。他们各自都有独特的能力和历史。”,

&nbsp;&nbsp;&nbsp; conversation: new ConversationModel(),

&nbsp;&nbsp;&nbsp; startingPos: new Vec2(32, 38),

&nbsp;&nbsp;&nbsp; upSprites: TypedAssets.spriteSheets.momup,

&nbsp;&nbsp;&nbsp; downSprites: TypedAssets.spriteSheets.momdown,

&nbsp;&nbsp;&nbsp; leftSprites: TypedAssets.spriteSheets.momleft,

&nbsp;&nbsp;&nbsp; rightSprites: TypedAssets.spriteSheets.momright,

&nbsp; }

{

&nbsp;&nbsp;&nbsp; id: 2,

&nbsp;&nbsp;&nbsp; name: “女儿国国王”,

&nbsp;&nbsp;&nbsp; description: “女儿国国王是《西游记》中的一个角色。她是女儿国的统治者,对唐僧产生了浓厚的兴趣。”,

&nbsp;&nbsp;&nbsp; age: 35,

&nbsp;&nbsp;&nbsp; starSign: “virgo”,

&nbsp;&nbsp;&nbsp; money: 500,

&nbsp;&nbsp;&nbsp; items: [“elixir of life”],

&nbsp;&nbsp;&nbsp; personalHistory: 你是女儿国的国王,你的国家只有女性。当你听说了唐僧的到来,你决定要与他结婚。,

&nbsp;&nbsp;&nbsp; personalKnowledge: “你知道唐僧是一个高贵的和尚,他正在进行取经之旅。”,

&nbsp;&nbsp;&nbsp; conversation: new ConversationModel(),

&nbsp;&nbsp;&nbsp; startingPos: new Vec2(23, 47),

&nbsp;&nbsp;&nbsp; upSprites: TypedAssets.spriteSheets.carolup,

&nbsp;&nbsp;&nbsp; downSprites: TypedAssets.spriteSheets.caroldown,

&nbsp;&nbsp;&nbsp; leftSprites: TypedAssets.spriteSheets.carolleft,

&nbsp;&nbsp;&nbsp; rightSprites: TypedAssets.spriteSheets.carolright,

&nbsp; },

&nbsp; {

&nbsp;&nbsp;&nbsp; id: 3,

&nbsp;&nbsp;&nbsp; name: “牛魔王”,

….

每个NPC的核心在于:

1、 其独特的人格 - 我们引入了一系列属性来定制其人格:description,personal history,personal knowledge,年龄,星座等等。

2、一系列可以与玩家交互的属性/道具:钱,道具(items)。

3、记忆:我们在这就用每个NPC的对话记录作为其所有的记忆。当然还可以把NPC之前的所有action也加入记忆。

[人格驱使角色提供定制的对话]

[有时候的对话甚至会自带旁白]

为了让ChatGPT给出定制的对话,我们需要提供的包括:

const fullPrompt = generalContent + personalContent + currentState;

1. generalContent:

const generalContent = npcSharedPrompt + worldHistory + worldKnowledge;

2. personalContent

const personalContent = Your name is ${npc.name}, ${npc.age} years old, you have the personality of a ${npc.starSign}.</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp; You have ${npc.money} fictional dollars. ${npc.personalHistory} ${npc.personalKnowledge}</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp; ${storySoFar}</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;;

3. currentState

const prompt = ${timeMsg} at ${envDescription}, What would ${npc.name} say to 悟空? (Keep the response short and just the words your character says)

实现NPC与玩家的互动 - 动作:

content: 悟空 replies "${replyText}". What would you like to do?</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1: 让悟空跟着你,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: 你向他告别,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3: 继续当前对话,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp; Pick an action from the list above. respond with just the number for the action,

}];

我们为NPC提供一系列可选择的工作,ChatGPT将决定NPC的下一步行动。这里的prompt同样包含了位置,时间,对话历史等信息,但为了简洁暂略去。

[这里ChatGPT让牛魔王带领孙悟空前往下一地点]

实现NPC的记忆&nbsp;- 让NPC记住和玩家的所有互动对话:


&nbsp;1、 每次NPC与玩家对话后,ChatGPT将生成本次对话的重点(也就是摘要):

// summarize conversation

const summary = await this.summarizeConversation(conversation, endConversationText);

const updatedConversation: IConversationModel = {

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; isActive: false,

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; history: […conversation.history, { msg: Conversation summary: ${summary} }],

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; messages: [],

&nbsp;&nbsp;&nbsp; };

[在之前发生剧情之后,牛魔王根据记忆选择用「真经」来发起对话]

与NPC的道具互动

[问八戒要点饼子吃]

避免NPC/玩家搞花活导致产生风险内容

这里我们让ChatGPT来判断玩家/NPC的回复是否特别离谱,如果特别离谱则应拒绝正经回答!

private async validateReply(replyText: string, conversation: IConversationModel): Promise{

&nbsp;&nbsp;&nbsp; const promptMsgs: GptMessage[] = […this.mapToGptMessages(conversation), {

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; role: “user”,

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; content: 悟空 replies "${replyText}". Does his response make sense. On this scale of 1 to 5,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1: Response is non-sensical,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2: Response is immersion breaking or meta and acknowledging this is a game,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. Reponse is bad, unnecessarily vulgar for no reason based on the past conversation</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4: Response is all right, and something someone might say but unlikely,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5: Response is good and mostly in context of the game world,</span></p><p style="text-wrap: wrap;"><span style="font-size: 12px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; how would you rate the response, give a one sentence reason why,

&nbsp;&nbsp;&nbsp; }];

Reference


以上。本人对LLM在游戏中的使用十分乐观,这么简单的demo我乐此不疲的玩了很久。

从技术上来说,这个demo整体的框架还算比较完整,很适合在此基础上删删改改,实验各种agent的方法和prompt等。

此外由于demo是用react实现,这里推荐大家观看2小时的react入门视频,从而无缝上手。&nbsp;

注:作者目前为萨里大学在读博士

完整的代码参见:

https://github.com/liyucheng09/ChatGPT_Agent

知乎主页:

https://www.zhihu.com/people/li-yu-cheng-15


∎&nbsp;互动有奖!

我们将在2023年11月16日抽出2名幸运粉丝,分别送出100Q币。参与方式如下:


①点击文末右下角的“在看”

②评论留言

③发送关键词“打卡”至公众号后台完成验证



小讯
上一篇 2026-03-08 23:54
下一篇 2026-03-08 23:56

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/208666.html