ASCII DOS Games - Методы рендеринга - PullRequest
8 голосов
/ 22 июля 2010

Я пишу ASCII DOS-Prompt для старой школы. Честно говоря, я пытаюсь подражать ZZT, чтобы узнать больше об этом бренде игрового дизайна (даже если он устарел)

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

Я знаю, что мой код рендеринга и предварительного рендеринга работает быстро, потому что, если я не добавлю никаких проверок delay () s или (clock () - renderBegin) / CLK_TCK из time.h, рендеринг будет невероятно быстрым.

Я не хочу использовать delay (), потому что это связано с моей платформой знаний и, кроме того, я не могу запускать какой-либо код, пока он задерживается (например, пользовательский ввод и обработка). Поэтому я решил сделать что-то вроде этого:

do {
    if(kbhit()) {
        input = getch();
        processInput(input);
    }

    if(clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval) {
        renderTimer = clock();
        render();
        ballLogic();
    }
}while(input != 'p');

Что должно в "теории" работать нормально. Проблема в том, что когда я запускаю этот код (устанавливая RenderInterval в 0.0333 или 30 кадров в секунду), я не получаю НИКОГДА близко к 30 кадрам в секунду, я получаю больше как 18 при макс.

Я подумал, что, возможно, я попытаюсь установить RenderInterval в 0.0, чтобы увидеть, повысилась ли производительность ... это не так. Я получал (с RenderInterval 0,0) максимальную скорость ~ 18-20 кадров в секунду.

Хотя, может быть, так как я постоянно вызываю все эти методы clock () и "делю это на то", я замедлял процессор до чего-то пугающего, но когда я взял вызовы render и ballLogic из скобок оператора if и установив RenderInterval в 0.0, я снова получаю невероятно быстрые рендеры.

Это не имеет смысла для меня, так как, если я оставлю регистрацию if, разве она не будет работать так же медленно? Я имею в виду, что он все еще должен делать все расчеты

Кстати, я собираю с Turland C ++ V1.01 Borland

Ответы [ 5 ]

2 голосов
/ 05 сентября 2010

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

В текстовом режиме 80x25 происходит вертикальный возврат (на VGA)70 раз / секунду.Я не помню, была ли частота одинаковой на EGA / CGA, но я почти уверен, что она была 50 Гц на Hercules и MDA.Измеряя продолжительность, скажем, 20 кадров, вы должны иметь достаточно точную оценку частоты, с которой вы имеете дело.

Пусть основной цикл будет выглядеть примерно так:

  while (playing) {
     do whatever needs to be done for this particular frame
     VSync();
  }

  ...  /* snip */

  /* Wait for vertical retrace */
  void VSync() {
    while((inp(0x3DA) & 0x08));
    while(!(inp(0x3DA) & 0x08));
  }
1 голос
/ 24 июля 2010

Я понял, почему он не рендерился сразу, таймер, который я создал, в порядке, проблема в том, что фактический clock_t точен только до .054547XXX или около того, и поэтому я мог рендерить только с 18fps. Я бы исправил это, используя более точные часы ... это совсем другая история

1 голос
/ 22 июля 2010
clock()-renderTimer > RenderInterval * CLOCKS_PER_SEC

будет вычисляться немного быстрее, возможно, даже быстрее, если вы предварительно вычислите часть RenderInterval * CLOCKS_PER_SEC.

0 голосов
/ 23 июля 2010

Как вы заметили в своем последнем вопросе, вы ограничены CLOCKS_PER_SEC, который составляет всего около 18. Вы получаете один кадр на дискретное значение тактового сигнала, поэтому вы ограничены 18 кадрами в секунду.

Вы можете использовать интервал вертикального гашения экрана для синхронизации, это традиционно для игр, так как позволяет избежать «разрыва» (когда половина экрана показывает один кадр, а половина показывает другой)

0 голосов
/ 22 июля 2010

Как насчет этого: вы вычитаете из x (= clock ()) y (= renderTimer).И x, и y делятся на CLOCKS_PER_SEC:

clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval

Не будет ли лучше написать:

( clock() - renderTimer ) > RenderInterval

Самая первая проблема, с которой я столкнулся при делениимы не собираемся получать от него действительное число, поскольку это происходит между двумя длинными целыми числами.Вторая проблема заключается в том, что более эффективно умножать RenderInterval * CLOCKS_PER_SEC и таким образом избавляться от него, упрощая операцию.

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

...