Разработка и ромхакинг > Разработка игр
[SMD] Battle City (форк от battlecity-md от KRIKzz)
Sharpnull:
Werton, остаток Game Over тоже видел и в Gens, ловил ещё в версии 1.07. Если найду причину, напишу.
Sharpnull:
* Исправил остатки спрайтов Game Over и других, дело в этом цикле:
--- Код: ---u16 spr_kl2 = sprite_counter;
for (ttt=0; ttt<(spr_kl-sprite_counter)+2; ttt++) {
VDP_setSpriteFull(sprite_counter, -8, -8, SPRITE_SIZE(1, 1), 0, sprite_counter+1);
sprite_counter++;
}
--- Конец кода ---
sprite_counter изменяется и используется в условии, из-за этого не все спрайты затираются.
* Также убрал обновление спрайтов из коллбэка VBlank и перенёс перед VDP_waitVSync() (т. е. перед VBlank, а не сразу после), это приводило к мерцанию при 9+ танков на поле и остаткам тайлов на экране подсчёта экрана. Хотя 9+ танков быть всё равно не должно, в этом случае начинаются тормоза.
* Написал VDP_updateSprites(1, FALSE); вместо VDP_updateSprites(1,1);, чтобы спрайты танков сразу исчезали после экрана очков.
* Убрал мерцание в начале уровня, не тот слой становился серым. SYS_disableInts() не понадобилось :) В Kega Fusion почему-то последние полосы открытия видны чуть дольше, чем должны. Это было и до моих правок.
--------
Из багов, которые кажется не были озвучены:
- В оригинале если стрелять по центру блока, а слева или справа осталась тонкая стенка, то она не задевается:
--- Код: ---0001 или 1000
0001 1000
/\ /\
|| ||
--- Конец кода ---
- Петух не задевается, если стрелять со смещением. Нужно в detectBulletToStaffCollision() дописать по аналогии с detectBulletToWallCollision().
- Если зажать кнопку выстрела (не турбо), то при движении или повороте происходят выстрелы.
- При заморозке (оглушении?) игрока, он может один раз выстрелить.
Werton:
Sharpnull, отличная работа :thumbup:
Добавлено позже:
--- Цитата: Sharpnull от 01 Май 2018, 01:09:10 ---Хотя 9+ танков быть всё равно не должно, в этом случае начинаются тормоза.
--- Конец цитаты ---
Вот поэтому я не стал особо увеличивать кол-во танков в моде, заметил эту тормозню, видимо надо код оптимизировать, явно консоль на большее способна.
Werton:
Добавил еще возможность стрельбы при заморозке, собрал описание фиксов для наглядности, за сами фиксы дружно благодарим Sharpnull), отметил его как тестера и багфиксера в стартовых титрах :)
--- Код: ---===== версия 1.08-4 =====
-добавлено возможность стрельбы при заморозке игрока (как было в оригинале)
-устранено невозможность уничтожить блоки возле границ поля внизу и справа
-устранено заезд танков за правую и нижнюю границы поля
-устранено остатки спрайтов Game Over
-устранено при смене экрана подсчета очков спрайта танков исчезали с задержкой
-устранено мерцание в начале уровня
-устранено смещение взрыва со всеми стенами
-устранено иногда при выстреле происходило пробитие двух кирпичей вместо одного
-устранено потенциальное мерцание танков
-устранено враг после взятия часов размораживался слишком быстро
--- Конец кода ---
battlecity-md_1.08-4.zip (158.14 КБ - загружено 382 раз.)
Sharpnull:
Werton, принял pull request, возможно стоило объединить в один коммит (squash), добавил как есть. Добавил вас в Collaborators, если что.
Sharpnull:
Важное исправление. Было смещение спрайта пули и её начальной позиции вылета:
Случайно заметил, что пули летящие вниз и вправо дольше в полёте, стал отнимать 8 пикселей при отрисовки и оказалось, что пуля вылетает прямо из позиции танка, которая в левом верхнем углу, поэтому стреляя влево/вверх вылет был прямо из ствола, а в другие стороны пуля пролетала через весь танк. Думаю баг "-Снаряд появляется поверх танка ближе к центру (второй скриншот). ..." можно убрать из багов, я наверно ловил как раз тот момент пролёта через танк (обновление: посмотрел ещё раз оригинал, кажется всё-таки ближе к стволу, а не из центра). Возможно +/- пиксель не точно, пули при рикошете кажутся чуть дальше слева.
Новый баг: смещение спрайта танка врага, раньше не замечал пока не стал им. Приложил скриншоты.
Это оказался не баг, а оригинальное смещение с NES. Правда спрайты танков всё равно имеют немного другое положение, это не так важно.
Sharpnull:
Новые исправления:
* В прошлом исправлении смещение спрайта стояло от балды. Я посмотрел на спрайты пули и сделал точные смещения, теперь центр пули как на скриншоте.
* Убраны нежелательные выстрелы, если зажать A или C (с вкл. турбо) и двигать танк. Если это была фишка, тогда я её сломал :)
* Возможность разрушить орла, если пуля смещена. Но не как в оригинале, где разрушение уже после 3-го выстрела, а после 4-го. На скриншоте после 3-го выстрела орёл цел. Чтобы как на NES, обработку столкновений с орлом нужно перенести туда же, где и кирпичи, но придётся решать проблемы со звуком: когда я пробовал, звук разрушенного кирпича перебивал.
Werton, убийство себя рикошетом с вкл. PVP модом считается нормальным поведением?
Werton:
--- Цитата: Sharpnull от 02 Май 2018, 14:39:52 ---убийство себя рикошетом с вкл. PVP модом считается нормальным поведением?
--- Конец цитаты ---
Да, так и задумывал, чтобы эффект модов суммировался и жизнь медом не казалась :lol:
Sharpnull:
Важные исправления, так как влияют на столкновения пули и танков:
* Раньше можно было убивать стоя задом к врагу. В версиях до моих фиксов такое было возможно только в двух направления, а после - во всех направлениях, так как снаряд летел из центра, а не из угла.
* В двух направлениях пуля нагоняла на 6 пикселей раньше.
* Раньше пуля была не пикселем, а летящей палкой перпендикулярно направлению полёта. Из-за этого окно попадания поперёк пули было 28 пикселей (30 - 2*1 отступа), а вдоль было 14 (16 - 2*1) пикселей. Теперь 16x16, как размер спрайта, можно выглядывать и тебя не убьют, но проехать через вас не получиться как в оригинале.
Найден новый баг: сохраняются моды после игры в Mad Mode и последующую игру в другой режим.
Werton,
* Если можете, посмотрите конфиг, чтобы сбрасывалось правильно. Если сохранять нужно только Options, то проще config_init() вызывать перед выбором режима, тогда и моя правка в modeMenu() config.game_mode = 0; не нужна будет.
* Я ошибся что анимации взрывов длились меньше, не знаю почему мне так казалось. Сверил по кадрам: в NES маленький взрыв 10 кадров, а здесь 11, что достаточно точно. Кадры считал в FCEUX с замедлением времени, а для SMD через GensKMod. Из history.txt этот пункт не убирал.
* Тормоза при 9+ вражеских танков из-за проверки столкновений, так как проверяются все со всеми в gamelogic.c:
--- Код: ---delta_1 = moveAvailableInUnits(&game_player[i]);
game_player[i].posx += speed_x[game_player[i].rotate];
game_player[i].posy += speed_y[game_player[i].rotate];
if (!moveAvailableInWalls(&game_player[i])) {
game_player[i].posx -= speed_x[game_player[i].rotate];
game_player[i].posy -= speed_y[game_player[i].rotate];
game_player[i].collision++;
}
delta_2 = moveAvailableInUnits(&game_player[i]);
if (delta_1 > delta_2) {
game_player[i].posx -= speed_x[game_player[i].rotate];
game_player[i].posy -= speed_y[game_player[i].rotate];
game_player[i].collision++;
}
--- Конец кода ---
Этот код выполняется для каждого танка, а в moveAvailableInUnits() проверка также для всех танков. Я пробовал хак и перед delta_2 = moveAvailableInUnits(&game_player[ i ]); дописывал if (delta_1 == 32) continue;, это отсекало один вызов moveAvailableInUnits(), если танки были далеки друг от друга, и FPS оставался на уровне 60, но если были близки - тормоза оставались такими же.
В NES, как следует из этой статьи, танки рисовали под себя невидимые стены, это позволяло избежать вычислений и поэтому по стволу игрока могли проехать. Переделывать как в оригинале было бы долго, лучше оставить как есть.
* Подробности исправлений столкновений. Из collision.c, в detectBulletToUnitsCollision() стало:
--- Код: ---s16 bx = bull->posx;
s16 by = bull->posy;
// Этих переменных и условий не было. Если margin_x = 1 и margin_y = 1, то обработка столкновений 14x14
s16 margin_x = 0;
s16 margin_y = 0;
// (game_player[i].rotate & 1) и !(game_player[i].rotate & 1) можно убрать, но если margin_x > 0 или margin_y > 0,
// то танк стоящий вдоль пули, но со смещением поперек пули (8 пикселей), не будет убит, что может считаться правильным поведением, только не в оригинале
if ((game_player[i].rotate & 1) && !(bull->rotate & 1)) {
margin_x += 7; // Корректировка для поперечного столкновения с пулей, фактически она шириной 2 пикселя
} else if (!(game_player[i].rotate & 1) && (bull->rotate & 1)) {
margin_y += 7; // ...
}
if (bull->rotate == 3) {
bx -= 15; // Было 9, на 6 пикселей раньше прилетало
} else if (bull->rotate == 2) {
by -= 15; // Было 9, ...
}
delta_x = bx - game_player[i].posx;
delta_y = by - game_player[i].posy;
// Don't kill with ass
// Ниже проверки отсекают убийство задом
if ((delta_x < 0 && bull->rotate == 1)
|| (delta_x > 0 && bull->rotate == 3)
|| (delta_y < 0 && bull->rotate == 0)
|| (delta_y > 0 && bull->rotate == 2))
continue;
if (delta_x < 0) delta_x = -delta_x;
if (delta_y < 0) delta_y = -delta_y;
// Было delta_x < 15 && delta_y < 15, это давало отступ 1 по сторонам (28x14 или 14x28), теперь 16x16
if (delta_x < 16 - margin_x && delta_y < 16 - margin_y) {
// Дальше убийство
--- Конец кода ---
--------
Ещё одно замечание, так как код запутанный. Если margin_x = margin_y = 1..n, то отступ дальней стороны от пули всё равно будет 0. Для того, чтобы были честные отступы, нужно ещё проверку делать вроде delta_x >= margin_x, delta_y >= margin_y, при этом только одно из них в зависимости от направления пули. Проще было бы заменить код на проверку пикселя внутри прямоугольника, но я следовал духу кода :)
Werton:
--- Цитата: Sharpnull от 03 Май 2018, 14:31:29 ---сохраняются моды после игры в Mad Mode и последующую игру в другой режим.
--- Конец цитаты ---
Исправил на гите, а также исправил найденный баг с продолжением движения замороженного в движении игрока.
Sharpnull:
--- Цитата: Werton от 03 Май 2018, 16:41:24 ---баг с продолжением движения замороженного в движении игрока.
--- Конец цитаты ---
Хотел спросить об этом, думал может это специально, как паралич в Road Rash (мотоцикл едет дальше). В сообщении выше в самом низу я добавил ещё замечание о столкновении, на всякий случай.
--------
Как я и боялся, остались некоторые переменные. Из mutator.c:
--- Код: ---case 13:
mods.en_on_map_inc = 1;
config.max_enemies_on_map = MAX_ENEMIES + 2;
config.units_on_map = config.max_enemies_on_map + 2;
config.max_explode = config.units_on_map << 1;
config.max_bullets = config.units_on_map << 1;
--- Конец кода ---
Количество врагов остаётся после этого, остальное тоже, кроме en_on_map_inc.
Ещё эти (mods_count - точно) из config_init():
--- Код: ---config.mods_count = MODS_COUNT;
config.mods_inc_lvl = MODS_INC;
--- Конец кода ---
А config.random_mods = RANDOM_MODS; всегда имеет это значение. Но это уже по рефакторингу, там есть ещё лишние переменные вроде config.difficulty и дублировании mods.en_on_map_inc = 0; в reset_modes().
Werton:
--- Цитата: Sharpnull от 03 Май 2018, 17:00:25 ---А config.random_mods = RANDOM_MODS; всегда имеет это значение. Но это уже по рефакторингу, там есть ещё лишние переменные вроде config.difficulty и дублировании mods.en_on_map_inc = 0; в reset_modes().
--- Конец цитаты ---
RANDOM_MODS это флаг для дебага так сказать, чтобы отключить случайность и можно было моды потестить
config.difficulty да не используется, это остатки от было начатой реализации настройки сложности, но заброшенной т.к. тупо надоело это все. Остальное справедливо, честно я полностью потерял интерес к этой затеи, поправь все как сам считаешь нужным, если есть такое желание конечно.
Sharpnull:
Исправления, в основном визуальные для соответствия оригиналу:
* Сброс настроек после игры с модами.
* Исправлены положения: GAME OVER (во время игры), жизней, PAUSE.
* GAME OVER (во время игры) рисуется поверх танков.
* Мерцание PAUSE быстрее.
* Вместо иконки второго игрока IIP отображалось IP.
* Жизни отображаются на одну меньше как на NES. Не знаю сколько макс. количество жизней в NES, здесь нет ограничений. При 20000 очках в NES прибавляется жизнь, здесь нет.
К слову, о неточностях с оригиналом:
При игре вдвоём, после смерти игрока сбоку прибегает GAME OVER для проигравшего игрока.
При переходе на следующий уровень шторки закрываются для карты уровня, а не для подведения рекордов, как здесь.
GensKMod мусор конечно, кадры он неправильно сохранял. Запись экрана в 60FPS дала точнее результат. Маленький взрыв происходит по-разному от 6 до 9 кадров, а в оригинале около 10. Время анимации не буду трогать.
--------
Ещё одно исправление:
* Проверка столкновений снарядов была смещена, это сказывалось на перпендикулярных столкновениях. Вражеский танк даже мог отбить летящий в его бок снаряд, выпустив свой в другом направлении. Теперь видно как снаряд подлетает к другому и сбивает.
Обновил файл.
Sharpnull:
Исправления, в этот раз со звуком:
* Был звук разбивки кирпичной стены вместо звука разбивки снаряда в некоторых случаях. Также сейчас: если одновременно бить по стали и кирпичу, будет оба звука в разных каналах (SOUND_PCM_CH3 и SOUND_PCM_CH4). Баг был известен как:
-звук попадания как в кирпич при попадании в вертикальную броню (2 кубика), снизу и сверху справа (вообще глюки со звуком)
* Использовался неверный звук снятия HP с танка. Теперь "заморозка" тоже с таким звуком, на NES же при "заморозке" другого игрока никакого звука не было.
* Если у первого игрока закончились жизни, второго игрока нельзя было убить бомбой, взятой противником.
Из звуковых несоответствий остаются, исправлять нет смысла:
- Звук стоящего танка должен прерываться после убийства всех врагов. Но если это звук нашего танка, почему он прерывается в оригинале? Затишье после войны или это был звук не нашего танка?
- Звук взрыва базы во время стартовой музыки отсутствует. Такое возможно только когда игрок себя убивает сразу.
Sharpnull:
Исправления, теперь с очками:
* Не работала загрузка рекорда из SRAM. Была в 1.07b, в 1.08 сломалась. Ваш эмулятор сохраняет это в файле название_игры.srm обычно в папке с эмулятором.
* Было ошибочное удвоение очков.
* Теперь за взятые бонусы дают очки.
* Не давали очки за врагов в оболочке игрока. С этим багов связаны другие: много очков за убийство такого врага, а после смерти появлялся спрайт рождения вместо количества очков.
С врагом в оболочке игрока остались проблемы. Даже если оболочка начальная, поведение всё равно будет как у обычных танков, а очки дают за оболочку. То есть за жирного врага с начальной оболочкой игрока будет 100 очков вместо 400, но если враг возьмёт звезду, то очки будут +100. Исправлять это не буду, но чтобы не сбивать с толку на подведении очков отображаются оболочки игрока.
* После первого запуска игры движения врагов были одинаковыми, кроме режима Mad Mode.
---
Ещё одно исправление на сегодня:
* Мод жоподёр (ass killer) работал неправильно, враг убивался если игрок имел такой же поворот танка во время попадания.
Sharpnull:
Мой последний релиз. Напоминаю, что исходный код находится здесь: https://github.com/infval/battlecity-md.
Исправления:
* Была проблема с модом ass killer, когда вторая пуля выпущена в другом направлении, пока первая в полёте.
* Танк застревал в воде, если у него сбивали способность плавать. Теперь танк уничтожается сразу.
* За убийство себя или другого игрока с модом "игрок убивает игрока" (pvp_kills) давали очки и отображался неправильный спрайт очков после убийства. Теперь очков не дают и спрайта нет.
* Теперь последний результат второго игрока показывается на главном экране, но в отличие от оригинала он не скрывается, если в последний раз игрок был один.
* Редактор уровней: была анимация танка (из-за неинициализированного объекта структуры _tank), мерцание танка не работало, обновление спрайта танка задерживалось.
Замечания по коду и проекту:
- Остались ещё баги и сам код написан плохо. Добавление модов запутало код ещё больше.
- При реорганизации кода были изменены положения графики (gfx.s), что видно на скриншотах (видеопамять до и после). Во втором ряду не используются тайлы: '!' (на NES рядом с BONUS при игре вдвоём), где стоят '?', какой-то мусор в виде клизмы после 'STAGE'.
Убраны gfx/bonus.bin, tiles.s так как дублировали бонусные тайлы, кроме "корабля" и рамки для танка, отображающей взятие бонуса "корабль". Эта рамка находится в конце gfx.s, но её можно переместить вместо "клизмы".
- Символы 0-9, A-Z, -, ., "пробел", [, _, ] расположены в видеопамяти по ASCII таблице, поэтому их не стоит трогать.
- kzzlogo.s не используется. В папке .vscode настройки для работы в Visual Studio Code. _make_clean_project.bat - очистить проект, нужно если изменения были сделаны в .h-файлах и в некоторых других случаях, _make_project.bat - компиляция проекта без очистки (это быстрее).
Что можно улучшить или добавить:
- При проверки столкновений использовать паттерн проектирования "Двойная буферизация" (http://gameprogrammingpatterns.com/double-buffer.html). Сейчас проверка происходит в текущем кадре на основе текущего положения, которое зависит от порядка проверки.
Пример: танк игрока 1 едет, а за ним игрок 2 впритык. Так как сначала проверка у первого игрока, они едут без зазора, но если поменять танки местами, то игрок 1 будет отставать на одно смещение, потому что игрок 2 ещё не сдвинулся в этом кадре.
- Сжимать уровни. Сейчас каждый маленький блок (8x8 пикселей) кодируется одним байтом: 70 уровней * 26 ширина * 26 высота = 47320 байт (~46КБ). Если уровни строятся как в режиме конструктор (нужно проверить), то каждый блок (16x16) кодируется 4 битами: 70 уровней * 13 ширина * 13 высота / 2 = 5915 байт (~6КБ).
- Порядок появления и состав врагов в оригинале всегда одинаковый, в сети есть информация о составе. Здесь используются случайные танки.
- Бонусы (Power-Ups) дают только 3 раза на уровне. Здесь 5 раз. Видел упоминание, что бонусы располагают в 16 местах. Здесь по всей карте и могут попасть в воду или в сталь.
- В оригинале даётся 1000 бонуса игроку, который набрал больше очков при игре вдвоём.
- Более точное начальное расположение пули. Сейчас разница в один пиксель в зависимости от направления. Плюс там странный код, который смещает иногда ещё на один пиксель (функция GLog_shot). Наверно стоило убрать.
- Только 2 типа скоростей пуль, в оригинале 3.
- На NES вода не двигается во время паузы.
- На NES звук гусениц прерывается после убийства всех врагов.
Баги:
- Звук взрыва базы во время стартовой музыки отсутствует.
- Музыка пропадает на следующем уровне, если взять в конце уровня бонус. Также остаётся след от взятия бонуса.
- После первого выстрела, второй быстрее выпускается, чем последующие с зажатой кнопкой.
--------
Увеличил скриншоты. Добавил загадочную "клизму" (или капля).
Werton:
Sharpnull, хорошо поработал, респект :thumbup:
vovan225:
Парни спасибо за игру! вспомнил 90-стые. Хотел сказать ещё про одну очень важную фитчу - в игре на приставке ещё можно было брать жизнь у второго игрока нажатием двух кнопок А и B одновременно. Можно это реализовать??? Было бы офигенно!!! Без этого играть в двоем не очень интересно, если одного убили то ему тупо остаётся ждать пока доиграет другой.
Sharpnull:
--- Цитата: vovan225 от 11 Январь 2019, 22:02:40 --- брать жизнь у второго игрока нажатием двух кнопок А и B одновременно
--- Конец цитаты ---
Тестируйте.
vovan225:
:wow: Спасибо!!! ща будем тестить!
Добавлено позже:
Протестили - первый игрок может брать жизни а второй нет, по крайней мере в танк 1990 так. И вот бы ещё добавить прикольный звук "тррррр" при рубке леса заметил что его нет ;)
Навигация
Перейти к полной версии