如何在不创建新行的情况下更新 Console.WriteLine 中的循环结果?

How to update for loop result in Console.WriteLine without creating new line?

此代码显示如下结果:

distance from target : 10
distance from target : 9
distance from target : 8
(line by line)

我想显示结果 - 与目标的距离:10,然后 9,8,7 替换 10 的位置,(只有 10 的位置会更新)

public void Attack()
{
    for (int i = 1; i < 3; i++)
    {
        if (i == 1)
        {
            Console.WriteLine("Target Locked (+)");
            Thread.Sleep(2000);
        }
        if (i == 2)
        {
            Console.WriteLine("Fired!");
            Thread.Sleep(1000);
        }
    }
    Random random = new Random();
    int distance = random.Next(100, 3000);
    for (int i = distance; i > 0; i = i - 3)
    {
        Console.WriteLine("distance from target : " + i);
        Thread.Sleep(30);
        //Console.Clear();
    }
    Console.WriteLine("BloooW!");
}

那么你应该先删除写入控制台的距离,可以用一个或多个退格键来完成\b

改变

for (int i = distance; i > 0; i = i - 3)
            {
                Console.WriteLine("distance from target : " + i);
                Thread.Sleep(30);
                //Console.Clear();
            }

int lastDistanceLength = 0; // save the last number of distance chars written

for (int i = distance; i > 0; i = i - 3)
{
   if(lastDistanceLength == 0) { // no distance chars written yet.
       Console.Write("distance from target : " + i);
    } 
    else  { 
       for(int j=0;j‹lastDistanceLength;j++)
          Console.Write("\b"); // delete old distance
       Console.Write(""+i);

    }
    lastDistanceLength = i==10 ? 2 : 1;           
    Thread.Sleep(30);
    //Console.Clear();
}
Console.WriteLine("\r\nBloooW!");

您很可能需要更高级的算法来计算 lastDistanceLength,也许只需将 i 转换为字符串并获取长度,例如lastDistanceLength = (""+i).Length

这里有一个比较全面的解释:Is there a way to delete a character that has just been written using Console.WriteLine?

您可以像这样使用 Console.CursorTop :

for (int i = distance; i > 0; i = i - 3)
{
    Console.WriteLine("distance from target : " + i + "    "); // dirty trick to erase longer previous numbers
    Thread.Sleep(30);
    Console.CursorTop--;
}
Console.CursorTop++; // so that we advance to the next line after the loop.

它将光标向上移动一行,因此后续调用会覆盖之前在上面一行中的内容。

这种方法不是最有效的方法,因为它会重写整行,但它很简单,而且从用户的角度来看,只会更新数值。

如果如此小的性能差异很重要,您可以尝试将光标位置更精确地设置为数值开始的位置。我不确定是否可行,但如果重要的话值得一试。

您可以将 Console.WriteLine 更改为 Console.Write 在字符串的前面添加一个 \r

        for (int i = distance; i > 0; i = i - 3)
        {
            Console.Write("\rdistance from target : " + i);
            Thread.Sleep(30);
            //Console.Clear();
        }
        Console.WriteLine("");

这将导致控制台 return 到行的开头并再次写入字符串以覆盖上次写入时的字符串。还要确保在 for 循环之后添加一个 Console.WriteLine(""); 以移动到下一行,这样您的下一次写入就不会从该行开始。

如果您的字符串只会变得更长,则此解决方案最有效。

如果您的字符串要变短,您可以在字符串末尾添加一些白色 space,如下所示:

 Console.Write("\rdistance from target : {0} ", i);

当你从 109

时,你就是这种情况

您可以使用 CursorTop、CursorLeft 和 SetCursorPosition 来精确控制写入输出的位置。但真正的诀窍是删除你以前在那个地方写的东西。在这里您可以使用控制台的格式字符串功能。Write/WriteLine

    // This needs to be written just one time
    Console.Write("distance from target : ");
    // Now get the current cursor position after the write above
    int posX = Console.CursorLeft;
    int posY = Console.CursorTop;


    for (int i = distance; i > 0; i = i - 3)
    {
        // Position the cursor where needed
        Console.SetCursorPosition(posX, posY);

        // Replace the previous write with a number aligned on the left on 4 spaces
        Console.Write($"{i,-4:D}");
        // As an alternative to SetCursorPosition you could have
        // Console.CursorLeft -= 4;
        // but, to me this is less clear....

        Thread.Sleep(30);
    }
    // Do not forget to jump to the next line
    Console.WriteLine("\r\nBloooW!");