Как сохранить правильный фон в графической системе с символьной графикой?

Я почувствовал себя ретро и решил написать свою любимую 8-битную компьютерную игру (Williams' Defender) на своем первом компьютере (Commodore PET 4032). Весь код выполняется на языке ассемблера 6502. Для тех, кто не знаком с PET, вся графика основана на персонажах, и для создания игр вы перемещаете разных персонажей по экрану размером 40 столбцов x 25 строк. Это очень старая технология — здесь нет ни спрайтов, ни графических слоев, ни возможности И на уровне экрана и т. д., к которым мы привыкли бы сегодня.

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

Существует ли классический «легкий» алгоритм или набор правил, который позволяет нескольким объектам перемещаться друг относительно друга так, чтобы исходные правильные вещи под ними сохранялись? Я пробовал разные подходы (замена фона по мере прохождения и т. д.), но, похоже, ничто не дает мне правильного результата, который я хочу.


person Jim    schedule 02.01.2020    source источник
comment
Возможно, вам повезет больше спросить на gaming.stackexchange. Вопросы для рекомендаций для программных библиотек обычно не разрешены в stackoverflow (я полагаю, отчасти потому, что они меняются так быстро по мере технического прогресса и создают основанные на мнениях разговоры), пожалуйста, предоставьте минимальный воспроизводимый пример и перепроверьте Как спросить   -  person admcfajn    schedule 02.01.2020
comment
Если вы всегда отрисовываете и отрисовываете все объекты в правильном порядке, ваш подход будет работать. Многие игры делают это. Другой часто используемый метод заключался в XOR (исключающее ИЛИ) объектов на экране и XOR их снова, чтобы отменить отрисовку, но это может не сработать в зависимости от вашего разрешения и цветового сопоставления — это лучше всего подходит для черно-белого. В противном случае другое предложение Томми о перерисовке фона было бы стандартным подходом.   -  person Nick Westgate    schedule 03.01.2020


Ответы (3)


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

Вы также можете использовать буфер размером с экран с флагами «фон» и «спрайт». Каждый раз, когда рисуется спрайт, помечайте расположение его символов как «это спрайт». Чтобы стереть все спрайты, выполните итерацию по буферу размером с экран, перерисовывая фон везде, где нет пометки «является фоном». Вы можете сохранить верхнюю и нижнюю границы обновленных позиций, если повторение всех 2000 потенциальных слотов слишком дорого.

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

person Tommy    schedule 02.01.2020
comment
Спасибо, Томми. Именно такие идеи я искал. У меня должно быть достаточно циклов, чтобы работать с тем, что в вашем первом абзаце. - person Jim; 03.01.2020

Я бы предложил:

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

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

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

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

person Matt Timmermans    schedule 05.01.2020

Никогда не программируя для питомца, я не могу дать каких-либо конкретных советов о том, что вы можете попробовать, но я могу порекомендовать хранить копию текущего фонового изображения на экране примерно в 1 КБ ОЗУ. Таким образом, вы можете использовать эти данные для восстановления фона при удалении последнего «спрайта», записанного на эту плитку. К сожалению, это также требует, чтобы ваш код и данные объекта были объединены в пределах 31 КБ, если только вы не программируете это как картридж. Всего несколько мыслей, чего они стоят.

person G David    schedule 18.01.2020