【问题标题】:Animated ASCII art flickering in cc中闪烁的动画ASCII艺术
【发布时间】:2021-12-04 07:39:19
【问题描述】:

我正在用 c (windows) 制作一个 ASCII 艺术游戏,但由于某种原因,当我玩它时,它总是以明显随机的间隔闪烁,而且大部分时间我什么都看不到。谁能解释为什么或如何解决它?

这是我的代码:

const int WIDTH = 20, HEIGTH = 5;
const int AREA = (WIDTH) * HEIGTH;
const int gl = HEIGTH - 2; //Ground level
const float delta = 0.1f; //Frame rate
char scr[AREA]; //String for displaying stuff

char input;
int posx = 10, posy = gl - 1; //Player position
int vel = 0; //player velocity

while(1)
{
   //TODO: player input

    for(i = 0; i < AREA; i++) //Rendering part
    {
        if(i % WIDTH == 0 && i != 0)
        {
            scr[i] = '\n';
            continue;
        }

        if(floor(i / WIDTH) >= gl) //i is on ground
        {
            scr[i] = '.';
            continue;
        }


        scr[i] = ' ';
    }
    
    //Set player position
    scr[posy * WIDTH + posx + 1] = '@';
    scr[(posy + 1) * WIDTH + posx + 1] = '@';


    system("cls");// Clear terminal
    printf(scr);// Print screen
    usleep(delta * 1000);//Sleep
}

输出:

          @
..........@........
...................►↓@

它可以工作,但它会闪烁......

【问题讨论】:

  • 如果您希望其他人能够重现您的问题,您可能需要考虑提供minimal reproducible example,其中包括函数main 和所有#include 指令。
  • 我猜用户将能够在scr 上写他的名字(或其他一些东西),所以请不要printf(scr); ,这是一种不好的做法,因为它不安全。用户可以使用"%n" 泄漏地址甚至写入他不应该写入的内存。我会使用puts 或者如果您坚持使用printf_s...
  • 您可以考虑使用Console Functions APIConsole Virtual Terminal Sequences,而不是使用system("cls");。请注意,后者需要最新的 Windows 10 或 11,它不适用于 Windows 7。
  • 或者另一种选择是终端功能库;在 Windows 上有 pdcurses。

标签: c windows ascii ascii-art


【解决方案1】:

问题的一个可能原因是,当您调用睡眠函数usleep 时,输出缓冲区中可能有输出等待。在这种情况下,您应该始终在睡眠前通过调用函数fflush( stdout ); 刷新所有输出。

另外,使用system("cls"); 效率非常低。通常最好使用Console Functions API,或者,如果您的目标平台是Windows 10 或更高版本,您也可以使用Console Virtual Terminal Sequences

如果您决定使用控制台函数 API,那么您将需要用于替换 system("cls"); 的主要函数是 GetStdHandle 以获取输出句柄,以及 SetConsoleCursorPosition。这样,您不必清除整个屏幕,而只需覆盖正在更改的屏幕部分。我还建议您将printf 替换为WriteConsole,否则您可能会遇到缓冲问题。

如果这不能解决您的闪烁问题,那么也有可能使用double-bufferingConsole Functions APIConsole Virtual Terminal Sequences 都支持这一点。

在使用控制台函数 API 时,您可以使用函数 CreateConsoleScreenBuffer 创建一个新的缓冲区来写入,而不会立即显示。这将允许您首先完成下一个屏幕的构建,而在此过程中不会发生任何闪烁(因为它尚未显示)。构建完下一个屏幕后,您可以使用函数SetConsoleActiveScreenBuffer 显示它。

控制台虚拟终端序列通过支持alternate screen buffer 提供类似的功能。

【讨论】:

    猜你喜欢
    • 2018-11-06
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-27
    • 2010-12-14
    • 1970-01-01
    相关资源
    最近更新 更多