0,0
рейтинг
23 апреля 2012 в 08:56

Разработка → Ностальгия: роемся у «Танчиков» под капотом

Многие из нас выросли на «Танчиках», «Марио» и прочих нетленных шедеврах времён рассвета игровой индустрии. Приятно порой вспомнить, как днями напролёт резались с друзьями у экранов телевизоров, меняя джойстики как перчатки. Но время не стоит на месте, и одни интересы сменяются другими. Однако, порой любовь к старым-добрым игрушкам не угасает.
Я отношу себя к людям именно таким, и мой интерес к старым играм пошёл в сторону реверс-инжиниринга, что и привело меня в IT-сферу, где я и осел с концами.

Я хочу рассказать вам о том, что же под капотом у железных монстров из знаменитой игры Battle City (в простонародье «Танчики») с не менее знаменитой приставки Nintendo Entertainment System (сокращённо NES, в России более известен её китайский клон «Dendy»). Мне в своё время эта информация показалась довольно любопытной — надеюсь, такой же она покажется и вам.

Предыстория


Несколько лет назад, изучая разнообразные графические библиотеки, я поставил перед собой цель написать точный клон «Танчиков». Так уж сложилось, что как раз в тот момент один мой знакомый занимался созданием довольно интересного ремейка путём модификации кода оригинальной игры, так что я решил проконсультироваться у него (кстати, огромное ему спасибо за консультацию и помощь в подготовке статьи). Тогда меня поразило то, какими методами реализовывался некоторый функционал. Вот и решил я, спустя годы, поделиться этими знаниями с общественностью: всё-таки это часть истории геймдева, которая может показаться интересной как ценителям классики, так и разработчикам современных игр.

Хочется сказать отдельное спасибо человеку под ником Griever за труды по декомпиляциии игры. Прежде всего благодаря полученным им исходникам стало возможно настолько подробно вникнуть в суть.

Карты уровней


Карты в Battle City состоят из тайлов — блоков размером 8x8 пикселей. Весь фон, видимый на экране, является картой — гипотетически даже со счётчиком жизней можно взаимодействовать, но по факту это, конечно же, не удастся.

Однако, в сериализованном виде уровни хранятся более компактно: для этого тайлы компонуются в блоки размером 2x2 тайла. Всего имеется 16 разновидностей блоков, которые приведены в таблице ниже. Хранится только основная часть карты (13x14 блоков), по которой и ездят танки — нет смысла сохранять статичные стены и вспомогательную информацию. Для записи одного блока используется 4 бита, таким образом, вся карта занимает 91 байт.

Блок Код Блок Код Блок Код Блок Код
0 1 2 3
4 5 6 7
8 9 A B
C D E F


В отличии от блоков, разновидностей самих тайлов гораздо больше, а именно — 256, т.е. ровно столько, сколько вмещает одна страница знакогенератора — участок видеопамяти, где каждому тайлу соответствует индекс от 0 до 255. Тайлы используются как для создания окружения уровня, так и для отображения информации о количестве вражеских танков, жизней и т.п. Но непосредственно в элементах уровня их используется всего 22 — из них 6 для формирования перечисленных блоков, остальные 15 — дополнительные тайлы кирпичных блоков, о них стоит рассказать подробнее.

Если карта состоит из тайлов размером 8x8 пикселов, то как же получается уничтожать кирпичные мини-блоки размером 4x4 пиксела? Дело в том, что на самом деле не существует «кирпичей» такого размера, вместо этого существует 16 видов обычных тайлов — по одному на каждое состояние. Т.е. при попадании по блоку размером 4x4, в реальности заменяется целый тайл, а сам кирпич переходит в другое состояния, в зависимости от того, куда попал снаряд.



Поэтому, кстати, при уничтожении части кирпичного блока, танк не может въехать на освободившееся пространство — ведь сам тайл не был уничтожен.

Расположение точек респауна и орла на карте фиксированы, объекты будут появляться на своих местах независимо от того, что находится в месте их появления. Это и происходит, если во встроенном редакторе уровней «замуровать» эти участки.

Если кому-то интересно позаниматься картостроительством, то для этих целей существует хороший редактор Quarrel, который работает прямиком с образом игры.

Генерация случайных чисел


Задача генерации случайных значений с давних пор не давала покоя человечеству. Программным путём получить истинно случайное значение невозможно, поэтому зачастую задача сводилась к генерации псевдослучайных значений с распределением, близким к тому, что свойственно случайным.

Для компьютера с полностью детерминированным поведением генерация псевдослучайных чисел является ещё более сложной задачей. Например, при каждом запуске, оказывая одинаковое воздействие (нажимая одни и те же кнопки в одно и то же время), мы будем получать одинаковый ход игры — на этом принципе даже основаны записи игрового процесса, где для каждого кадра хранятся нажатые в тот момент кнопки. Но для нас это не столь критично: важно получать как можно более «случайные» значения в рамках одного сеанса.

Рассмотрим, как обстоят дела с Battle City. Здесь для генерации псевдослучайного значения используется несколько «случайных» сущностей — это предыдущее случайно значение, счётчик секунд и поочерёдно байты т.н. нулевой страницы — первых 256-ти байт оперативной памяти, которые процессор NES может адресовать быстрее и проще, чем остальные. Именно поэтому нулевая страница содержит наиболее часто используемые, и, как следствие, наиболее часто изменяемые переменные, что обеспечивает более равномерное распределение.

В итоге на конечное значение числа влияет множество факторов: нажатые игроком кнопки, координаты всех танков и пуль на экране, количество очков обоих игроков, состояние множества таймеров (таких как бонусные) и даже состояние звуковых каналов! Конечно, это далеко не полный список.

Само выражение, по которому высчитывается очередное случайное число, довольно простое. Не буду вдаваться в подробности, просто покажу, как это выглядело бы на языке C:
uint8 seed = 0;
uint8 index = 0;

uint8 rand()
{
	seed = (seed << 3) - seed + secondsCounter + zeroPage[++index];
	return seed;
}


Как видно из кода, мы можем в любой момент получить псевдослучайно значение в диапазоне от 0 до 255. При том его распределение достаточно адекватно, в чём можно убедиться по нетленному геймплею.

Бонусы


В игре есть ровно семь типов бонусов — каска, часы, лопата, звезда, граната, танк и пистолет. При этом в оригинальной игре последний не используется вовсе, зато его можно встретить в пиратских модификациях — там он делает мгновенный максимальный апгрейд, т.е. эквивалентен трём взятым звёздам (а в некоторых вариациях ещё и позволяет уничтожать «лес»). Действия же остальных бонусов, думаю, известны каждому. Но, на всякий случай, напомню: часы заставляют врагов застыть, лопата создаёт броню вокруг штаба, звезда увеличивает мощность танка, граната уничтожает всех противников на экране (при этом очки за них не начисляются), а танк увеличивает количество жизней.



Кстати, в пиратских версиях с пистолетом присутствует ещё один бонус — корабль, который позволяет передвигаться по воде. Также в некоторых модификациях бонусы могут брать и противники, что в корне меняет баланс игры. Существовали даже целые сборники подобного рода модификаций, где версии различались разными подобными мелочами.

Судя по всему, изначально планировалось включить в игру восемь бонусов, но в итоге их осталось шесть. Однако, при появлении бонуса берётся случайное значение по модулю 8 (от 0 до 7), которое является индексом в таблице бонусов, где место не включенных в игру бонусов повторно заняли звезда и граната. В итоге вероятность их выпадения равна 1/4, в то время как вероятность выпадения остальных бонусов равна 1/8.

Бонусы часы и каска действуют 10 секунд (при респауне игрока каска действует 3 секунды, включая время на респаун), бонус лопата — 20 секунд.

Сами носители бонусов — мигающие танки — появляются, если у врага в ангарах остаётся 17, 10 или 3 танка. Т.е. танки под номерами 4, 11 и 18 — бонусные.

Стоит упомянуть, что секунда по меркам игры длится немного дольше обычной: у NTSC-версии консоли частота обновления экрана составляет 60 кадров в секунду, и самым простым способом вести счёт секунд является в каждом кадре увеличивать номер секунды, если счётчик кадров по модулю 60 равен нулю. Но для упрощения вычислений, а также, чтобы обнуление счётчика кадров в результате переполнения не влияло на подсчёт таким способом, это число округлили до 64 (0x40) — для взятия числа по этому модулю достаточно произвести логическое умножение на 0x3F. Получается, что игровая секунда составляет 1.06 реальной секунды, но это не касается временных отрезков, которые измеряются количеством кадров.

Занимательный факт, известный каждому знакомому с игрой: перед тем, как перестать действовать, защита вокруг штаба начинает «мигать», превращаясь то в кирпичное, то в бронированное ограждение (происходит это в последние 4 секунды действия бонуса). При этом, даже если защита вокруг штаба была частично или полностью уничтожена, каждый раз при мигании она восстанавливается, пока полностью не превратится обратно в целую кирпичную стену.

Интеллект противников


Конечно, AI в танчиках не представляет собой тактический анализатор, но кое-какая логика всё же высчитывается.

Начнём с того, что игра имеет динамическую сложность. В качестве показателя сложности используется значение задержки между респаунами врагов, которое зависит от уровня и количества игроков — чем больше эти значения, тем быстрее будет происходить респаун. Время респауна в кадрах для заданного уровня (нумерация с нуля) и количества игроков можно вычислить по следующей формуле: 190 - level * 4 - (player_count - 1) * 20. Чтобы получить время в секундах, надо просто умножить результат на 60.

Существует три периода поведения танков: сначала они движутся хаотично, затем они преследуют игроков, и, в конце концов, начинают атаковать штаб. Длительность первых двух периодов одинакова и равна восьми периодам респауна. Т.е., поделив время респауна на 8, мы получим длительность в секундах (или, умножив на 8, получим то же самое время в кадрах) — например, для первого уровня и одного игрока это будет 23 секунды. Третий же период будет длиться до тех пор, пока счётчик секунд не обнулится (достигнув 256), и цикл периодов не начнётся заново.

Вся эта вражеская тактика основана на системе команд, для чего выделено 8 байтов: два под танки игроков и шесть под вражеские танки. Четыре старших бита такого байта используются под команду, оставшиеся четыре младших — под её аргументы (как правило это направление движения). В итоге получается 16 команд, под каждую из которых существует обработчик. Обработчики вызываются раз в кадр для каждого танка после обработки движения.

Поверхностно рассмотрим существующие команды:
  • 0 — NOP (танк отсутствует)
  • 1..7 — обработать взрыв танка (по команде на кадр анимации)
  • 8 — обработать статус (скольжение по льду и т.п.)
  • 9 — изменить направление
  • A — проверить на пересечение границы тайла
  • B — двигаться к штабу
  • C — двигаться к танку второго игрока
  • D — двигаться к танку первого игрока
  • E..F — команды управления респауном


Существует функция смены направления, которая при вызове в первом периоде поведения меняет направление танка случайным образом, во втором периоде даёт танкам с чётными номерами команду двигаться к первому игроку, с нечётными — ко второму, а в третьем даёт команду двигаться в сторону штаба.

При пересечении вражеским танком границы тайла (когда обе коодринаты становятся кратны восьми), существует вероятность 1/16, что для танка будет вызвана эта функция. Если же координаты танка не были кратны восьми, либо же не была вызвана функция смены направления, и при всём этом танк упирается в препятствие, то с вероятностью 1/4 произойдёт следующее: танк сменит направление на противоположное, если хотя бы одна из координат не кратна восьми, в ином случае танку будет дана команда смены направления.

При выполнении команды смены направления происходит несколько другое: с вероятностью 1/2 вызывается описанная выше функция, иначе с равными вероятностями циклически берётся либо предыдущее, либо следующее направление из списка: вверх, влево, вниз, вправо (т.е. танк поворачивается либо по часовой, либо против часовой стрелки).

Можно представить всю эту логику в виде такого псевдокода:
void changeDirection(Tank tank)
{
	// period duration in seconds, respawn time in frames
	const int periodDuration = respawnTime / 8;
	
	if (time() < periodDuration)
	{
		// first period
		tank.setRandomDirection();
		tank.setCommand(cmdCheckTileReach);
	}
	else if (time() < periodDuration * 2)
	{
		// second period
		if ((firstPlayer.isAlive && tank.number % 2 == 0) || !secondPlayer.isAlive)
		{
			tank.setCommand(cmdMoveToFirstPlayer);
		}
		else
		{		
			tank.setCommand(cmdMoveToSecondPlayer);
		}
	}
	else
	{
		// third period
		tank.setCommand(cmdMoveToEagle);
	}
}

void onCheckTileReachCommand(Tank tank)
{
	if (!tank.isPlayer && tank.x % 8 == 0 && tank.y % 8 == 0 && rand() % 16 == 0)
	{
		changeDirection(tank);
	}
	else if (!tank.isPlayer && frontTile.isBarrier && rand() % 4 == 0)
	{
		 if (tank.x % 8 != 0 || tank.y % 8 != 0)
		 {
			  tank.invertDirection();
		 }
		 else
		 {
			  tank.setCommand(cmdChangeDirection);
		 }
	}
}

void onChangeDirectionCommand(Tank tank)
{
	if (rand() % 2 == 0)
	{
		 changeDirection(tank);
	}
	else if (rand() % 2 == 0)
	{
		 tank.rotateClockwise();
	}
	else
	{
		 tank.rotateAnticlockwise();
	}
}


Интересная ситуация получается, когда танк упирается в препятствие или стену — поскольку в таком случае, даже если танк не повернул, одна из координат постоянно кратна восьми и перед ним существует тайл-препятствие, то вероятность поворота возрастает в разы. Поэтому танки практически не застревают на месте: даже попадая в угол или нишу, они довольно быстро оттуда выезжают.

Не менее интересно обстоят дела с вражескими выстрелами. Сами по себе они происходят абсолютно обособленно от танков — у каждого врага есть одна пуля, а выстрел в каждом кадре сам решает, запустить эту пулю или нет. Если пуля уже в полёте, то выстрела не происходит, иначе существует вероятность 1/32, что танк выстрелит. В таком случае, пуля оказывается на передней границе танка по её центру и наследует направление своего танка.

Стоит сказать пару слов и о поведении танков игроков в режиме демонстрации. Тут всё просто: если на экране есть бонусы, танки стремятся к ним (при этом могут застрять по пути, если пуля пролетает мимо препятствия, в которое они упираются). Иначе они просто преследуют первый доступный танк, а если таковых не осталось — стоят на месте. Снаряды выпускаются по тем же правилам, что и у вражеских танков. Огонь по своим в демо-режиме не даёт эффекта.

Обработка коллизий


Расчёт коллизий всегда был довольно ресурсоёмкой задачей, что может быть критично для такого процессора, как у NES. Просчёт взаимодействия между танками с реализацией «в лоб» требовал бы сравнить каждую пару танков, что, несмотря на их небольшое количество, всё же довольно дорогостоящая процедура для процессора с тактовой частотой 1.76 МГц. Но не стоит забывать, что кроме танков по карте передвигаются и выпущенные снаряды. Поэтому разработчики пошли на довольно интересную хитрость.

Дело в том, что каждый танк… «рисует» под собой невидимую стену. Таким образом, обнаружение коллизии между танками происходит на этапе обнаружения коллизий между танками и элементами уровня, для чего достаточно лишь определить, имеется ли по определённой координате препятствие. Имеет это и побочные эффекты: наверняка многие замечали, что если пытаться «въехать» сзади в движущийся вперёд танк, движение игрока блокируется, пока танк не отъедет на некоторое расстояние — как раз в этот момент он переезжает на следующий тайл, «рисуя» там новую стенку и «стирая» старую.



Тот же эффект можно заметить, когда в танк попадает снаряд. Визуально соприкосновение возникает на разной дистанции от границы спрайта танка (как внутрь, так и наружу) — от 0 до 7 пикселей. Но если танки рисуют под собой стену, то пули — нет. Более того, на расчёт коллизий между снарядами уходит большая часть времени кадра! И в особых случаях его может даже не хватить, тогда все эти операции перенесутся на следующий кадр, а текущий не будет изменён. Т.е. да, и в «Танчиках» бывают лаги.

При попадании снаряда одного игрока по другому, второй теряет управление движением на 192 кадра, т.е. на три игровых секунды. Но в режиме демонстрации этого не происходит.

Примечательно то, что снаряд имеет две точки, по которым проверяются коллизии. Они находятся по бокам от носа пули, и фактически может быть обработано две коллизии одновременно (иначе, после обнаружения хотя бы одной из них, снаряд исчезает). Это и происходит, если, например, целиться в центр кирпичного блока: уничтожается целая полоска.

Ещё одна интересная вещь: медленные пули (подробнее о скорости чуть ниже) обрабатываются не каждый кадр, а через кадр. Теоретически может возникнуть ситуация, когда игра будет тормозить в каждом нечётном кадре, и процессор не будет успевать дойти до обработки коллизий такой пули, откладывая её. А ведь в следующем кадре он и вовсе не должен будет её обрабатывать! Из-за подобного стечения обстоятельств медленные пули в некоторых чрезвычайных случаях могут пролетать стенки насквозь, когда игра сильно притормаживает.

Движение


Скорость в игре обуславливается количеством пропускаемых кадров при изменении координат. Так, например, у игрока координата меняется каждые три кадра из четырёх, у самого быстрого врага в игре — каждый кадр.

То же самое касается и снарядов — их существует два типа: быстрые, летящие со скоростью 4 пикселя в кадр, и медленные, имеющие скорость 2 пикселя в кадр.

Танк Скорость, px/frame Тип снаряда Танк Скорость, px/frame Тип снаряда
3/4 Медленный 2/4 Медленный
3/4 Быстрый 4/4 Медленный
3/4 Быстрый 2/4 Быстрый
3/4 Быстрый 2/4 Медленный


Поскольку при движении необходимо обрабатывать и коллизии, то уместно было бы оптимизировать рассчёты, как можно более равномерно распределив их по кадрам. При самом простом подходе достаточно было бы в чётных кадрах обрабатывать перемещение всех врагов, а в нечётных только передвижение шустрого БТР. Но тогда нечётные кадры могли бы быть перегружены, и игра бы просто лагала.

На самом деле нагрузка распределена довольно хитро. Производится «XOR» между номером кадра и номером танка, и только потом проверяется чётность/нечётность результата. В итоге получается, что в чётных кадрах обрабатывается одна половина медленных танков, а в нечётных — другая.

И немного информации о скольжении на льду. Тут всё просто: после того, как игрок отпустит кнопку направления на льду, танк будет ехать сам ещё 28 кадров (т.е. проедет 21 пиксель) или пока не выедет со льда. В этот период состояние его гусениченого трака не меняется и звук езды не проигрывается, а если нажать кнопку направления уже на льду — будет проигран характерный звук, если таймер скольжения в этот момент равен нулю.

Пасхальные яйца


Пасхальные яйца встречаются во многих играх того времени, не обошли стороной они и Battle City.

Если на титульном экране выбрать режим CONSTRUCTION, войти и выйти из него 7 раз (нажимая START, START), затем зажать на первом джойстике кнопку «вниз», нажав на втором кнопку A 8 раз, потом зажать на первом джойстике «вправо», нажав на втором кнопку B 12 раз, и, наконец, нажать на первом джойстике кнопку START, то мы увидим трагическую историю любви.



Кроме того, в игре можно встретить неиспользуемые данные — имена разработчиков (RYOUITI OOKUBO, TAKEFUMI HYOUDOU, JUNKO OZAWA) и иероглифы, означающие имя главного героя лавстори и название улицы (возможно, на которой жил он сам или его возлюбленная).



Пожалуй, здесь я не буду вдаваться в подробности, ибо это подробно изложено по ссылке чуть выше.

Эпилог


В заключение хочу сказать, что раньше создание игр было в некотором смысле всё же большим искусством, чем сейчас. Это же колоссальное мастерство — уложиться в ограничения аппаратной части, и в то же время создать хорошую игру. Это сродни демосцене, которая, по сути, преследует те же самые цели — создавать шедевры там, где это сложно вообразить.

В наши дни всё это уходит в прошлое, позволяя не особо задумываться о способах реализации. На мой взгляд, это сильно понижает порог вхождения в процесс разработки игр, что постепенно, но верно превращает его скорей в обыкновенный бизнес, чем в искусство. Хотя, возможно, я просто слишком эстетичен в этом отношении.
Михаил Быстрянцев @horror_x
карма
181,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (72)

  • +22
    Танчики! Детство моё сопливое)) Прям столько воспоминаний нахлынуло… Спасибо Вам.
  • –41
    Это же колоссальное мастерство — уложиться в ограничения аппаратной части, и в то же время создать хорошую игру.

    Флешеры игроделы как раз именно этим и занимаются…
    Спасибо огромное за статью!
    • +24
      Если вспомнить на какие ухищрения шли разработчики игр на ZX Spectrum, то флешеры просто как сыр в масле катаются.

      А ведь ещё игры на электроника МК 62/61 были
    • +6
      Помните стеб во времена дисков типа «1000 лучших игр» когда выходила какая-нибудь тяжелая игра говорили с сарказмом, что «теперь компактная игра — это игра, с трудом влезающая на компакт!» Тогда казалось, что игры под 600 -700 метров это дикость какая-то.

      А сейчас выгоднее заниматься не оптимизациями, а кроссплатформенностью, чтоб и на PC и на приставках играть можно было, над пиаром, чтобы игра в первые дни разошлась как можно большим тиражом, т.к. очень быстро появляются пиратки. Время разработки становится гораздо важнее оптимизаций, т.к. пока конкурент усиленно вылизывает свою игру, можно уже 2-3 своих выпустить. Иногда выпускают такое, что не верится, что у разработчиков вообще был отдел тестирования.
      • +6
        Вы знаете. Я играл в Арканум. И несмотря на то, что она тормозила на мощных для того времени машинах, имела кучу багов и занимала два диска это была прекрасная игра.
        • +2
          Полностью согласен. Отличная RPG была (ну и есть :)).
        • +1
          То, что значительное количество плюсов позволяет смириться с минусами, не означает, что минусы — это хорошо.

          Например, очень часто в TBS не заморачиваются с оптимизацией поиска пути, что приводит к тому, что ход занимает три секунды вместо трехсот миллисекунд. А эти секунды складываются в полчаса ожидания за партию из полутысячи ходов. Пример реальный, в той игре после того, как оптимизацию таки сделали, ходы компьютера стали практически моментальными, а до того на больших картах занимали секунд по 15.

          Особенно «весело» когда подгрузки практически не завясят от железа — это явный признак косяка в архитектуре.
          • +1
            Я к тому, что ни микрооптимизации, ни ограниченное железо, ни мощнейший отдел тестирования не сделают бездушную игру душевной, а остутствие всего этого не заберёт душу у хорошей игры.
            • 0
              Душа — это хорошо, но Квазимодо всё же не самый приятный объект.
              • +2
                Душа — хорошо, а крайности — плохо.
                • +2
                  Забить на оптимизацию ради души — и есть крайность :)

                  Я готов простить примитивную графику, но когда игра по десятку секунд грузит маленький спрайтовый уровень на мощном процессоре и сверхбыстром SSD — это, извините, никуда не годится. Когда на этом же железе в реальном времени и идеально гладко рендерится сложнейшая 3Д графика с уймой объектов, полигонов и источников света, а убогая плоская картинка дергается в конвульсиях — это рукожопие программиста.

                  Возможно, впрочем, это у меня профдеформация — уже который год в геймдеве, а когда приходится писать свои имплементации механизмов типа ArrayList (да, Java) ради выигрыша в скорости то как-то раздражают те, кто просто кладут на это.
                  • 0
                    Забить на оптимизацию ради души — и есть крайность


                    Опять вы в крайности. Где «забить на оптимизацию»? Почему если оно не работает на 1.76 МГц, то это уже «забили на оптимизацию»? Почему нельзя «оптимизировать в меру»? Выше я приводил в пример Арканум. Да, графа так себе. Да, на слабых машинах тормозит. Но играли с упоением. А если бы писали свои имлементации типа ArrayList ради выиграша в скорости, то мы бы могли вообще игры не увидеть.

                    когда игра по десятку секунд грузит маленький спрайтовый уровень на мощном процессоре и сверхбыстром SSD

                    и снова крайности. покажите пример игры, которая «по десятку секунд грузит маленький спрайтовый уровень на мощном процессоре и сверхбыстром SSD»? Хотя бы одной? Только не случай, когда человек вообще не разбирается в основах игростроения, а нормальный продукт, рассчитанный на людей.
                    • +1
                      Sonic 2 HD Remake
                      Грузится у меня по несколько минут. А разработчики в ридми так и говорят, мол «Ждите или апгрейдите комп»
                    • 0
                      и снова крайности. покажите пример игры, которая «по десятку секунд грузит маленький спрайтовый уровень на мощном процессоре и сверхбыстром SSD»? Хотя бы одной? Только не случай, когда человек вообще не разбирается в основах игростроения, а нормальный продукт, рассчитанный на людей.


                      Пожалуйста. Вот вам на выбор разные масштабы.

                      Eador — через 3 года после выхода автор таки немного занялся скоростью, после чего ход компьютера ускорился на 2 порядка, и почти исправлены дикие тормоза анимаци на более-менее мощных компьютерах. Раньше приходилось извращаться с замедлением процессора.

                      Mass Effect 2 — если заменить ролики во время загрузки уровней на заглушки то грузится всё практически моментально вместо десятков секунд.

                      Magic the Gathering 2012 — в момент перевода хода часто игра заметно подвисает на пустом месте, с явной зависимостью от мощности компьютера. Откровенный и бросающийся в глаза косяк.

                      Recettear — что там вообще можно грузить совершенно неясно, графика примитивная спрайтовая, уровни маленькие, но из-за ошибки где-то в архитектуре прогрузки дико долгие. Зато если поковыряться в конфиге и выставить жесткий лимит FPS то грузит моментально.

                      Опять вы в крайности. Где «забить на оптимизацию»? Почему если оно не работает на 1.76 МГц, то это уже «забили на оптимизацию»? Почему нельзя «оптимизировать в меру»?
                      Оптимизация в меру — это когда на актуальном железе всё работает с вменяемой производительностью. А если имеются очевидные косяки с явным несоответствием производительности и результата — это рукожопие. И оно ну никак не связано с качеством сюжетной линии и проработанностью игровой механики.
                      • 0
                        Ок, согласен, такие игры есть.
                        Но моя мысль в том, что не оптимизации определяют наличие души в игре. И привёл в пример Арканум, которая подтормаживала на современном железе, но, при этом, была с душой.
                        • 0
                          А моя в том, что душа — не оправдание для рукожопия. Хотя и порой заставляет его терпеть.
                          • 0
                            Не оправдание. Но это не значит, что оптимизации==душа.
                            • 0
                              Ну значит сойдемся на том, что душа у игры это хорошо, но профайлер забывать не надо, ему одиноко в этом жестоком и холодном мире.
                          • 0
                            Сделал человек (люди) как мог. Как говорится, не нравится — не кушайте. Он может не кладёт на профайлер, а просто о нём не знает. Или видит, что узкое местор сортировка, но кроме пузырька ничему его не учили. Как может такой факт раздражать?
                            • 0
                              Так это ведь коммерческие продукты. Я конечно знаю, что по традиции к софту не применяются никакие критерии качества, но сам с этим не согласен. И не нравится тут не катит — возврат некачественного продукта не предусмотрен.

                              Не умеешь — поищи в интернете, там всё есть.
                    • 0
                      И к чему я вообще упомянул. Можно делать так — признать наличие необходимости и исправлять проблему. А можно как обычно — послать игроков в жопу и сказать «это релиз, мы уже продали игру и нам невыгодно заниматься дальнейшей поддержкой, покупайте следующую из серии».
  • +5
    Очень интересно. Много нового узнал для себя.

    P.S. А про пасхалку даже не знал. К сожалению, по ссылке информации не так много. Вообще нашли этих влюбленных или нет? :)
    • +1
      Увы, о судьбе влюблённых история умалчивает :)
  • +5
    Сразу два детства напомнило: детство, когда играл в них, и детство программистское, когда была задача написать их клон.
  • +2
    Про счетчик кадров очень интересно!
  • +4
    Когда играли в «танчики» в детстве, то кто бы мог подумать, что когда нибудь буду изучать их внутреннее устройства с програмерской точки зрения.
  • +2
    Спасибо, очень интересно было. А поставленная задача решена? Точный клон создан?

    На мой взгляд, это сильно понижает порог вхождения в процесс разработки игр, что постепенно, но верно превращает его скорей в обыкновенный бизнес, чем в искусство.

    Бог с ними с ограничениями. Придумать хорошую игру (без учёта ограничений) само по себе искусство. Втиснуть её в аппаратные ограничения — скорее инженерная задача.
    • +1
      А поставленная задача решена? Точный клон создан?
      К сожалению, из-за особенностей генерации случайных чисел эта задача оказалась мне непосильной. Целью было не просто написать клон, а ещё и получить точно такое же детерминированное поведение.
      • +1
        Странно, вы же полностью описали алгоритм, дальше осталось только добавить «прокладку» в виде искусственного таймера, не привязанного к FPS. Можно даже оставить «длинные» секунды.

        Я понимаю, что это проще сказать, чем написать, но вы с такой любовью описали все это, что захотелось чтоб хоть у этой истории был счастливый финал )
        • +3
          Там же в качестве некоторых переменных выступают состояния элементов аппаратной части, поэтому воссоздать абсолютно идентичный геймплей можно только точной эмуляцией :)
  • +5
    Интересно. Я бы ещё добавил в качестве введения об устройстве видеопамяти устройств от Nintendo. Конкретно вот это описание я делал про Gameboy, в NES оно тоже близкое к этому:

    Довольно интересная организация экрана. Как таковой сплошной экранной памяти (как в БК или хотя бы как в ZX Spectrum) вообще нету. Отдельно лежат тайлы 8x8 в количестве до 192 штук. На экран выводится проекция аж трёх планов, снизу вверх: фона, окна и объектов (т.е. спрайтов). И фон и окно — это матрицы 32x32 индексов тайлов. И для фона и для окна можно задать координаты от угла, с точностью до пиксела — тем самым, полноэкранный скроллинг не стоит буквально ничего, значение в регистр занести! Объекты (они же спрайты) — это те же тайлы, но для каждого спрайта задано положение с точностью до пиксела, и цвет 00 считается прозрачным. При этом можно создать до 40-ка спрайтов размером 8x8 либо 8x16 (размер одинаков для всех спрайтов). Каждому спрайту можно задать отражение по вертикали и/или горизонтали — тоже даром, один битик взвести. Но в одной строке может быть не более 10-ти спрайтов.

    В общем, получается вещь довольно удобная для разного рода платформеров и скроллеров — загружаем кучу тайлов, набираем из них игровую сцену, сверху плюхаем подвижные спрайты. С другой стороны, работать с экраном как со сплошным полем — довольно тяжело.
    • 0
      А NES от PC-Engine сильно отличается в этом плане кроме поддержки большего объемы цветов?
      • 0
        Вы имеете в виду организацию режимов графики на PC того времени? Да сильно. Судя по тому, что тут описано, получается, что на NES графика сильно походила на продвинутый текстовый режим.
        • 0
          Нет, я про это ru.wikipedia.org/wiki/PC_Engine. Процессоры то там одинаковые моторолловские, а цвет PC-Engine выдает как SNES, вот и хотелось узнать — внутри игры то отличаются и как сильно.
  • +5
    Да, восхищаюсь игроделами того времени. Полностью согласен с эпилогом
  • 0
    из пиратских бонусов еще был Корабль позволяющий преодолевать воду)
    • +1
      один из любимых бонусов
  • 0
    Шикарно :) любимая игра для денди
  • +3
    Спасибо автору за пост! Еще бы такой разбор по Elite был. Всегда хотел узнать как на Z80-м делали почти 3D
    • +2
      Мне лично более интересен был бы разбор генерации миров, планет и прочего :)
      Автору спасибо за отличный пост!
  • +1
    В заключение хочу сказать, что раньше создание игр было в некотором смысле всё же большим искусством, чем сейчас
    Да сейсас программисты уже так не ограничены в своих возможностях и игру в большинстве случаев оценивают по работе дизайнеров, аниматоров и модельеров.
    P.S. Пользуясь случае покажу свои варианты танчиков и марио в акаде на основе его примитивов:
    www.youtube.com/watch?v=946fmxv5cC8
    www.youtube.com/watch?v=p20zAhB3mjU
  • +2
    Возможно, кому-то пригодятся исходники на ActionScript: code.google.com/p/bcmmog/
    Play BattleCity
  • +6
    Только у меня в голове заиграла фоновая музыка? :)
    • +3
      У меня еще пронеслись все основные звуки игрового процесса, особенно звук взятия бонуса и звук двигателей :)
      • +1
        У меня неповторимы «Пыхххх» когда штабу капут =)
    • +2
      А я покосился на приставку Денди, которую получил от Анонимного Деда Мороза… Там и эти танчики, и марио и контра и многое другое. Вот же она, рядом лежит )
      image
      • 0
        Эта маленькая коробочка под ёлкой нового 1994 года перевернула жизнь 6 летнего ребёнка (меня) на всегда. До сих пор сохранилась… надо бы её починить и сыну показать.

        PS правда, на моей мотоциклист был другого цвета и я ни когда не мог понять, что значит слово «турбо» в турбо джойстиках.
        • 0
          Что ж тут непонятного? Турбо — это круто!
        • 0
          У классического контроллера по одной кнопке A и B, у «турбо» — дополнительные «rapid fire» A и B, которые, будучи зажатыми, имитируют быстрые повторные нажатия на обычные A и B. Полезно в шутерах )
          • 0
            Все. Пропал смысл жизни) У меня всегда было как выше — если турбо — значит круто! =)
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Псп? Смотрю понять никак не могу
      • НЛО прилетело и опубликовало эту надпись здесь
  • +1
    А есть ли современный римейк этой игры? Например новая графика, уровни, но старый геймплей.
    • 0
      Tank-o-box например. Ещё есть тут.
    • 0
      Не совсем ответ на вопрос, но всё же:

      Tank Force — сиквел, выпущенный Namco на аркадных автоматах в 1991 году. (Вот тут есть скрины.)
      Согласно википедии, в 2009 году в Японии его ещё на Virtual Console (читай Nintendo Wii) выпустили.

      Кстати, был, оказывается, и приквел — Tank Batallion.
  • 0
    Где можно взять дизассемблер, для копания в ром'ах?
  • 0
    Помню была у меня Sega :) Каждую неделю было такое: «Мам, дай денег на новый джойстик».
    • 0
      Джои низкого качества и Мортал Комбат с Врестлманией плохо сочетались это да
  • 0
    Эх, эти знания бы тогда, когда писал свои «улучшенные танчики» на паскале, но что-то шло не так, и ресурсов почему-то не хватало даже с ассемблерными вставками :) Спасибо за замечательную статью, побольше бы таких.
  • 0
    Вот автор пишет: Расчёт коллизий всегда был довольно ресурсоёмкой задачей, что может быть критично для такого процессора, как у NES.

    Ресурсоёмкой? Ой да ну ладно. Тот же ZX-SPECTRUM (да, там 4 МГц процессор, но зато нет дендивского видеопроцессора со спрайтами который на порядок ускорял работу с графикой на экране) — сделал вот один маньяк там игру BlackRaven — RTS(!), поддержка мыши етц. А вы говорите коллизии для десятка танчиков посчитать дорогая операция. Фуффф
    • 0
      Вы сравниваете разные вещи — в RTS работают несколько другие алгоритмы. Да и по видео на ютубе невооруженным глазом видно, что у Black Raven на рассчёты часто уходит более одного кадра. Для игры вроде Battle City это было бы абсолютно нежелательно.

      Если вы пожелаете доказать обратное, руководствуясь более объективными доводами, с удовольствием почитаю ваше доказательство :)
      • 0
        Я не сравниваю, я говорю о том, что ресурсы даже такого хиленького процессора, как у NES, в рамках рассматриваемой игры — просто огромны и задача по типу (опять возвращаюсь к предыдущей формулировке) «найти коллизии между танками» не может быть сколько-нибудь дорогой в контексте задержек игрового процесса.

        Собственно, суть предыдущего комментария и сводилась к тому что автор явно переоценил «дороговизну» данной операции для процессора
        • 0
          Откуда у вас такая уверенность в своих словах? Пока что она не сопровождается ни одним объективным доводом.
          • 0
            Прям чувствую как Вам хочется похоливарить, поэтому это мой последний комментарий — дальше пишите что хотите.

            8bit CPU, 64Kb Ram — это одинаково и в NES и в ZX-Spectrum

            Z80@4MHz успевал (не нравится Black Raven — посмотрите первую UFO — она тоже realtime была) заниматься расчетами и (очень важный фактор) отрисовывать всю графику (а экран на спектруме был не особо удобно с точки зрения «что нибудь на нём нарисовать» устроен).

            В NES есть спрайтовый процессор, т.е. CPU отрисовкой графики не занимается, только расчёты. Конкретно в Battle city расчетов этих — около нуля, т.к. вычислительная мощность этой игрушки никакая. «Задача недорогая для процессора» — означает что он её овер9к раз успеет посчитать без задержек в игре.

            Объективные доводы? Ну я не знаю. Вытащите кусок кода который занимается «обработкой коллизий», сделайте бесконечный цикл и посмотрите, сколько раз он их за время одного кадра успеет посчитать, прежде чем считать это «дорогой» задачей.

            Спасибо за оказанное внимание :)
            • +2
              Мне хотелось лишь услышать что-нибудь более объективное, чем ваше личное мнение. Всё-таки перед написанием статьи я проводил кое-какие исследования, и если я где-то допустил ошибку — то будьте добры, укажите на неё. Иначе холивар затеваю не я :)

              А вам советую просто взять ручку, бумагу и прикинуть «на глаз»: при частоте 1.76 МГц мы получаем простор примерно в 30 000 тактов в кадр. Допустим, на обработку коллизии одной пули надо 50 инструкций, максимум на экране может находиться 10 пуль (6 вражеских и 4 пули танков игроков). В среднем на инструкцию приходится 4 такта, т.е. получаем 200 тактов на обработку одной пули.

              Пусть мы проверяем пули только на столкновение друг с другом. Чтобы попарно сравнить 10 пар, понадобится 45 сравнений. 45 * 200 = 9 000 тактов, и это не учитывая других проверок и излишней оптимистичности исходных данных. Могу где-нибудь ошибаться, но это не важно — даже при грубых подсчётах очевидна дороговизна данной операции.
  • +1
    Вот он какой… World of Tanks моего детства! =)
  • 0
    страшно представить как реализовывались такие игры как battle toads. Вообще заметен огромный прогресс в играх сравнении 87 года и 93 (battle toads, kirby`s adventure) И музыка инетреснее стала, и оформление, прямо таки выжимание всех соков из железа.
  • 0
    Где можно качнуть полную коллекцию спрайтов?
    • 0
      В сети полно ресурсов с подобными архивами. Погуглите «Battle City Sprites NES».
      • +1
        Плохо, что все они в низком разрешении — под оригинальную NES

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.