Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Something faster than Console.Write()?

Tags:

c#

I am making a game and Redrawing the playfield isn't that nice with Console.Write() is there any way that I can rewrite the whole field faster without making it look "laggy"? Pretty much everything in the playfield is moving, but there are objects only at elements different than 0.. (You can check the full code here http://pastebin.com/TkPd37xD and see what I am talking about if my description is not enough)

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(" ");
        }
    }
}
like image 872
Darkbound Avatar asked Apr 28 '15 12:04

Darkbound


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.


2 Answers

There's basically two approaches: render less, and render faster.

Render less is usually more tricky, but also tends to be less intensive. The classic example would be Carmack's Keen games - the PC didn't have the guts to rerender the whole screen at once, so Carmack made sure only the parts of the screen that actually change get redrawn. In your case, this can be as simple as checking the new screen against the old screen (without using the Console methods, of course) - depending on the kind of game you're writing, this can save you a huge amount of work.

Render faster is usually easier. The usual approach in the olden days was to get direct access to the output buffer - instead of having the playfield in separate memory, you had it directly in the graphics card - which was quite capable of redrawing the entire screen as fast as needed, of course, since otherwise you wouldn't ever see much on your CRT screen. This option is still accessible as backward compatibility, so you can still use it if you code your application in, say, Turbo Pascal, but it's not really all that easily accessible in C#. There is an option in rendering the whole screen in a StringBuilder first, and then Console.Write that all at once. It's going to be quite a bit faster, but it's not exactly stellar. char[] will allow you an extra point of performance - you can represent your playfield directly as char[][] and then you don't have to recreate the StringBuilder every time you change something - you just have to Console.Write once for each playfield line.

And of course, you could simply write out the changes as soon as they occur; depending on the game you're writing, this can range all the way from "trivial with great results" to "pretty hard and not looking good". And since the buffer area of the console can be bigger than then window size, you could even draw it out to a hidden part of the buffer, and then use Console.MoveBufferArea to draw the whole change at once - this is usually called "backbuffering". I'm not sure if it will look good, though - the console window nowadays allows you to scroll in the buffer, which can be detriminal for your use case.

There's still ways to get much faster access to the console buffers, but not while staying fully in .NET - you'll need to use P/Invokes. A great answer on this topic is here - How can I write fast colored output to Console?. On modern systems, this is pretty much equivalent to using a back buffer and "drawing" it all at once - it's incredibly fast. And again, you can use the back buffer for your game data directly - it worked 20-30 years ago, and it still works today; it's good practice in playing around with limited resources. Can you write a game that only really uses the console text buffer for everything, or at least almost everything? It's pretty fun playing around with stuff like that; you can write a whole plethora of games like this, including games like Tetris or Lode Runner. Of course, this will only work on Windows, so if you want to support other systems, it's a lot trickier.

And finally, you can just write your own console (or better, use someone's already written and tested). It's a good practice if you want to go on to greater challenges over time, and it will allow you to play around with more powerful technologies over time. The typical example would be games like Dwarf Fortress - still text based, still console-like, but actually drawn graphically, using technologies like SDL. Not only is this vastly faster on modern systems (since you have no easy way to access the text buffers directly), it also opens up the option of changing over to graphical tiled game rather easily. It's yet another stepping stone on the stairway to cool stuff :))

like image 194
Luaan Avatar answered Oct 30 '22 16:10

Luaan


This incomplete answer to How can I write fast colored output to Console? (doesn't achieve color) is incredibly fast for full-window updates, taking only about 0.8ms for the standard 120x30 size of the System.Console window:

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);
}

Here is my performance from calling Write 1000 times:

enter image description here


If you are willing to do a p-invoke, colors can be achieved as demonstrated by this other answer to that same question by using CharInfo and WriteConsoleOutput.

Both of these methods are practical to use with "backbuffering" (i.e. build the entire scene then display it).


Update: Here is what I came up with for handling colors (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;
    }
}
like image 35
Elaskanator Avatar answered Oct 30 '22 17:10

Elaskanator