2

過去の異変がここに!

私はコマンド プロンプト用の ASCII Pong ゲームを作成しており (はい、古い学校です)、ビデオ メモリに直接書き込んでいます (Add. 0xB8000000)。

私のコードは正常に動作し、コードは Turbo C++ V1.01 の下で正常にコンパイルされますが、アニメーションが遅れます... ちょっと待ってください。私の超高速ブースト ターボ Dell Core 2 Duo では、これは論理的に思えますが、キーボードのキーを押したままにすると、新しくコンパイルされた赤ちゃんのおしりのようにアニメーションがスムーズになります。

キーボード バッファーをオーバーロードしてコンピューターの速度を落としていたからかもしれないと思ったのですが (本当に? 来てください...)、すぐに頭を切り替えて、DJGPP と Tiny C Compiler をコンパイルして、結果が同じかどうかをテストしてみました。 . Tiny C Compiler では、「far」ポインター型をコンパイルできないことがわかりました...まだ混乱していましたが、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);
}
4

2 に答える 2

1

まず、コードで:

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は char ではなく である必要があります。

その他の提案:

vertexFrom本当に何もしません。

A = vertexFrom(B);

次のものに置き換えることができるはずです:

A = B;

演算子を含むマクロ定数は、括弧で囲む必要があります。

#define Foo x/2

次のようにする必要があります。

#define Foo (x/2)

の使用を囲むコードに関係なく、演算子の優先順位について心配する必要はありませんFoo

16 ビット x86 PC では、実際には切り替え可能な 4 つの表示領域があります。アニメーション用にそれらのうちの 2 つを交換できれば、アニメーションは瞬時に発生するように見えるはずです。それはダブルバッファリングと呼ばれます。現在の表示バッファーとして機能するバッファーが 1 つと、作業バッファーとして機能するバッファーが 1 つあります。次に、作業バッファーに満足したら (そして、特定の速度で画面を更新しようとしている場合は、適切なタイミングで)、それらを交換します。これを行う方法は覚えていませんが、詳細を見つけるのはそれほど難しくありません。初期バッファをそのままにして、終了時に元のバッファに戻すことをお勧めします。これにより、プログラムは開始時とほぼ同じ状態で画面を離れることができます。また、

そのルートに行きたくなく、変更するのが「X」だけである場合は、画面をクリアするのをやめて、「X」の最後の場所をクリアすることができます。

画面バッファは表示文字と属性の2バイト単位の配列になっていませんか?私はそう思うので、それを次の配列として表します。

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

これにより、オフセットに基づいて間違いを犯す可能性が低くなります。

また、おそらくバイトではなく16ビット値としてバッファに読み書きするでしょうが、これは大きな違いにはなりません。

于 2010-07-21T18:29:50.147 に答える
0

すぐにレンダリングされない理由がわかりました。作成したタイマーは問題ありません。問題は、実際の clock_t の精度が .054547XXX 程度しかないため、18 fps でしかレンダリングできなかったことです。これを修正する方法は、より正確な時計を使用することです...これはまったく別の話です

于 2010-07-24T11:51:43.883 に答える