我试图只使用控制台图形制作一款简单的游戏,但由于某种原因,即使我使用putc()
而不是printf()
,平均14 FPS的速度仍然非常慢,尽管我所做的只是显示一堆@sighns。
代码:
#include <stdio.h>
#include <time.h>
#include <windows.h>
const int sizeX = 20;
const int sizeY = 20;
int grid[20][20];
void draw_screen() {
system("cls");
int y, x;
for (y = 0; y < sizeY; y++) {
for (x = 0; x < sizeX; x++) {
if (grid[y][x] == 0) {
putc('@', stdout);
}
}
putc('n', stdout);
}
}
int main(void) {
int x, y;
float frameTime, FPS;
while (1) {
clock_t start = clock();
draw_screen();
clock_t stop = clock();
frameTime = (float)(stop - start) / CLOCKS_PER_SEC;
FPS = 1.0 / frameTime;
printf("FPS: %fn", FPS);
}
}
有两个技巧可以快速生成控制台图形。首先,不要在每一帧都清理屏幕,只需将光标移动到左上角(使用SetConsoleCursorPosition(。其次,不要一个字符一个字符地打印,一行一行地打印(你甚至可以一帧一帧地打印(。请参阅下面的代码。更改"睡眠"中的值以获得合理的帧速率。
#include <stdio.h>
#include <time.h>
#include <windows.h>
#define SIZE_X 75
#define SIZE_Y 25
int grid[SIZE_X][SIZE_Y];
void draw_screen() {
static const HANDLE std_handle = GetStdHandle(STD_OUTPUT_HANDLE);
static const COORD top_left = {0, 0};
SetConsoleCursorPosition(std_handle, top_left);
char line[SIZE_X + 1];
line[SIZE_X] = ' ';
int y,x;
for(y=0;y<SIZE_Y;y++){
for(x=0;x<SIZE_X;x++){
line[x] = (grid[y][x] == 0) ? '@' : ' ';
}
puts(line);
}
// Use Sleep to control frame rate, comment to get maximum frame rate
// Sleep(33);
}
int main(void){
int t,y,x;
float frameTime, FPS;
t = 0;
while(1){
// Simple grid update every frame
for(y=0;y<SIZE_Y;y++){
for(x=0;x<SIZE_X;x++){
grid[y][x] = (t + 11*x + 7*y) & 1;
}
}
++t;
clock_t start = clock();
draw_screen();
clock_t stop = clock();
frameTime = (float)(stop - start) / CLOCKS_PER_SEC;
FPS = 1.0 / frameTime;
printf("FPS: %fn",FPS);
}
}
问题似乎是SetConsoleTextAttribute((。它可能不是为了经常被称为。这个问题也抱怨它的速度。有关更快的彩色控制台输出,请参阅此问题(涉及WriteConsoleOutput((函数(
下面列出的每一个调用都需要上下文切换到内核模式。这涉及到放弃在运行队列中的位置,直到系统调用后下一次将其放入运行队列。
为了提高性能,您将希望尽可能避免上下文切换。我会记下每一个电话都涉及到什么:
- 系统("cls"(
这将强制Windows复制整个进程,该进程的所有内存都将被复制。完成后,这两个过程将使用不同的叉子。家长继续运行游戏。子级加载并运行cls
。一旦完成,控制权将返回给父级 - putc('@',stdout(;这只向内核空间发送一个字节。您希望为每个电话尽可能多地写信。理想情况下,以每秒一百次或稍多次的方式批量发出这些调用,每次调用数百或数千字节
- clock_t start=clock((
此调用从内核获取时间。在所有的电话中,这是延迟成本最低的 - printf("FPS:%f\n",FPS(
这可能很昂贵,因为printf()
有很多选项 - GetStdHandle(STD_OUTPUT_HANDLE(;此调用需要输入和输出设备的句柄信息。延迟并不那么昂贵
- SetConsoleCursorPosition(std_handle,top_left(
这可能很贵,通常不会在一秒钟内使用多次