我尝试使用 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 上的字符值。
嗯,我做了一个游戏。它基本上是这样工作的。每半秒它进入我的 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 上的字符值。