
Может ли ИИ запустить следующую игру D & D? Этот проект направлен на выяснение
6 июня 2025 г.Я думал о создании многопользовательской веб -платформы RPG со времен моих дней в качестве флэш -разработчика. Существует множество онлайн -вариантов TTRPG (много замечательных!), Но ни один из них не чувствовал себя совершенно правильным для того, как я хотел бы играть.
Вы виделивидеоГде Дебора Энн Волл показывает Джон Бернтал, как играть в D & D? (У него есть 2M просмотров!)
https://www.youtube.com/watch?v=Jpvjzrabmqe&embedable=true
Это было так круто. Что если бы я мог сделать что -то такое, что такое, что такое?
Идея
Повествовательная, многопользовательская платформа RPG онлайн, свет на правилах, но с высоким уровнем общего рассказывания историй, с результатами, определяемыми рулоном D20.
Я всегда любилD & D модулиПолем Искусство. Захватывающее введение. Подробные встречи и эпические планы истории для игроков могут раскрываться, поскольку их персонажи пробираются в климатический финал.
Что если бы я мог создать способ для людей сделать свои собственные приключенческие модули, для любого жанра RPG, то позвольте игрокам управлять своими персонажами через эти приключения?
Кто будет управлять играми? Мастера игры трудно найти. Что если бы я мог обучить ИИ быть мастером игры? Чтобы фактически запустить хорошо структурированный план приключений (разработанный человеком!), Это было бы весело для игроков, а не просто кучаAI Slop?
Начиная
Мне было весело строить много вещей с ИИ (см.Мой проект стартер) Я буду использовать свой предпочтительный стек, чтобы сделатьD20Adventures.com, веб -приложение next.js с Tailwind для пользовательского интерфейса (нужно даже сказать?)AI SDKиспользуя Близнецы иВыпуклая база данныхразвернуто в Vercel.
И я решил построить его в открытом месте, опубликовать кодна GitHubПолем
Прототип
Для прототипа я буквально начинаю с сценария, выложенного на подкасте, рейнджер, идущий по лесу ночью, слышит трещину на расстоянии, что оказывается совкой.
Моя цель-построить короткое приключение с одним выстрелом и посмотреть, смогу ли я тренировать AI DM, чтобы фактически запустить небольшую серию поворотов и встречи с этим приключением. Я немного разбил сценарий с предысторией:
Полночь вызываетЗагадочный вызов от старого друга друида вводит затворнического рейнджера в дикой природы леса Валькарра.
После большого количества проб и ошибок я наконец смог провести полную игру и опубликовать ее на YouTube:
https://youtu.be/9wznvmhvmlg?si=qanej8wcf4bzzjk9&embedable=true
Как это работает
Целевая страница
Целевая страница - это большой образ героя (созданный в Midjourney с подсказкой «Сила D20»). Я добавил простое исчезновение в анимации, используя новое правило CSS @стартового стиля:
.fade-in {
@apply opacity-100 transition-opacity duration-1000 ease-in-out;
@starting-style {
opacity: 0;
}
}
Аутентификация
Чтобы воспроизвести быстрый старт, мне нужна учетная запись пользователя. Это не значит, чтобы не получать много денег из -за анонимных людей или ботов, использующих мои API.КлеркСделает очень просто добавление управления пользователями, и я использую их на всех своих проектах.
Кроме того, у меня есть отслеживание использования токенов, где я буду ограничивать использование с помощью системы токенов, где вы начинаете с достаточного количества токенов, чтобы сделать одну игру в демонстрации, а затем можно купить больше по ходу дела.
Первый ход
Когда пользователь приземляется на странице приключений для быстрого начала, первое, что происходит, это то, что мы загружаем данные для демонстрационного приключения, которое является просто простым файлом JSON (так) на S3. Модуль приключений или план в моей системе состоит из серии встреч, которые связаны друг с другом с инструкциями для LLM:
"encounters": [
{
"id": "broken-silence",
"title": "Broken Silence",
"intro": "Thalbern, a solitary ranger of the Valkarr woods, has always trusted the silence of the wilds more than the promises of men. Orphaned by border raiders and raised by the elves of the Valkrarr Forest, he has spent years living on the edge of Kordavos, guiding travelers, hunting for his own survival, and keeping his distance from the tangled politics of the city.\n\nYet on this night, a message delivered by a red squirrel bearing the unmistakable script of Wollandora, a trusted elven friend and druid, has drawn him from his hidden home. The note was simple and urgent: Meet me at the Old Standing Stones at midnight. The balance of the forest could depend on it.\n\nNow, as midnight approaches, Thalbern moves quietly through the dense undergrowth, guided by memory and instinct. It is dark with almost no moonlight coming through the forest canopy.\n\nSuddenly, the hush of the night is broken by a sharp crack. Something large has just stepped on a branch somewhere off in the distance.",
"instructions": "A perception check is appropriate if Thalbern investigates (low difficulty with a plus 3 modifier). If successful, he will determine it is a large creature that is approaching quickly. With a high roll (18+), he will determine it is an Owlbear. If combat ensues and Thalbern is below 25% health, Wollandora will intervene. If Thalbern avoids or defeats the Owlbear, or if Wollandora saves him, he proceeds to the Old Standing Stones.",
"image": "images/settings/realm-of-myr/the-midnight-summons/broken-silence-2.png",
"transitions": [
{
"condition": "If Thalbern successfully uses stealth to evade and proceeds cautiously towards the Standing Stones, go to meeting-at-stones.",
"encounter": "meeting-at-stones"
},
{
"condition": "If Thalbern fails a perception check, advance to owlbear-confrontation.",
"encounter": "owlbear-confrontation"
},
{
"condition": "If Thalbern fails any dice roll (including stealth, perception, or any other check), advance to owlbear-confrontation.",
"encounter": "owlbear-confrontation"
},
{
"condition": "If Thalbern does NOT successfully use stealth to evade, go to owlbear-confrontation.",
"encounter": "owlbear-confrontation"
},
{
"condition": "If Thalbern does nothing or takes no action, go to owlbear-confrontation.",
"encounter": "owlbear-confrontation"
},
{
"condition": "If Thalbern has a healthPercent of less than 50%, go to wollandora-intervention.",
"encounter": "wollandora-intervention"
}
]
},
{
"id": "owlbear-confrontation",
"title": "Owlbear Confrontation",
"intro": "From the direction of the sound, a little bit of eye shine glints in the shadows of the tree line. A hulking fifteen foot tall monster with the body of a giant bear and the head of an owl. As it crashes out from the undergrowth, it lets out a guttural squawk, clearly agitated and territorial.",
"instructions": "The Owlbear will attack. If Thalbern attempts an animal handling check (high difficulty) and succeeds, he can move past the Owlbear. If Thalbern wins initiative and attempts to hide, he can move past the Owlbear if he passes a medium difficulty stealth check. If Thalbern's health drops to a critical level, Wollandora appears and drives off the Owlbear, transitioning to 'wollandora-intervention'. If Thalbern defeats the Owlbear, describe his victory and transition to 'meeting-at-stones'.",
"image": "images/settings/realm-of-myr/the-midnight-summons/owlbear-confrontation.png",
"npc": [
{
"id": "owlbear",
"behavior": "Aggressively attacks any perceived threat. Will fight until heavily wounded or driven off.",
"initialInitiative": 1
}
],
"transitions": [
{
"condition": "Thalbern defeats the Owlbear, manages to evade it, successfully uses Animal Handling to pacify and move past it, or successfully rolls any other way to move past it.",
"encounter": "meeting-at-stones"
},
{
"condition": "Thalbern is reduced to critical health by the Owlbear.",
"encounter": "timely-rescue"
}
]
},
...
]
Первый ответ
Поскольку мы находимся в демонстрационном режиме, в бэкэнде еще не создано реальных приключений. Это происходит, когда игрок делает первый ответ. С каждым ответом мы запускаем его, хотяformatNarrativeAction
Функция, которая использует ИИ, чтобы оценить ответ, чтобы убедиться, что он грамматически правильный, от третьего лица, и добавляет диалог или другую прозу, чтобы он хорошо работал в стиле литературного повествования.
После того, как форматирование применяется, ответ отправляется на действие сервера. Поскольку это демонстрация, мы создаем приключение в базе данных, когда этот первый ответ получен. После того, как это будет сделано, он будет следовать нормальному потоку для обработки ответа игрока.
Обработка ответов игрока
АprocessTurnReply
Функция загружает текущий поворот из выпуклости, приключенческие данные от S3 и идентифицирует конкретную встречу и символ, выполняющий действие.
В этом контексте он использует ИИ, чтобы определить, является ли действие правдоподобным (мой сын, когда воспроизведение тестирование заставило рейнджера запустить ядерный узел в сова) и, если это так, то необходимо ли механически в кости рулон (например, «бросок атаки» или «проверка скрытности»), включая тип броска и его сложности.
Мы можем сделать это с помощью функционального вызова, где мы можем указать в ИИ, который мы хотим, чтобы структурированные данные были возвращены, в данном случаеrollRequirementSchema
:
import { z } from "zod";
export const rollRequirementSchema = z.union([
z.object({
rollType: z.string().describe("The type of roll required, e.g. 'Stealth Check'"),
difficulty: z.number().describe("The difficulty class (DC) for the roll"),
modifier: z.number().optional().describe("Bonus or penalty to the roll, e.g. +2 or -1"),
}),
z.null()
]);
export type RollRequirement = z.infer<typeof rollRequirementSchema>;
Тогда у нас есть функция, которая посылает подробную подсказку и схему наgenerateObject
:
export async function getRollRequirementForAction(action: string) {
const prompt = `
Given the following player or NPC action, determine if a dice roll is required for the character to attempt the action. If a roll is required, return a JSON object with "rollType" (choose the most appropriate from the list below) and "difficulty" (a number between 5 and 25). If no roll is required, return the JSON value null (not a string).
Possible roll types:
- Perception Check
- Investigation Check
- Insight Check
- Stealth Check
...
Examples:
Action: "Try to sneak past the guards."
Result: { "rollType": "Stealth Check", "difficulty": 15 }
Action: "Attack the goblin."
Result: { "rollType": "Attack Roll", "difficulty": 12 }
Action: "Try to determine what the sound is."
Result: { "rollType": "Perception Check", "difficulty": 10 }
Action: "Say hello."
Result: null
Now, given the following action, determine the roll requirement.
Action: "${action}"
`;
try {
const result = await generateObject({
schema: rollRequirementSchema,
prompt,
});
if (
result.object &&
typeof result.object === "object" &&
"rollType" in result.object &&
(result.object.rollType === "null" || result.object.rollType === "none" || result.object.rollType === "")
) {
return null;
}
return result.object ?? null;
} catch (error) {
throw error;
}
}
После добавления ответа игрока на историю поворота, если требуется бросок костей, мы обновляем состояние персонажа в данных выпуклых поворотов, чтобы отразить, что они ответили, но их очередь не завершена. Это обновление приводит к обновлению в реальном времени для пользовательского интерфейса, показывающего детали рулона, и дает игроку кнопку, чтобы бросить D20.
Как только пользователь катится, у нас естьresolvePlayerRollResult
Действие сервера, которое обновляет повествование с визуальным отображением результата и пишет прозу, описывающую результат. У нас также есть еще один вызов функции ИИ, чтобы обновить здоровье и статус для всех персонажей в ходе поворота.
Действия NPC
Когда для ответа это NPC -поворот, мы следуем аналогичному шаблону в качестве игрока, за исключением того, что в данном случае ИИ напишет ответ. Каждая встреча включает в себя информацию о мотивации NPCS, и в сочетании с контекстом приключенческого повествования до сих пор, надеюсь, ИИ сможет генерировать хороший ответ, а затем генерировать свой собственный бросок в кости и обновление результата.
Обучение ИИ для управления РПГ
Если вы когда -либо пытались сделать игровой сессию с ИИ в чате, вы знаете, как быстро он может снять с рельсов.
Надеемся, что, предоставив соответствующий контекст, конкретные инструкции по быстрому быстрому обращению и структурированные вызовы функций данных, мы можем получить приятный опыт.
Определенно много проб и ошибок, ведения журнала консолей и быстрого настройки. Например, когда спрашивает, почему ИИ не следовал инструкциям по встрече в одном из моих тестовых прогонов, это то, что чат курсора должен был мне сказать:
Таким образом, LLM не следовал своим явным инструкциям к переходу, когда символ не проходит проверку восприятия, несмотря на то, что ему предоставили четкие доказательства такого сбоя и правила перехода для этого конкретного сценария. Похоже, что это неправильное применение предоставленной логики LLM.
Я предполагаю, что случайность ИИ не делает именно то, что ожидается, может быть частью веселья. Полагаю, мы узнаем!
Вот примеродна из пьесПолем
Вы можете увидеть полный исходный код для этого проекта наgithub.com/johnpolacek/d20adventures.com
Оригинал