DOS ASCII Animation Lagging без постоянного ввода, скомпилированный Turbo C - PullRequest
2 голосов
/ 21 июля 2010

Вот странность из прошлого!

Я пишу игру ASCII Pong для командной строки (да да oldschool), и я пишу в видеопамять напрямую (Add. 0xB8000000), поэтому я знаю, что я рендеринг быстро (в отличие от gotoxy и затем рендеринг printf)

Мой код работает нормально, код прекрасно компилируется под Turbo C ++ V1.01, НО анимация запаздывает ... теперь держись, держись, есть кавает! Под моим суперскоростным турбонаддувом Dell Core 2 Duo это кажется логичным, однако, когда я держу клавишу на клавиатуре, анимация становится плавной, как дно недавно скомпилированного ребенка.

Я подумал, может быть, это потому, что я замедлял работу компьютера из-за перегрузки буфера клавиатуры (на самом деле, wtf? Давай ...), но затем я быстро сообразил и попытался скомпилировать для DJGPP и Tiny C Compiler, чтобы проверить, если результаты подобные. В Tiny C Compiler я обнаружил, что не могу скомпилировать «дальние» типы указателей ... я все еще не уверен в этом, но я смог скомпилировать для DJGPP, и анимация прошла гладко!

Я хочу скомпилировать это и заставить его работать на Turbo C ++, но эта проблема мучила меня в течение последних 3 дней, но не решила. Кто-нибудь знает, почему постоянные вызовы Turbo C ++ для моего метода рендеринга (код ниже) будут задерживаться в командной строке, а DJGPP - нет? Я не знаю, откомпилирован ли я как отладочный или нет, я даже не знаю, как проверить, так ли это. Я преобразовал код в ASM и увидел то, что выглядело для отладки данных в заголовке исходного кода, поэтому я не знаю ...

Любые комментарии и помощь будут с благодарностью!

Вот краткий пример того, с чем я столкнулся, его легко скомпилировать, поэтому, пожалуйста, проверьте его:

#include<stdio.h>
#include<conio.h>
#include<dos.h>
#include<time.h>

#define bX 80
#define bY 24
#define halfX bX/2
#define halfY bY/2
#define resolution bX*bY

#define LEFT 1
#define RIGHT 2

void GameLoop();
void render();
void clearBoard();
void printBoard();
void ballLogic();

typedef struct {
 int x, y;
}vertex;

vertex vertexWith(int x, int y) {
 vertex retVal;
 retVal.x = x;
 retVal.y = y;
 return retVal;
}

vertex vertexFrom(vertex from) {
 vertex retVal;
 retVal.x = from.x;
 retVal.y = from.y;
 return retVal;
}

int direction;

char far *Screen_base;
char *board;
vertex ballPos;

void main() {
 Screen_base = (char far*)0xB8000000;
 ballPos = vertexWith(halfX, halfY);
 direction = LEFT;
 board = (char *)malloc(resolution*sizeof(char));
 GameLoop();
}

void GameLoop() {
 char input;

 clrscr();
 clearBoard();
 do {
  if(kbhit())
   input = getch();
  render();
  ballLogic();

  delay(50);
 }while(input != 'p');
 clrscr();
}

void render() {
 clearBoard();

 board[ballPos.y*bX+ballPos.x] = 'X';

 printBoard();
}

void clearBoard() {
 int d;
 for(d=0;d<resolution;d++)
  board[d] = ' ';
}

void printBoard() {
 int d;

 char far *target = Screen_base+d;
 for(d=0;d<resolution;d++) {
  *target = board[d];
  *(target+1) = LIGHTGRAY;
  ++target;
  ++target;
 }
}

void ballLogic() {
 vertex newPos = vertexFrom(ballPos);

 if(direction == LEFT)
  newPos.x--;
 if(direction == RIGHT)
  newPos.x++;

 if(newPos.x == 0)
  direction = RIGHT;
 else if(newPos.x == bX)
  direction = LEFT;
 else
  ballPos = vertexFrom(newPos);
}

Ответы [ 2 ]

1 голос
/ 21 июля 2010

Сначала в коде:

void printBoard() {
 int d;

 char far *target = Screen_base+d;  // <-- right there
 for(d=0;d<resolution;d++) {

вы используете переменную d до ее инициализации.

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

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

Другие предложения:

vertexFrom на самом деле ничего не делает.

A = vertexFrom(B);

можно заменить на:

A = B;

Ваши макроконстанты, в которых есть операторы, должны иметь круглые скобки вокруг них.

#define Foo x/2

быть:

#define Foo (x/2)

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

Под 16-битными ПК с архитектурой x86 на самом деле есть 4 области отображенияэто может быть переключено между.Если вы можете поменять местами 2 из них для вашей анимации, и ваша анимация должна появиться мгновенно.Это называется двойной буферизацией.У вас есть один буфер, который действует как текущий буфер отображения, и тот, который является рабочим буфером.Затем, когда вы удовлетворены рабочим буфером (и настало время, если вы пытаетесь обновить экран с определенной скоростью), вы меняете их местами.Я не помню, как это сделать, но подробности не должно быть слишком сложно найти.Я бы посоветовал вам оставить исходный буфер в покое и восстановить его после выхода, чтобы программа покидала экран практически в том состоянии, в котором она была запущена. Кроме того, вы можете использовать другой буфер для хранения отладочного вывода изатем, если вы удерживаете клавишу пробела или что-то такое, что может отображаться в этом буфере.

Если вы не хотите идти по этому пути, и «X» - единственное, что меняется, тогда вы можете отказаться от очистки экрана ипросто очистите последнюю позицию 'X'.

Разве экранный буфер не является массивом из 2 байтовых единиц - один для отображаемого символа, а другой для атрибутов?Я так думаю, поэтому я бы представлял его в виде массива:

struct screen_unit {
    char ch;
    unsigned char attr;
}; /* or reverse those if I've got them backwards */

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

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

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

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

...