В текущей версии игрок управляет караваном, который путешествует между городами после ядерной войны. Кротокрысы воруют запасы еды, а радиоактивные гекконы убивают браминов. Воры могут выследить караван и похитить часть денег, а в пустыне могут напасть радиоактивные гули, рейдеры и прочие бандиты.
Весь сеттинг, мир и логику можно модифицировать, как вам вздумается — исходный код и графика распространяется как public domain, то есть без ограничений на копирование и использование.
Возможности игры
Ваши следопыты могут найти съедобный кактус или довоенные консервы. В пустыне можно найти трупы других путешественников, с которых можно поднять немного денег. У встречных караванов можно купить еды или браминов, а также нанять людей. А еще к вам могут присоединиться встречные бродяги, а иногда — даже бандиты, если вы поразите их своей харизмой. Шутка. На самом деле харизмы в игре пока нет, она эмулируется рандомом.
Эта игра, по сути, следующая ступень эволюции текстовых игр, к которым добавилось перемещение по карте мира, случайные встречи и возможность добавить любой свой модуль на JavaScript.
Функционал можно легко расширить, харизму и другие настоящие ролевые факторы добавить самим. Даже если вы не хотите программировать — можно просто открыть файлы с набором событий в Notepad и добавить новые события, изменить баланс или даже полностью переписать мир и лор, превратив путешествие по постъядерной пустыне в приключения караванщика Лютика в стране эльфов. Или в странствия космического корабля между разными звездными системами (правда, придется выбросить съедобные кактусы, попадающиеся по дороге).
Механика этой игры довольна проста, а её графические возможности — это диалоги, индикаторы и движение по карте мире. Ее сила — в магии текстовых игр, которые способны с помощью слов описывать самые невероятные приключения.
Основная идея и логика программы
Базовая идея игры очень проста — мы запускаем бесконечный цикл, внутри которого выполняется четыре базовых операции:
- Движение к заданной точке
- Отсчет дней
- Потребление еды
- Проверка на вероятность для события, которое нас ждет в пустоши
Последняя операция — это та самая табакерка, из которой, как чертики, выскакивают бандиты, гули, встречи с мертвыми путешественниками, все остальные приключения, которые можно придумать.
Как это происходит? Очень просто — каждое событие просто меняет числовые параметры каравана или мира, а затем сообщает об этом в лог. И вот тут возникает магия — параметры могут быть одними и теми же, но сообщать можно о совершенно разных причинах. Минус несколько единиц еды? Это могут быть нападения крыс, выпадение радиоактивных осадков или голодных бродяг. Плюс несколько единиц еды? Значит, ваши люди нашли съедобный кактус, раскопали в придорожных руинах довоенные консервы или нашли на дороге замечательные кожаные сапоги с мягкой подошвой.
Первая версия, с которой я начал экспериментировать, выглядела чистой иллюстрацией описанного алгоритма:
Я сделал этот прототип как ремейк игры про орегонский караван из этого туториала.
Одномерный прототип — караван для js13kGames
Игра из туториала, которую я нашел, была одномерной — караван выходил из одной точки и приходил в другую. В пути происходили случайные события, встречи с бандитами и торговцами.
Игрок в этой версии был сильно ограничен. В основном ему приходилось любоваться логом с событиями. Интерактив наступал лишь время от времени, когда появлялся магазин или бандиты. При этом все события имели равную вероятность и даже хранились в одном массиве.
Когда я посмотрел результат, то понял, что игру можно расширить до настоящей песочницы. Надо было лишь добавить свободы, сделать модульным код и разнести события по разным модулям. Пришлось переработать код практически полностью.
- Многоразовое путешествие — игра не прекращается с достижением цели
- Двухмерная карта мира и города
- Другой сеттинг мира и никакой дизентерии
- Бандиты могут вступать в переговоры и наниматься
- Добавлены товары, которые автоматически продаются и покупаются при достижении города
- Модульная система — логика на базе плагинов и наборы событий в отдельных файлах
Движок каравана и архитектура
Игра, как уже было сказано, сделана на чистом JavaScript без использования сторонних библиотек (вы можете сами добавить их, если сочтете нужным). Для отображения карты мира и интерфейса используется обычный HTML и CSS. Чтобы изменять их, используются базовые операции с DOM и классическая операция document.getElementById
this.view = {}; // объект для хранения элементов DOM
this.view.crew = document.getElementById('game-stat-crew'); // находим элемент при запуске игры
// ...
this.view.crew.innerHTML = world.crew; // записываем число людей в караване как обычный html
WorldState — модель мира
Мир в игре — это класс WorldState. Он хранит в себе все важные параметры и не содержит никакой логики. Логику мы привяжем потом, за счет плагинов.
function WorldState(stats) {
this.day = 0; // текущий день, с десятичными долям
this.crew = stats.crew; // количество людей
this.oxen = stats.oxen; // количество быков
this.food = stats.food; // запасы еды
this.firepower = stats.firepower; // единиц оружия
this.cargo = stats.cargo; // товаров для торговли
this.money = stats.money; //деньги
// лог событий, содержит день, описание и характеристику
// { day: 1, message: "Хорошо покушали", goodness: Goodness.positive}
this.log = [];
// координаты каравана, пункта отправления и назначения
this.caravan = { x: 0, y: 0};
this.from = {x: 0, y: 0};
this.to = {x: 0, y: 0};
this.distance = 0; // сколько всего пройдено
this.gameover = false; // gameover
this.stop = false; // маркер для обозначения того, что караван стоит
this.uiLock = false; // маркер для блокировки интерфейса
}
Game — создание мира и игровой цикл
Игровой цикл запускается и управляется объектом Game. Этот же объект создает мир. Обратите внимание на поле plugins — по умолчанию это пустой массив. Game ничего не знает о плагинах, кроме двух вещей — у них должна быть функция инициализации init(world) и функция обновления update.
Game = {
plugins: [], // генераторы событий,
};
Game.init = function () {
// создаем мир по стартовому состоянию которое хранится в отдельном файле
// в объекте StartWorldState в директории data
this.world = new WorldState(StartWorldState);
var i;
for (i = 0; i < this.plugins.length; i++) {
this.plugins[i].init(this.world);
}
};
// добавление плагинов
Game.addPlugin = function (plugin) {
this.plugins.push(plugin);
};
// игровой цикл
Game.update = function () {
if (this.world.gameover) return; // никаких действий
var i;
for (i = 0; i < this.plugins.length; i++) {
this.plugins[i].update();
}
};
Game.resume = function () {
this.interval = setInterval(this.update.bind(this), GameConstants.STEP_IN_MS);
};
Game.stop = function () {
clearInterval(this.interval);
};
Game.restart = function () {
this.init();
this.resume();
};
Для запуска новой игры надо вызвать функцию Game.restart. Но прежде чем это произойдет, надо добавить какой-нибудь плагин — иначе ничего не будет происходить, у нас просто будет вхолостую работать игровой цикл.
Ешь, живи, двигайся — CorePlugin
Самые базовые действия каравана — перемещение, отсчет времени и потребление пищи — реализованы в объекте CorePlugin:
CorePlugin = {};
CorePlugin.init = function (world) {
this.world = world; // запоминаем world
this.time = 0; // общее время с начала игры, в миллисекундах
this.dayDelta = GameConstants.STEP_IN_MS / GameConstants.DAY_IN_MS; // сколько дней в одном шаге игру
this.lastDay = -1; // отслеживаем наступление нового дня
this.speedDelta = Caravan.FULL_SPEED - Caravan.SLOW_SPEED; // разница между полной и минимальной скоростью
};
CorePlugin.update = function () {
if (this.world.stop) return; // если стоим - никаких изменений
this.time += GameConstants.STEP_IN_MS; // увеличение времени
this.world.day = Math.ceil(this.time / GameConstants.DAY_IN_MS); // текущий день, целый
// Движение каравана в зависимости от того, сколько дней прошло
this.updateDistance(this.dayDelta, this.world);
// события связанные с наступлением нового дня
if (this.lastDay < this.world.day) {
this.consumeFood(this.world);
this.lastDay = this.world.day;
}
};
// еда выдается один раз в день
CorePlugin.consumeFood = function (world) {
world.food -= world.crew * Caravan.FOOD_PER_PERSON;
if (world.food < 0) {
world.food = 0;
}
};
// обновить пройденный путь в зависимости от потраченного времени в днях
CorePlugin.updateDistance = function (dayDelta, world) {
var maxWeight = getCaravanMaxWeight(world);
var weight = getCaravanWeight(world);
// при перевесе - Caravan.SLOW_SPEED
// при 0 весе - Caravan.FULL_SPEED
var speed = Caravan.SLOW_SPEED + (this.speedDelta) * Math.max(0, 1 - weight/maxWeight);
// расстояние, которое может пройти караван при такой скорости
var distanceDelta = speed * dayDelta;
// вычисляем расстояние до цели
var dx = world.to.x - world.caravan.x;
var dy = world.to.y - world.caravan.y;
// если мы находимся около цели - останавливаемся
if(areNearPoints(world.caravan, world.to, Caravan.TOUCH_DISTANCE)){
world.stop = true;
return;
}
// до цели еще далеко - рассчитываем угол перемещения
// и получаем смещение по координатам
var angle = Math.atan2(dy, dx);
world.caravan.x += Math.cos(angle) * distanceDelta;
world.caravan.y += Math.sin(angle) * distanceDelta;
world.distance += distanceDelta;
};
// регистрируем плагин в игре
Game.addPlugin(CorePlugin);
Тут все элементарно. Сначала при запуске игры у нас вызывается init, который позволит сохранить ссылку на модель мира. Затем в игровом цикле у нас будет вызываться update, который будет менять мир к лучшему, как любят говорить персонажи из сериала «Силиконовая долина». Шутка — меняться мир будет во все стороны.
Наш базовый плагин отсчитывает время в миллисекундах, переводит их в дни, а затем обновляет дистанцию и запасы еды. В принципе, объект плагина просто должен содержать функции init(world) и update(), а делать он может что угодно. Можно даже просто вызывать какую-нибудь другую игру на HTML5 или создавать диалоговое окно.
Чтобы подключить плагин, надо добавить его код между определением объекта Game и первым вызовом Game.restart(). Примерно так, как это сделано сейчас в index.html:
<script src="js/Game.js"></script>
<!-- плагины -->
<script src="js/plugins/CorePlugin.js"></script>
<!-- запуск игры -->
<script>
Game.restart();
</script>
Итак, как сделать игру про караван
Если вы опытный программист — вы, безусловно, можете реализовать подобную игрушку на любом языке и графическом уровне, просто отталкиваясь от самой идеи «цикл, в котором происходит перемещение и рандомный выбор из массива событий». Думаю, прекрасно получится даже игра для bash, тем более, что недавние публикации показывают, что там есть весьма интересные графические возможности.
Если вам знаком JavaScript хотя бы на базовом уровне — вы можете скачать исходники к игре, которую я сделал на этом языке, и свободно модифицировать и улучшать их. Вы можете использовать любую архитектуру, если не устроит текущая. Но самый легкий вариант — это просто добавить плагин, реализованный по принципу, описанному выше.
Существующие плагины можно отключать (убирая их исходный код из index.html или закомментировав строку с Game.addPlugin(SomePlugin) в конце их кода). Они ничего не знают друг о друге и просто меняют модель мира или интерфейс игры.
Ну и последний вариант, для писателей — просто открывать файлы в директории data и редактировать описания событий и константы. Хотя это те же JavaScript-исходники, они довольны просты для изменений. Особенно тексты. Чтобы доказать это, я вкратце расскажу, как устроены другие плагины в текущей версии.
Случайные события
Все примитивные случайные события лежат в файле data/RandomEvents.js в переменной RandomEvents в таком формате:
var RandomEvents = [
{
goodness: Goodness.negative,
stat: 'crew',
value: -4,
text: 'На караван напал смертокогть! Людей: -$1'
},
{
goodness: Goodness.negative,
stat: 'food',
value: -10,
text: 'Кротокрысы на привале сожрали часть еды. Пропало пищи: -$1'
},
{
goodness: Goodness.positive,
stat: 'money',
value: 15,
text: 'У дороги найден мертвый путешественник. На теле найдены монеты. Денег: +$1'
},
{
goodness: Goodness.positive,
stat: 'crew',
value: 2,
text: 'Вы встретили одиноких путников, которые с радостью хотят присоединиться к вам. Людей: +$1'
},
Объекты случайных событий содержатся в фигурных скобках. В этом примере я привел только четыре объекта, но вообще их число может быть каким угодно. Только имейте в виду, что при увеличении числа событий вероятность выпадения конкретно отдельного из них уменьшается.
Первое поле — goodness- означает позитивную, негативную и нейтральную окраску сообщения в логе. Второе поле — stat — содержит название параметра WorldState, который должен меняться. Value — это среднее значение для изменения этого параметра. Последнее поле — должно содержать любой произвольный текст, описывающий произошедшее. Вместо символом $1 в текст будет подставлено реальное изменение параметра, которое выпадет в игре.
Случайные события проверяются на выпадение в объекте RandomEventPlugin и радуют взгляд игрока в логе:
Последнее примечание: в RandomEvents.js вы найдете переменную с константой вероятности выпадения случайного события. Она задается как среднее число событий на один игровой день каравана. Когда я экспериментировал с разными значениями, то обнаружил, что слишком много случайных событий, на которые нельзя никак повлиять, начинают дико раздражать. Отсутствие интерактива — это главный минус этих простых событий. Вот почему я почесал голову и решил сделать универсальный модуль диалогов, который можно вызывать из других плагинов.
Как написать или отредактировать диалог
За диалоговую систему отвечает объект DialogWindow. Если вы заглянете в его исходный код, то увидите мутанта, который находит в HTML-коде нужный div-элемент и привязывает к нему общий обработчик кликов мышкой. Идея заключается в том, что когда мы просим этот объект показать нам новый диалог, мы передаем ему массив наших диалогов. И обработчик нажатия на конкретный выбор описывается в конкретном диалоге в таком формате:
var DeathDialogs = {
"start": {
icon: "images/pic_death.jpg", // ссылка на url картинки
title: "Погибший в пустоши", // заголовок диалога
desc: "", // статический текст диалога
desc_action: function (world, rule) { // функция для создания вычисляемого текста диалога
var desc = " Причина смерти: "+rule.text+". Вы сумели пройти "+Math.floor(world.distance) + " миль и накопить "+Math.floor(world.money) + " денег";
desc += "Может быть, следующим караванщикам повезет больше?"
return desc;
},
choices:[ // массив выборов
{
text: 'Начать новую игру', // текст на кнопке
action: function () { return "stop"; } // функция, возвращающая тег следующего диалога
}
]
},
};
В диалогах смерти только один вариант, описанный как поле «start». Но таких вариантов может быть бесконечно много. К примеру, в диалогах бандитов я реализовал 12 развилок. Как происходит переход между ними? Наш универсальный объект DialogWindow при вызове функции show сохраняет у себя список переданных диалогов и показывает тот, который определен в поле «start».
При отображении очередного диалога его массив choices отображается как набор кнопок, в атрибуты которых записывается номер выбора. А все функции action из choices записываются во внутренний массив dialogActions. При клике мышкой на кнопке выбора универсальный обработчик определяет номер функции в dialogActions и вызывает ее, попутно передавая два аргумента, которые мы решили использовать в этом диалоге. Таким образом, в диалогах с бандитами функция action в конкретном choice может принимать состояние мира (world) и описание текущих бандитов (bandits). А в диалогах к другим плагинам — другие параметры. Да можно и вообще без них, особенно, если смысл выбора — просто закончить диалог, как при геймувере.
Чтобы диалог закончился и игрок вернулся к карте мира, надо, чтобы функция action в объекте choice возвращала один из зарезервированных тегов «finish»,«exit»,«stop». Вообще смысл этой функции в том, чтобы возвращать имя следующей развилки. Но до этого заветного return-a можно и порой нужно вставить любую логику, любые вычисления, которые позволят выбрать следующую развилку — «run», «fight» или, быть может, даже «love».
Как вызвать диалог из плагина
В любой момент времени в update любого работающего плагина можно вызвать диалог следующим образом:
// ... где-то в недрах update у объекта-плагина
// останавливаем караван, аналог паузы
world.stop = true;
// просим показать диалог с набором развилок из DeathDialogs
// в развилки будут передаваться аргументы world и rule
DialogWindow.show(DeathDialogs, world, rule, this);
Также в плагине должна быть реализована функция onDialogClose — этот коллбэк будет вызываться после закрытия диалога. Пример из плагина, определяющего наступление смерти:
DeathCheck.onDialogClose = function () {
Game.restart();
};
Краткое описание существующих плагинов
В текущей версии игры используются следующие плагины:
Map2DPlugin — перемещение каравана по карте. Поиск городов, которые задаются в index.html как обычные div с параметрами top и left. Здесь же определяется прибытие в город и происходит автоматическая торговля.
ShopPlugin — генерация случайных встречных караванов или других торговцев. Позволяет купить еду, браминов и нанять наёмников. Или ничего не покупать и пойти дальше.
BanditPlugin — встречи и диалоги с бандитами. Примерно на середине этого плагина я понял, что с идеей сделать простой туториал я погорячился. Простого не получилось, извините. Бандиты могут наняться к вам, а если они умирают с голоду — попросят принять их бесплатно, если вы откажете при найме за деньги.
DropPlugin — плагин перегруза. В прототипе из туториала про орегонский караван игра сама автоматически сбрасывала вещи — сначала оружие, а потом еду. Это было не очень комфортно и вызывало недоумение — как так-то? Ведь с оружием можно добыть еду, а «жареным мясом нельзя убить врага» (с) один известный стрим по Fallout 4. Так что я решил сделать диалог, в котором ты просто выбираешь, от чего избавиться.
DeathCheck — плагин проверки на смерть. Это пока очень простой плагин, и к нему наверняка могут быть вопросы. К примеру, почему люди умирают сразу, когда заканчивается еда? Ну, предлагаю ответить на этот вопрос самостоятельно — или подождать следующей версии, если все пойдет хорошо.
WorldViewPlugin — интерфейсный плагин. Он просто обновляет интерфейс, показывая текущие параметры мира. Возможно, эта идея покажется кому-то странной — самостоятельный объект интерфейса, который отслеживает в цикле обновления изменения переменных. Но зато благодаря этой странной идее мы избавились от многочисленных updateUi и получили независимость между блоками разной логики.
Небольшие советы по текущей игре и балансу
Жизненно важный параметр сейчас — количество еды. Пополнить ее можно при встречах с другими караванами — если они происходят, следует закупаться по максимуму. Конечно, разумно было бы добавить покупку и в городах, но будем считать, что пока все они страдают от недостатка еды.
Второй жизненно важный параметр — количество людей в караване. Они должны быть. Если всех людей выбивают — игра заканчивается.
Все изменения в балансе, увеличивающие ущерб еде и количеству людей, резко повышают сложность игры.
Ссылки и дистрибутивы
Я использовал графику с лицензией Creative Common 0 с ресурсов pixabay.org и opengameart.org, так что и графика, и код распространяется на этих условиях — свободное копирование и использование, без каких-либо обязательств.
Исходный код можно взять с GitHub или скачать zip-архивом отсюда. Первый вариант предпочтительнее, так как чаще обновляется.
Для тестирования даже на локальном компьютере достаточно открыть index.html в браузере — там не используются функции, которым обязательно требуется сервер.
Живой билд игры можно потестить здесь. Верстка рассчитана на обычные мониторы, не на мобильные экраны.
Комментарии (71)
vintage
18.09.2017 21:29+6В гитхабе можно создавать релизы и они будут автоматом упаковываться в архив.
Legion21
19.09.2017 00:16+1Ностальгия по первому фолычу… Желаю успехов и дальнейшего развития проекта!
TheShock
19.09.2017 02:23+1Сейчас геймплей очень простой: выбираешь два ближайших города (кажется, это левые-нижние) и ходишь между ними, уповая на удачу. То есть геймплея, к сожалению, нету.
Жанр, мне кажется, больше всего похож на Космические Рейнджеры, некоторые идеи можно почерпнуть оттуда. Для начала оттуда следует взять экономику — браминов, еду, оружие, товары и людей можно покупать в городах за разные цены. При случайных встречах можно продать подороже и купить подешевле. Цены меняются от количества товара — продаешь пачками и цена падает, покупаешь пачками — цена растет. Появляется смысл следить за ценами, строить разные маршруты, покупать слухи на счет ходовых товаров, думать, стоит ли продавать еду, чтобы купить людей, сдавать весь товар или часть оставить для следующего города.
А еще, кажется, брамины не едят. Может, стоит добавить возле количества еды ее дельту за день?TheShock
19.09.2017 02:28Это, кстати, решит текущую проблему с едой и людьми, когда от игрока, по сути, ничего не зависит
TheShock
19.09.2017 02:43Мой результатTheShock
19.09.2017 03:06+1Можно сказать, что я её прошёл?
Zoolander Автор
19.09.2017 11:05расскажите, как вы этого добились?
это из-за автоматической торговли, которая позволяет не отходя от города набивать деньги? Этот прокол я поправлю, а вашим достижением — горжусьkasperos
19.09.2017 13:07+1Побегал по точкам, возвращаться обратно в город не догадался, но и без этого все получилось.
Начало игры между соседними городами.
Активно создаем по возможности запас пищи (первый приоритет, так как по достижении 0 все пропало, хотя вроде как я понял пофиксили поеданием волов).
Не хватает очень множителя, ибо очень вспоминается в процессе покупки пищи волов и прочего молодость.
Перед тем как зависнуть (видимо попал на момент обновления), накопил 1500 браминов, 1,5 мегаденег, центнер людей.
Еще идеи:
От пропорции людей/волов имеет смысл менять скорость каравана, так как если один человек будет вести 1000 волов, то высокий шанс их растерять, а большое количество людей сказывается на скорости поедания еды, а волы как я понял еду добывают по пути.
Классификация людей:
Наемники — универсал охотник/загонщик но требует периодической зряплаты, на то он и наемник.
Охотник — плохо управляется со скотом но хорошо отражает нападения бандитов/хищников.
Загонщик — хорошо управляется со скотом но плохо помогает в обороне.
Пропорция вознаграждения должна зависеть от дистанции между городами, так как пройти караваном наискосок через всю карту, и выйти за забор и вернуться назад разные риски.
vlukanichev
19.09.2017 13:41
Пожалуй да, даже без стояния в одном городе можно набить стартовый капитал между двумя близ стоящими городами. И дальше можно бегать из одного противоположного угла в другой. Открыв консоль для того чтобы не ломать мышку кликами по 1000 раз при покупках можно получить что то такое. Врядли тут можно проиграть. Было бы неплохо добавить возможность покупать «оптом». Или, как вариант, дать всем встречающимся магазинам лимит по товарам.
findoff
19.09.2017 09:42Еще проще: нажимаем на другой город, выходим и нажимаем обратно… $$$
vlukanichev
19.09.2017 11:03Еще проще: тоже самое только никуда выходить не надо. Можно просто кликать в тот город в котором стоишь получая каждый раз по $600.
iSergios
19.09.2017 07:47+4Гм, идем, значит, мы караваном в 35 человек, еды 5000+, браминов 60+, денег 20к+, и тут на тебе:
День 155: На дороге найдены хорошие довоенные кожаные сапоги. Запасы еды: +3
А еще очень странно, когда 10-20 здоровых (или не очень) мужиков дохнут в пустыне с голоду при полусотне живых браминов рядом :)
За идею и реализацию большой респект :)Zoolander Автор
19.09.2017 11:08да, быков можно будет жарить
думал о механике людоедства (в истории реальных переселенцев такое случалось), но решил, что можно обойтись и без этого.ikovrigin
19.09.2017 13:19-310-20 здоровых мужиков будут жарить быков… разрешите им в городе брать баб в отряд.
ikovrigin
19.09.2017 13:35-2Похоже некоторые не осознали всей глубины игры с добавлением баб… это же песочница игрок может делать что хочет. Могут бабы жарить быков, могут мужики жарить баб, а могут даже быки жарить баб, тут все зависит от фантазии, только в зависимости от уровня фантазии нужно будет повышать возрастные ограничения.
kasperos
21.09.2017 07:30+1Занятная ситуация, караван шел, шел, ели быков потихоньку, когда съели последнего: караван завис вместе с браузером.
Кстати а чем собственно они там заниматься будут когда последнего быка съедят или потеряют, а «магазина» с быками не попадется.Zoolander Автор
21.09.2017 15:24Пофиксили — убрали бесконечный цикл проверки. Теперь, когда заканчивается еда, забивают 1 брамина, чтобы пройти условие проверки смерти с нулевыми запасами еды. Это может выглядеть странно, если в отряде от 100 человек и больше, а едят каждый день только 1 брамина. Но поскольку в планах вообще добавить разумный диалог с выбором действий — такая механика автозабития браминов пока принимается, как временное решение )
Milfgard
19.09.2017 10:16+1Чёрт, какая может крутая инди-игра получиться.
Жалко только, Беседка за вами может прийти — стоит чуть-чуть начать косить под Фаллаут.johnnymmc
19.09.2017 10:44+1Да, интересненько. Отдалённо напоминает тёплвй ламповый Oregon Trail. Было бы клёво добавить сюжетностей, NPC со своими вызывающими сопереживание историями и возможностью осмысленного общения, всего такого, добавить какой-то атмосферный арт и может весьма уютная штука выйти.
Zoolander Автор
19.09.2017 11:44приятно увидеть человека, знакомого с Oregon Trail!
изначально у меня даже был небольшой обзор этой игрушки, как дедушки всех караванов, но я убрал из-за большого объема. Ну и вдобавок я сам не застал живые версии старых Oregon Trail, поэтому был риск, что могу спороть какую-нибудь ерунду.
Туториал с простым караваном, на который я ссылаюсь, в свою очередь ссылается на Oregon Trail. Так что это дедушка и этого каравана )johnnymmc
19.09.2017 13:09+1Взаимно приятно :-) Вообще Oregon Trail Deluxe 1992-го года прекрасно скачивается по первой же ссылке из Гугла (myabandonware) и легко запускается через CrossOver на Маке. Провёл за ним в обнимку с девушкой несколько невероятно уютных вечеров :-) (а вот Oregon Trail II, например, уже показалась черезмерно усложнённой). Подумал тогда что надо будет как-нибудь написать что-то подобное. Рад, что в опенсорсе появился такой проект. Но мне кажется надо будет только всё-таки слегка усложнить-детализировать игровую модель, увеличить мир и добавить сюжетную составляющую и может выйти что-то очаровательное. Очень здорово, что в основу заложена идея отделения данных от движка, так что в будущем не-программисты смогут достаточно легко вносить вклад в обогащение игрового мира.
johnnymmc
19.09.2017 13:39Вообще меня завораживает мысль об игре, более-менее глубоко воспроизводящей идею Фллоаута в таком вот формате. Оригинальный Фоллаут по сути сочетал в себе интересную и душевную книгу, обширный интерактивный мир в котором можно жить и навороченный «рогалик» с очень атмосферной графикой. И мне кажется, что по первому и второму пунктам (а именно они мне кажутся главными, интерес к обшариванию ветвистых корридоров и истреблению толп монстров в них у меня лично пропал достаточно быстро, хотя многие, наверно, как раз такое любят) можно сделать на уровне и переплюнуть запросто, достаточно чуточку допилить движок и попробовать затянуть в команду несколько писателей более-менее адекватных фанфиков с тематических форумов. А если плюс к этому ещё удастся найти художников, которые нарисуют атмосферных иллюстраций (способных на это на самом деле не так уж мало), то вообще будет бомба.
TheRabbitFlash
19.09.2017 10:5935 кб это много или мало? Меня зацепило название. Тут упор на «как можно меньше»? ) Если да, то код можно «похудеть» в 2 раза :)
Zoolander Автор
19.09.2017 11:13думаю, что 35 килобайт — это скорее мало, чем много
но вы правы — в исходниках много места занимают тексты и названия функций
я старался создать читаемый код, хотя бы для себя
с играми на таком принципе можно смело идти на конкурс js13k — там есть что оптимизировать и сократитьTheRabbitFlash
19.09.2017 11:44Читаются очень здорово, согласен :)
Я себе делал как-то тулзу, которая ищет повторяющиеся блоки в коде и дает их переименовать ручками :) некий прокачанный find&replace. В итоге код любой более-менее либы сокращается на 10-50% :)
Tisar
19.09.2017 11:01Брамины это что такое? и зачем они нужны?
P.S.: в игре не помешало бы иметь справку с описанием характеристик и краткой механикой игры.
theWaR_13
19.09.2017 11:44Очень интересно написана сама игра. То, как работают плагины в частности. Обязательно изучу исходники потом. Спасибо большое за статью! :)
jaguard
19.09.2017 11:55+2Механика этой игры довольна проста, а её графические возможности — это диалоги, индикаторы и движение по карте мире. Ее сила — в магии текстовых игр, которые способны с помощью слов описывать самые невероятные приключения.
Эм… А собственно, где? Где магия текста и невероятные приключения?
Где «Вы осторожно входите в ржавые руины, бывшие когда-то огромным городом. На входе — остатки приволоченных откуда-то гаражных ворот и двое грязных оборванцев, похоже служащих стражей города; один одет в шапку-ушанку, второй — абсолютно лысый, зато имеет третий глаз..»?Zoolander Автор
19.09.2017 16:31Это вы сами придумали?
Я могу использовать этот кусок текста для оформления одного из будущих городов, которые появятся в следующем апдейте как нечто большее, чем просто точки? )
den_golub
19.09.2017 15:18Было бы неплохо если бы караван еще двигался, когда ты уходишь с вкладки, хотя это уже мелочи.
TheShock
19.09.2017 16:21Было бы неплохо если бы караван еще двигался, когда ты уходишь с вкладки, хотя это уже мелочи.
Я так предполагаю, что используется requestAnimationFrame. Стоит заменить на setTimeout и все заработает.
mcsimkin
19.09.2017 15:25Главное, в начале игры удачно затариться браминами, людьми и едой, а дальше проиграть просто невозможно.
Zoolander Автор
19.09.2017 15:28Рад, что игра нашла опытных игроков.
Ну, баланс можно утяжелить, увеличив вероятность встречи с бандитами с 0.1 до 1 в день для начала. Еще можно добавить событий, отнимающих еду, быков и людей.
Мне сначала это показалось слишком жестким — особенно с рандомом — поэтому сейчас баланс в игре довольно мягкий и позволяет легко отыгрывать манчкина, набивая десятки тысяч
danl
19.09.2017 15:33+2
на этом всё закончилось — OutOfMemory exception (последний FF, памяти ел всего около 1.5Гб)
Наверное «прошёл» :)Scf
19.09.2017 15:54Это сколько же человеко-клико-часов потрачено на покупку еды и браминов....
danl
19.09.2017 17:22+1ну не будет же веб-разработчик кликать 100 раз чтоб купить 2000 еды :) конечно без консоли и программных кликов (по 100 — 1000 за раз) не обошлось. Но эти клики были только в диалоге торговли и только потому, что нельзя купить сразу много. Особенно это востребовано на поздней стадии — когда надо кормить целое войско, а опта нет.
Zoolander Автор
21.09.2017 16:02ограничили размер лога, если будет свободная минутка — попробуйте запустить свои волшебные скрипты еще раз, будет ли OutOfMemory exception?
Tatikoma
19.09.2017 19:03+1Остановился на 20к браминов (закупка через xdotool click --repeat 1000 --delay 0 1).
Количество браминов совершенно необходимо связать с количеством людей. При 20к браминов я держал при себе 30-40 людей только для того, чтобы случайно не умереть. Покупать большее количество людей нет никакого толку.
По тактике — главное сначала скопить штук 100 браминов, запас 2000 еды и людей человек 20. Дальше просто докупаешь браминов — объем торгов растёт. Оружие — непонятно что и как работает. При значении 500 — никаких потерь в стычках с бандитами уже нет (количество людей, вероятно тоже не влияет?).
«смертокогть» — кажется опечатка.
Если десять раз тыкнуть на целевой город — он десять раз напишет «путешествие начинается», даже если путешествие уже в самом разгаре.
Случайных не интерактивных событий происходит очень много — они занимают много места в логе игры, таким образом тот становится довольно бесполезным. Было бы хорошо отделить важное от неважного. Найденные запасы еды и отбитые атаки гекконов — даже в самом начале игры не оказываются сколь-либо сильного влияния на игровой процесс.
В текущем формате после 5-15 минут игры — делать становится нечего. Возможно добавление мультиплеера (и связанных с ним игровых моментов) сможет дать хороший толчок.
Непонятно что со скоростью работы самой игры. За весь игровой процесс скапливается не самый длинный текстовый лог (а нужен ли он целиковый?) + значения 8 чисел, однако при 20к браминов обсчет случайных событий занимает у меня 1-3 секунды. Товарищ чуть выше жаловался на OutOfMemory. Очевидно так быть не должно.
В целом автор молодец. Атмосферно.Tatikoma
19.09.2017 19:14Выше предлагают по аналогии с космическим рейнжерами сделать разные цены в разных городах. Мысль здравая, но сильно усложнит игру — это вообще другой жанр. Одно дело ходилка/бродилка, другое дело — экономическая стратегия. На мой взгляд нужно регулировать рост сложности игры с процессом прохождения, но другими методами. Конкретно — использование процентных ставок в событиях, учёт размера городов и прочие мелочи.
Вообще непонятно, сам город какого размера, что я в него нормально захожу с 20к браминов? — Откуда у них каждый раз в наличии 3млн груза?
Почему смертокогти убивают ровно 4 человек? — При некотором стечении обстоятельство они легко вырежут, скажем, 50% всей ватаги? :-)
sumanai
19.09.2017 22:25+1Разок промазал по кнопке…
Побег
Воодушевленные вашим отступлением, бандиты стреляют вам вслед и улюлюкают. Ваши потери: люди: 1 / браминов: 751 / eда: 10467. Денег: 5514632
Akuma
В целом круто, только я несколько раз погибал от голода, но при этом еды купить было просто негде. Надо бы какой-то баланс добавить.
Так же смертокогти убивали тупо всех людей, хотя у меня куча еды, оружия и бабла.
Zoolander Автор
да, справедливо
магазины в городах добавятся
смертокогти, как и все остальные причины смертей, думаю, надо выносить из чисто рандомных событий в более управляемые события. Это наследие «орегонского каравана», там люди вообще умирали от дизентерии
bond1768
Вообще ништяк идея. В городе надо магазины сделать что бы можно было самому баланс настраивать — что продать что докупить.
Viacheslav01
Миру все равно, есть вы или нет, мир ничего не должен вам, мир подарил вам жизнь, но больше мир вам ничего не должен.
findoff
Добавил поедание браминов…
https://habrahabr.ru/post/336724/#comment_10423496
Zoolander Автор
спасибо, вечером посмотрю на рабочей машине
kasperos
Глюк: если количество людей таково что количество еды после потребления в день становится равно 0, при имеющемся запасе браминов караван погибает от голода.
findoff
В коде автора 0 еды = все умерли.
В теории поправил, уменьшив допустимое кол-во съедаемой еды до забивки браминов до (имеющегося-1).
Но вообще думаю если развивать тему, то надо перерабатывать многое.