我正在制作一个游戏,并重新绘制游戏场,难道Console.Write()不是很好吗?我可以在不让它看起来“滞后”的情况下更快地重写整个字段吗?游戏场中几乎所有的东西都在移动,但是只有在与0不同的元素上才有对象。(您可以检查这里的完整代码,http://pastebin.com/TkPd37xD,看看我在说什么,如果我的描述不够)
for (int Y = 0; Y < playfield.GetLength(0); Y++)
{
for (int X = 0; X < playfield.GetLength(1); X++)
{
//destroying the row when it reaches the top
if (playfield[0, X] != 0)
{
for (int i = 0; i < playfield.GetLength(1); i++)
{
playfield[0, X] = 0;
Console.SetCursorPosition(X, 0);
Console.Write(" ");
}
}
if (playfield[Y, X] == 3)
{
playfield[Y - 1, X] = 3;
playfield[Y, X] = 0;
}
else if (playfield[Y, X] == 1)
{
Console.SetCursorPosition(X, Y - 1);
Console.Write("=");
playfield[Y - 1, X] = 1;
Console.SetCursorPosition(X, Y);
Console.Write(" ");
playfield[Y, X] = 0;
}
else if (playfield[Y, X] == 0)
{
Console.SetCursorPosition(X, Y);
Console.Write(" ");
}
}
}
发布于 2015-04-30 06:08:11
基本上有两种方法:渲染更少,渲染更快。
渲染更少通常更棘手,但也倾向于不那么密集。经典的例子是Carmack的热衷游戏-- PC机没有勇气一次改变整个屏幕,所以Carmack确保只有屏幕上真正改变的部分才能重新绘制。在您的例子中,这可以很简单,就像检查新屏幕与旧屏幕一样(当然,不使用Console
方法)--当然,这取决于您正在编写的游戏类型,这可以为您节省大量的工作。
渲染得更快通常更容易。在过去,通常的方法是直接访问输出缓冲区--而不是把游戏场放在单独的内存中,而是直接放在显卡中--当然,这样就可以根据需要重新绘制整个屏幕,因为否则你在CRT屏幕上就看不到太多了。该选项仍然可以作为向后兼容性进行访问,因此,如果您使用Turbo编写应用程序,您仍然可以使用它,但在C#中并不是那么容易访问。首先在StringBuilder
中呈现整个屏幕,然后在Console.Write
中同时呈现整个屏幕,有一个选项。它会更快一些,但它并不完全是恒星。char[]
将为您提供一个额外的性能点--您可以将您的运动场直接表示为char[][]
,然后不必每次更改时都重新创建StringBuilder
--您只需为每个运动场线路重新创建一次Console.Write
即可。
当然,您可以在更改发生时立即写出它们;根据您正在编写的游戏的不同,这可以从“小而好的结果”到“非常难且看起来不太好”。由于控制台的缓冲区可能大于窗口大小,您甚至可以将其绘制到缓冲区的一个隐藏部分,然后使用Console.MoveBufferArea
立即绘制整个更改--这通常称为“回退缓冲”。不过,我不确定它是否好看--现在的控制台窗口允许您在缓冲区中滚动,这对您的用例可能是有害的。
仍然有一些方法可以更快地访问控制台缓冲区,但在完全停留在.NET时却不是这样--您将需要使用P/调用。关于这个话题的一个很好的答案是在这里- How can I write fast colored output to Console?。在现代系统中,这几乎等同于一次使用后台缓冲区并“绘制”它--它非常快。再一次,你可以直接对你的游戏数据使用后台缓冲区--它在20-30年前就开始工作了,现在仍然有效;这是在使用有限的资源时的良好实践。你能不能写一个游戏,真正使用控制台文本缓冲区的一切,或至少几乎所有?玩这样的东西很有趣,你可以写很多这样的游戏,包括俄罗斯方块或者Lode。当然,这只会在Windows上工作,所以如果您想支持其他系统,就会遇到更棘手的问题。
最后,您可以编写自己的控制台(或者更好地使用已经编写和测试过的人)。这是一个很好的实践,如果您想要继续更大的挑战,随着时间的推移,它将允许您使用更强大的技术。典型的例子是像Dwarf堡垒这样的游戏--仍然是基于文本的,仍然是控制台的,但是实际上是用SDL这样的技术绘制的。这不仅大大加快了现代系统(因为你没有容易的方式来直接访问文本缓冲区),它还打开了选择,切换到图形平铺游戏相当容易。这是楼梯上的又一个踏脚石,用来冷却东西:)
发布于 2021-10-28 21:52:55
This incomplete answer to How can I write fast colored output to Console? (没有实现颜色)对于全窗口更新非常快,对于标准的120x30大小的System.Console
窗口,只需要0.8ms:
int cols = Console.WindowWidth, rows = Console.WindowHeight;
//some sample text
byte[] buffer = Enumerable.Repeat((byte)'=', cols * rows).ToArray();
//because output appends, ensure the window is reset
Console.SetCursorPosition(0, 0);
using (Stream stdout = Console.OpenStandardOutput(cols * rows)) {
stdout.Write(buffer, 0, buffer.Length);
}
下面是我1000次调用Write
的性能:
如果您愿意进行p调用,那么可以通过使用this other answer和WriteConsoleOutput
来实现颜色(如CharInfo
和WriteConsoleOutput
对相同问题的演示)。
这两种方法都适用于“反向缓冲”(即构建整个场景,然后显示它)。
更新:下面是我为处理颜色(also see)而提出的内容:
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
public struct CharUnion {
[FieldOffset(0)] public char UnicodeChar;
[FieldOffset(0)] public byte AsciiChar;
}
[StructLayout(LayoutKind.Explicit, CharSet=CharSet.Unicode)]
public struct CharInfo{
[FieldOffset(0)] public CharUnion Char;
[FieldOffset(2)] public ushort Attributes;
public ConsoleColor ForegroundColor => (ConsoleColor)((this.Attributes & 0x0F));
public ConsoleColor BackgroundColor => (ConsoleColor)((this.Attributes & 0xF0) >> 4)
public CharInfo(char character, ConsoleColor? foreground = null, ConsoleColor? background = null) {
this.Char = new CharUnion() { UnicodeChar = character };
this.Attributes = (ushort)((int)(foreground ?? 0) | (((ushort)(background ?? 0)) << 4));
}
public CharInfo(byte character, ConsoleColor? foreground = null, ConsoleColor? background = null) {
this.Char = new CharUnion() { AsciiChar = character };
this.Attributes = (ushort) ((int)(foreground ?? 0) | (((ushort)(background ?? 0)) << 4));
}
public static bool Equals(CharInfo first, CharInfo second) {
return first.Char.UnicodeChar == second.Char.UnicodeChar
&& first.Char.AsciiChar == second.Char.AsciiChar
&& first.Attributes == second.Attributes;
}
}
发布于 2015-04-30 04:31:36
另一种方法是使用链接https://msdn.microsoft.com/en-gb/library/windows/desktop/aa363362%28v=vs.85%29.aspx中指定的API调用。
[DllImport("kernel32.dll")]
static extern void OutputDebugString(string lpOutputString);
您还可以通过将for循环中的输出缓冲到StringBuilder中并在每个for循环之后输出,从而获得轻微的性能。这可能并不是必要的,这取决于您想要实现您的程序。
https://stackoverflow.com/questions/29920056
复制相似问题