У меня просто несколько комментариев.Во-первых, у вас недостаточно комментариев.Есть места, где неясно, что вы пытаетесь сделать, поэтому трудно сказать, есть ли лучший способ сделать это, но я укажу на них, когда приду к ним.Во-первых, хотя:
#define MSECS_PER_STEP 20
int stepCount, stepSize; // these are not globals in the real source
void loop() {
int i,j;
int iterations =0;
static int accumulator; // the accumulator holds extra msecs
static int lastMsec;
Они ни к чему не инициализированы.Вероятно, получится 0, но вы должны были их инициализировать.Кроме того, вместо того, чтобы объявлять их как статические, вы можете рассмотреть возможность размещения их в структуре, которую вы передаете в loop
по ссылке.
int deltatime = msec() - lastMsec;
Поскольку lastMsec
не было (инициализировано и, вероятно, равно 0) это, вероятно, начинается как большая дельта.
lastMsec = msec();
Эта строка, как и последняя строка, вызывает msec
.Это, вероятно, подразумевается как «текущее время», и эти вызовы достаточно близки, чтобы возвращаемое значение, вероятно, было одинаковым для обоих вызовов, что, вероятно, также то, что вы ожидали, но, тем не менее, вы вызываете функцию дважды.Вы должны изменить эти строки на int now = msec();
int deltatime = now - lastMsec;
lastMsec = now;
, чтобы избежать вызова этой функции дважды.В настоящее время получение функций часто имеет гораздо больше накладных расходов, чем вы думаете.
if (deltatime != 0) {
iterations = deltatime/MSECS_PER_STEP;
accumulator += deltatime%MSECS_PER_STEP;
}
У вас должен быть здесь комментарий, в котором говорится, что это делает, а также комментарий выше, в котором говорится, что переменные должны были означать.
while (accumulator >= MSECS_PER_STEP) {
iterations++;
accumulator -= MSECS_PER_STEP;
}
Этот цикл нуждается в комментарии.Это также должно быть не там.Похоже, что он мог быть заменен на iterations += accumulator/MSECS_PER_STEP;
accumulator %= MSECS_PER_STEP;
.Деление и модуль должны выполняться за более короткое и более согласованное время, чем цикл на любой машине с аппаратным разделением (что делают многие).
handleInput(); // gathers user input from an event queue
for (j=0; j<iterations; j++) {
for (i=0; i<stepCount; i++) {
doStep(stepSize/(float) stepCount); // forwards the sim
}
}
Выполнение шагов в цикле, независимом отВ результате ввода игра перестает отвечать на запросы, если она выполняется медленно и отстает.По крайней мере, кажется, что, если игра отстает, все входные данные начнут складываться и выполняться вместе, и все игровое время пройдет в одном блоке.Это менее чем изящный способ потерпеть неудачу.
Кроме того, я могу догадаться, что означает петля j
(внешняя петля), но о внутренней петле я менее ясна.также значение, переданное функции doStep
- что это значит.
}
Это последняя фигурная скобка.Я думаю, что это выглядит одиноко.
Я не знаю, что происходит, если что-либо вызывает вашу функцию loop
, которая может быть вне вашего контроля, и это может диктовать, что эта функция делает и какэто выглядит, но если нет, я надеюсь, что вы пересмотрите структуру.Я полагаю, что лучшим способом сделать это было бы использование функции, которая вызывается неоднократно, но с одним событием за раз (выпускается регулярно за относительно короткий период).Эти события могут быть событиями пользовательского ввода или событиями таймера.События пользовательского ввода просто настраивают реакцию на следующее событие таймера.(когда у вас нет событий для обработки, вы спите)
Вы должны всегда предполагать, что каждое событие таймера обрабатывается в один и тот же период, даже если здесь может быть некоторое отклонение, если обработка отстает.Главная странность, которую вы можете заметить здесь, заключается в том, что если игра отстает в обработке событий таймера, а затем снова догоняет время в игре, может появиться замедление (ниже реального времени), затем ускорение (до реального времени)затем замедлите (до реального времени).
Способы решения этой проблемы включают в себя только разрешение одного события таймера одновременно находиться в очереди событий, что приведет к замедлению времени (ниже реального времени).), а затем ускориться (до реального времени) без интервала суперскорости.
Еще один способ сделать это, который функционально аналогичен тому, что у вас есть, состоит в том, чтобы последний шаг обработки каждого события таймера заключался в постановке в очередь следующего события таймера (обратите внимание, что никто другой не должен отправлять события таймера {кроме для первого}, если вы решили реализовать игру). Это будет означать отказ от регулярных интервалов времени между событиями таймера, а также ограничение возможности для программы спать, поскольку, по крайней мере, каждый раз при проверке очереди событий будет происходить событие таймера для обработки.