Создаю игру
19 постов
19 постов
Привет. Меня не было пару дней — читал эту книгу.
Она называется Branching Story, Unlocked Dialogue (Тойя Кристен Финли). Это учебник по проектированию и написанию визуальных новелл. Честно? Лучшее, что я находил на тему.
Она не про код. Она про то, как история становится игрой. Про то, как спроектировать ветвления, сделать выборы осмысленными, не обмануть ожидания игрока. И про персонажей — настоящих, а не картонных.
Пару примеров того, что вынес:
Трёхгранные персонажи (физиология — социология — психология). Раньше я писал «журналист расследует дело». Теперь у героя есть страх воды, разбитая семья и погибшая дочь, которую он не может простить себе. Это не фон — это двигатель.
Foldback structure (складная структура). Ветвления не должны расползаться в бесконечность. Игрок исследует мир, но все нити в итоге сходятся в одну точку — в момент выбора.
Концовки с разным эмоциональным зарядом (по Макки). Не просто «хорошо/плохо», а идеализм, пессимизм, ирония. Игрок должен уйти с чувством, а не со шкалой «правильно/неправильно».
В общем, книга — мастхэв. Если делаете свою ВН, начните с неё. Хотя я тот ещё советчик. Сам ничего толком не сделал)))
Теперь к сюжету
Я долго думал, как говорить о нём, не раскрывая главного. Поэтому расскажу только начало. Без без спойлеров, без финальных твистов. Только атмосфера и вопросы, которые возникают у героя в первый же день.
Утро. Рабочий стол в редакции. Ноутбук, бумаги, старая папка. На стене — дипломы и пожелтевшие газетные вырезки.
Редактор даёт задание. Юбилей. Нужно написать материал к годовщине. История старая — четыре десятилетия. Исчезновение детей в санатории. Одна смена — целиком.
— “Ты обычный посетитель”, — говорит редактор. — “Никаких удостоверений. Разговори старожилов, сотрудников. Что бы всё красиво”.
Журналист приезжает в санаторий весной. Его задача не офишировать свою деятельность, как будто он обычный зевака, случайно услышавший загадочную историю. Неофициально — разобраться в деле, которое не даёт покоя уже четыре десятилетия, и написать материал к очередной годовщине трагедии. Исчезновение детей в одну из смен. 1985 год.
Санаторий встречает его тишиной и малочисленностью посетителей. Сезон ещё не начался и он один из первых посетителей. Весеннее майское утро. Фонтан во дворе ещё чинят. Персонал насторожен, но вежлив.
Номер ещё не готов. Приходится ждать. Герой отправляется изучать территорию.
В первый же день он находит несколько странных фигурок. Маленькие, сделанные из сложенной бумаги, будто кто-то специально подкидывает их ему. Двенадцать животных. Одна из них — в траве у фонтана. Другая в библиотеке.
Он может поисследовать территорию санатория и найти несколько таинственных, по своей атмосфере, мест. Например, пожарную вышку в лесу.
Так же он знакомится с персоналом. Медсестра, которая слишком много знает. Следователь, чей взгляд трудно выдержать. Старый сторож, который не говорит, но смотрит так, будто узнал. Музей с языческой статуэткой и бивнем мамонта.
И девушка. В белом платье. Сидит на краю фонтана, брызгает воду ногами. Смеётся.
— «Вы здесь, потому что ищете что-то», — говорит она. — «Я сразу поняла».
Ей нужно бежать. Обещает пересечься.
Вечером в номере ломается туалет. Приходится идти в общий в другой корпус.
Собирается гроза. Удары молний освещают старые корпуса. Он видит между здания подозритльную фигуру.
На следующее утро на пляже находят тело той самой девушки. Она просто лежит, слово уснула. Но она мертва.
Расследование начинается.
Но герой ещё не знает, что ищет не убийцу.
Он ищет способ вылечить свою старую душевную рану. Попутно узнав правду, которую похоронили 40 лет назад.
И что ответы — намного глубже. Возможно, даже в другом мире, куда ему предстоит спуститься.
Сегодня расширяю географию санатория.
Хочу сделать очень важное для игры место — местный музей.
Начал с нового персонажа. Пока это просто музейный работник.
Затем я добавил экстерьер музея.
И интерьер.
Да, проблему я вижу. Основная — полное несоответствие фасада и внутреннего убранства. Проблема в том, что все предыдущие здания я делал не из головы, а использовал очень конкретные фотографии мест, где сам был, в качестве референса. Даже в случае проявления фантазии получалось сохранять целостность. Здание музея же взято с нуля, и здесь я, скорее всего, всё переделаю в будущем. Но пока важно, чтобы всё работало.
Здесь будет много активностей и квестов. Например, после выполнения задания от музейной сотрудницы герой получит банку с 15-копеечными монетками для игрового автомата — это открывает бесконечную игру в «самолётик».
Ещё здесь будут важные сюжетные предметы, среди которых бивень мамонта и древняя деревянная фигурка.
Вот такой фронт работ. А теперь собираю всё вместе и смотрим, что получилось за день.
Всем добра.
Всем привет. Был в небольшом незапланированном отпуске — работать над проектом не мог. Но теперь продолжаем.
Начну с концепции. В целом атмосфера игры у меня начинает вырисовываться. Да, пока картинка светлая и красочная, в стиле студии Ghibli, однако сюжет предполагает её постепенное изменение в сторону более загадочного и атмосферного сеттинга. Это не хоррор, но загадка и саспенс будут присутствовать. За референс атмосферы я взял Twin Peaks. Что-то такое, ну вы понимаете.
Название города, где находится реальный санаторий, я, конечно же, поменял. Но кто знает — тот знает. Картинку с Двугорском я создал в качестве концепта и пока не знаю, где она будет использована: либо на главной заставке, либо в открывающем интро. Но это в будущем. А пока о насущном.
Альбом
В игре будет интересный инструмент — альбом. Это что-то вроде заметок на полях, блокнота и части головоломок вместе. По сюжету альбом есть у героя с самого начала, и он листает его по ходу игры.
Механика простая: побывав в определённом месте или сделав какую-то активность, герою открывается нужная страница. Например, открыв локацию и взяв фотографию, герой помещает её в альбом. Фотографии чаще всего будут старые, с описаниями, дающими пищу для размышлений или подсказками, а также раскрывающими историю места и события, предшествующие игре.
Начал я с того, что сделал иконку альбома на основном экране. Это оказалось непросто. Сначала она болталась сверху, потом начала наезжать на иконку рюкзака.
И наконец после ручного изменения параметров она встала где нужно.
Затем я начал реализовывать задумку, чтобы альбом не был виден весь изначально, а открывался по мере прохождения. Так появилась первая заглушка.
На первом экране в альбоме ничего нет. Но если выйти и подойти хотя бы к первой статуе, в нём уже появляются кое-какие записи.
Я сделал их в виде фотографий с текстом.
Какие-то фотографии будут разбросаны по территории санатория в виде предметов, другие откроются просто так. Например, где-то можно будет найти полароидный снимок.
Итоговый ролик по механике:
Всем добра. Спасибо за просмотр.
Сегодня продолжаю работу над автоматом. Вчера остановился на том, что всё работало технически, но выглядело так себе. Начинаем облагораживать.
Первое, с чего я начал, — визуализация автомата в библиотеке.
Затем я сделал основной экран. Да, он не полностью подходил, центральный экран пришлось раздвигать, но это была не самая большая проблема.
Окно игры было квадратным…
Я сделал скрин и обвёл квадрат нужного размера. Вариантов было несколько.
Но потом я нашёл более элегантный способ: сделал маску, которую наложил поверх изображения.
Потом я заменил фон на вот такую интересную текстуру в виде экрана монитора и затемнил её по краям, чтобы придать выпуклость.
Ну и итоговый результат.
Да, всё ещё далеко от идеала, и провозился я намного дольше, чем хотел изначально. Тем не менее, становится всё лучше и лучше.
Сегодня воскресенье, и я надеялся отдохнуть от новеллы. Позаниматься чем-то связанным с игростроем, но простым, чтобы это заняло минимум времени. Эх, как же я был наивен. Но обо всём по порядку.
Моя задача на сегодня изначально была сделать какую-нибудь простенькую игру за день, чтобы подтянуть свои навыки и в то же время расслабиться.
Под эту задачу отлично подходили игровые автоматы СССР. Когда я начал изучать игры на них, то подумал: это была бы отличная вставка в игру. Старый советский автомат, на котором можно реально поиграть. Круто.
Мой выбор после изучения истории пал на «ПЕРЕХВАТЧИК».
Такой вполне мог бы стоять где-нибудь заброшенным в библиотеке. Я даже придумал сайд-квест: герой попадает в местный музей, выполняет задание библиотекаря, за что та даёт ему банку с 15-копеечными монетами. После этого автомат можно запустить и играть. Но сначала нам нужно саму игру сделать.
«Перехватчик» — это сайд-скроллер, где вы управляете самолётиком, взрываете вражеские истребители и набираете очки. Стоимость одной игры — 15 копеек, за которые можно летать определённое время.
Мой план был таким:
Сделать рамку автомата (arcade_frame.png)
Сделать экран монитора (arcade_screen.png)
Сделать временную кнопку закрытия (или просто клик по экрану)
Написать простой цикл игры: игрок (белый квадрат), враги (летят сверху)
Добавить стрельбу по пробелу
Добавить столкновения (игрок — враг)
Добавить счёт
Чтобы ничего не напутать, я создал новый проект в Ren'Py и отдельный файл в Visual Studio, где прописал первую заглушку игры. Файл поместил в папку game нового проекта.
# ЗАГЛУШКА: экран (чёрный прямоугольник)
add Solid("#000000") xysize (1024, 768) xalign 0.5 yalign 0.5 yoffset -20
# Игровая область (пока текст)
frame:
background None
xalign 0.5
yalign 0.5
yoffset -20
xsize 1024
ysize 768
vbox:
xalign 0.5
yalign 0.5
spacing 30
text "ПЕРЕХВАТЧИК" size 60 color "#ffffff" outlines [(2, "#333", 0, 0)]
text "Тестовый экран" size 40 color "#88ff88"
text "Кликните мышкой, чтобы выйти" size 24 color "#ffffff"
# Кнопка выхода (просто текст)
textbutton "X" action Return() xalign 0.95 yalign 0.05
label test_interceptor:
scene black
"Подходите к старому игровому автомату..."
call screen interceptor_game
"Вы отошли от автомата."
return
Файл script.rpy в новом проекте я полностью почистил, оставив только две строчки.
label start:
jump test_interceptor
При запуске появился экран.
При нажатии кнопки «Начать» запустился экран игры. Пока всё работает.
Отлично! Экран появился — это прогресс. Кнопка «X» работает как выход. Но это пока лишь заглушка. Самой игры ещё нет.
Продолжаем и теперь пишем код для самолётика.
Это база. Дальше нужно добавить:
Движение врагов
Пули
Проверку столкновений
Увеличение счёта
Game Over
Сам код со стрельбой и врагами получился достаточно объёмным, поэтому публиковать его здесь целиком не вижу смысла. Отмечу только, что в нём присутствуют такие элементы, как…
1. Движение игрока (влево-вправо)
if ev.type == pygame.KEYDOWN:
if ev.key == pygame.K_LEFT:
self.player_x -= 30
if self.player_x < 0:
self.player_x = 0
elif ev.key == pygame.K_RIGHT:
self.player_x += 30
if self.player_x > self.game_width - self.player_width:
self.player_x = self.game_width - self.player_width
2. Стрельба по пробелу
elif ev.key == pygame.K_SPACE:
self.shoot()
3. Появление врагов сверху
self.spawn_timer += 1
if self.spawn_timer > 30:
self.spawn_timer = 0
enemy_x = random.randint(0, self.game_width - self.enemy_width)
self.enemies.append([enemy_x, -self.enemy_height])
4. Проверка столкновений (пуля → враг)
if (bullet[0] < enemy[0] + self.enemy_width and
bullet[0] + self.bullet_width > enemy[0] and
bullet[1] < enemy[1] + self.enemy_height and
bullet[1] + self.bullet_height > enemy[1]):
self.bullets.remove(bullet)
self.enemies.remove(enemy)
self.score += 10
5. Game Over при столкновении игрока с врагом
if (enemy[0] < self.player_x + self.player_width and
enemy[0] + self.enemy_width > self.player_x and
enemy[1] < self.player_y + self.player_height and
enemy[1] + self.enemy_height > self.player_y):
self.playing = False
Вышло достаточно залипательно, но пока не работал счётчик очков.
Как выяснилось, счётчик не обновлялся, потому что Ren'Py не перерисовывал экран при изменении переменной score в классе. Нужно было явно вызывать renpy.redraw() и передавать актуальное значение счётчика в экран.
Дальше пошли мучительные исправления. Что бы я ни делал — счётчик не работал. Но когда я добавил картинки, всё каким-то чудесным образом само починилось.
Графику я начал с самолётика.
Вырезал из оригинальной игры самолётик. Правда, там он вытянутый, а у меня квадратный.
Обвёл его примерно по контуру.
И отразил.
Ну и доработал немного свой шедевр, вырезав кабину для пилота. Размер — 48×48 px.
Вражеский самолётик я перевернул и покрасил в красный. Он уже 40×40 px.
Экран автомата я пока просто сделал рандомной картинкой из интернета — проверить, работает или нет.
Ну и кнопочка выхода. Два варианта обычная и при наведении.
А вот и результат сегодняшнего дня.
Выглядит странно, но я доволен, потому что всё работает!
Спасибо за внимание. Всё, сил нет, пошёл отсыпаться 😴
Жду комментариев какой я рукожоп)
Изменений сегодня не много, так как был занят. Но они есть.
Доработал немного второй этаж с библиотекой. Сейчас появился экран самой библиотеки
И можно сделать выбор. Идти к шкафу или повернуться обратно. В случае если герой разворачивается, он видит новую локацию.
Кто-то забыл убрать раскладную лестницу на второй этаж. Здесь так же два выбора, спуститься вниз или отправиться на крышу.
С крыши видна парковка. Но последний кадр не загрузился. На нем герой находит ещё одну фигурку животного. Этим займусь завтра.
Вот такая небольшая работа. Приятного просмотра.
Сегодня позанимался разными вещами.
Например, создал набор фигурок для дополнительного челленджа.
Челлендж сбор фигурок: двенадцать фигурок спрятаны по территории. Найдёте их все — откроете секретную концовку.
Создал иконки в стиле какой-нибудь NiNo Kuni.
Сделал медсестру Нину.
Добавил новую локацию. Домик с водными процедурами.
Сделал интерьер домика с водными процедурами
И саму процедуру
Немного покодил. В частности, прописал вход в домик с водными процедурами и общение с медсестрой.
Пример кода:
Затем начал, как я думал, с простого, но провозился достаточно долго. Сначала подготовил иконку инвентаря, но она в размере 64×64 была слишком мелкой. Пришлось увеличить до 128×128. Так же понадобилась иконка при наведении. Вроде где-то читал, что можно это проделывать и через одну иконку (кодом), но пока не разбирался и сделал по старинке, как умел.
Вот так это выглядит в масштабе экрана. Возможно, крупновато, но 64×64 точно мелко.
По коду никаких нововведений не было. Обычное добавление новой локации, разговор с Ниной (новым персонажем) и статичная картинка с процедурами.
Короткий ролик с новым контентом выкладываю по традиции.
Сегодня сделаю инвентарь.
Чтобы механика не была абстрактной, сразу завяжу её с сюжетом. Попробуем положить где-то предмет, поднять его, положить в инвентарь, а затем используем его где-нибудь, и чтобы это ещё и что-то меняло. По-моему, звучит интересно.
Я решил объединить сегодняшнюю тему с небольшим багом у Лены. Да и вообще она ещё слабо проработана. Предметом я выбрал цветы, а объектом, на котором можно их применить, — Лену. Это сделает её немного добрее и даже поменяет настроение. Но обо всём по порядку.
Начал я с самой Лены. У меня было только одно её изображение, поэтому я подготовил ещё два. Она немного поменялась, но это не страшно.
Теперь, когда у нас есть три Лены — нормальная, весёлая и злая, — мы можем вырезать их и отправить злиться в домик с грязным номером.
Реализуем инвентарь
Если просто, то он делается вот таким образом:
К нему нужна иконка. Пока взял стоковую 64×64 px. Это пока не так важно. Важнее, чтобы всё работало.
Добавляем предмет
Теперь, когда у нас есть инвентарь, нужен предмет. Это букет, и он будет лежать возле памятника девушки с веслом.
Для начала я вырезал из фотографии букет и сделал PNG-файл 64×64, чтобы в инвентаре все предметы смотрелись одного размера. Поэтому выбрал квадрат 64×64 px.
Дальше всё просто. Делаем одно изображение статуи с букетом…
…и одно — без него.
Теперь прописываем взаимодействие с букетом. По сути, его можно взять или не брать.
Пример кода:
Выглядит инвентарь пока так себе. Важнее, что он вообще хоть как-то выглядит. Дальше поправим.
Взаимодействие с Леной
И теперь пишем код взаимодействия с Леной. Логика следующая:
Мы заходим в домик — она злая.
Можем подарить букет, можем не дарить.
Если дарим — она меняет эмоцию и реплику (прямо в моменте).
Когда заходим снова — она уже нормальная.
Пример кода:
Что пошло не так
Из сложного — помучился с мелкой логикой:
Сначала Лена не хотела радоваться сразу, только после выхода и возвращения.
Потом начала накладываться: новая, весёлая Лена появлялась, а старая не исчезала.
Под конец она не хотела становиться нормальной после возвращения — всё время была какой-то весёлой.
В итоге всё поправил и сделал короткий ролик, посвящённый только этой механике.
Спасибо за просмотр.
