我尝试使用 ascii 字符制作游戏,但它闪烁太多

I tried making game using ascii characters but its flashing too much

嗯,我做了一个游戏。它基本上是这样工作的。每半秒它进入我的 if 条件进行必要的计算,然后将所有内容打印到控制台。这是我的游戏循环。

//game loop
    while(!IsGameOver)
    {
        // Updates every half a second
        if ((int)(ElapsedTime / 500) > PreviousRoundQSec)
        {
            PreviousRoundQSec = (int)(ElapsedTime / 500);

            BulletCalculation(bullets);
            RemoveBulletsOutsideOfTheBoard(bullets, BoardLength);
            HealthCalculation(SpaceShips, bullets);
            RemoveDead(SpaceShips, bullets);
            DrawGame(BoardWidth, BoardLength, SpaceShips, bullets);
        }
        
        // Updates EverySecond
        if ((int)(ElapsedTime / 1000) > PreviousRoundSec)
        {
            PreviousRoundSec = (int)(ElapsedTime / 1000);


            PreDir = HordLogic(SpaceShips, bullets,BoardWidth, BoardLength, PreDir, PreNearBorder);
            
        }

        IsGameOver = GameOver(SpaceShips);

        // To keep time
        auto end = chrono::steady_clock::now();
        ElapsedTime = chrono::duration_cast<chrono::milliseconds>(end - start).count();
    }

起初我尝试cout计算每个字符。但是它的打印效果很差,你可以看到每个字符都是单独打印的。那确实很糟糕。在互联网上进行一些搜索后,我发现 printf func 速度更快,但也没有真正帮助我。我最后的想法是将每个字符添加到字符串中并立即打印该字符串。这是最好的解决方案,但还不够,因为您可以看到游戏在闪烁,这让一切变得复杂。

这是我的绘图功能的最新版本。

void DrawGame(int BoardWidth, int BoardLength, vector<Entity*> &SpaceShips, vector<Bullet> &bullets)
{
    system("cls");

    string screen = "";
    for (int x = 0; x < BoardWidth + 2; x++)
    {
        screen += (char)178;
    }
    screen += "\n";
    for (int y = 1; y < BoardLength + 1; y++)
    {
        for (int x = 0; x < BoardWidth + 2; x++)
        {
            if (x == 0 || x == BoardWidth + 1)
            {
                screen += (char)178;
            }
            else
            {
                bool enteredIf = false;
                for (int i = 0; i < SpaceShips.size(); i++)
                {

                    // Tough Enemy drawing
                    if (SpaceShips[i]->x == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 't')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 1 == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 't')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 2 == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 't')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 't')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 2 == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 't')
                    {
                        screen += "#";
                        enteredIf = true;
                    }

                    //Idle Enemy drawing
                    if (SpaceShips[i]->x == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 'i')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 1 == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 'i')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 2 == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 'i')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 1 == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 'i')
                    {
                        screen += "U";
                        enteredIf = true;
                    }
                    
                    //Shooting Enemy Drawing
                    if (SpaceShips[i]->x == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 's')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 1 == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 's')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 2 == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 's')
                    {
                        screen += "#";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 2 == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 's')
                    {
                        screen += "/";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 's')
                    {
                        screen += "\";
                        enteredIf = true;
                    }

                    //Player Drawing
                    if (SpaceShips[i]->x + 1 == x && SpaceShips[i]->y == y && SpaceShips[i]->type == 'p')
                    {
                        screen += "^";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 'p')
                    {
                        screen += "<";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 1 == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 'p')
                    {
                        screen += "_";
                        enteredIf = true;
                    }
                    else if (SpaceShips[i]->x + 2 == x && SpaceShips[i]->y + 1 == y && SpaceShips[i]->type == 'p')
                    {
                        screen += ">";
                        enteredIf = true;
                    }
                }
                if (!enteredIf)
                {
                    screen += " ";
                }
            }
        }
        screen += "\n";
    }
    for (int x = 0; x < BoardWidth + 2; x++)
    {
        screen += (char)178;
    }

    // draw bullets
    for (int i = 0; i < bullets.size(); i++)
    {
        if (bullets[i].GetDir() == 's')
        {
            screen.at(((bullets[i].y * (BoardWidth + 3)) - 1) + (bullets[i].x + 1)) = (char)203;
        }
        else if (bullets[i].GetDir() == 'w')
        {
            screen.at(((bullets[i].y* (BoardWidth + 3)) - 1) + (bullets[i].x + 1)) = (char)202;
        }
    }

    screen += "\n Remaining lives: ";
    screen += itoa(SpaceShips[0]->hp);

    cout << screen;
}

这是游戏的样子(我没有看到任何禁止共享链接的规则。如果有的话欢迎任何警告):https://www.loom.com/share/1bcc97fa0cbe4ee3aec62e317b10fcd0

问题可能与您使用的 std::cout 有关。标准输出流与终端交互的方式是连续的行序列,随着新行的添加自然向上滚动。您需要与终端进行较低级别的交互,以便更好地控制其行为。

其中一个选项是将 ncurses library for Unix systems (or PDCurses 用于 Windows command-line)

这将允许您使用“固定”终端 window,并设置固定 window 上的字符值。