Why is system.console so slow?

N

Nik Coughlin

System.Console is really slow. I wanted to make a retro text-only console
application game (a roguelike), but I can't get decent performance out of
it. Does anyone know how to get decent performance out of it? Is there
some way of buffering the text before outputting it? Here's my test code
(slow!):

Random r = new Random();

Console.Clear( );

while ( true ) {
for ( int y = 0; y < 20; y++ ) {
for ( int x = 0; x < 70; x++ ) {
Console.SetCursorPosition( x, y );
Console.ForegroundColor = (ConsoleColor) r.Next( 16 );
Console.Write( 'x' );
}
}
}

The only way I could get it to run at a decent speed was by using
Console.WriteLine on each row, but that means I can't set the color for
individual characters.

As an aside note, I fired up the oldest programming IDE I could find
(QuickBasic 4.5, ah the nostalgia) and tried this:

CLS

DO
FOR y% = 1 TO 20
FOR x% = 1 TO 70
LOCATE y%, x%
COLOR INT(RND * 16)
PRINT "x"
NEXT x%
NEXT y%
LOOP

It was blazingly fast. Surely a modern framework like .Net can do fast
console drawing, I must be missing something.

Please tell me I don't have to use the Win32 API :) I'm aiming to have it
work in Mono too, so I want to stay in managed code.
 
J

Jon Skeet [C# MVP]

Nik Coughlin said:
System.Console is really slow. I wanted to make a retro text-only console
application game (a roguelike), but I can't get decent performance out of
it. Does anyone know how to get decent performance out of it? Is there
some way of buffering the text before outputting it? Here's my test code
(slow!):

Random r = new Random();

Console.Clear( );

while ( true ) {
for ( int y = 0; y < 20; y++ ) {
for ( int x = 0; x < 70; x++ ) {
Console.SetCursorPosition( x, y );
Console.ForegroundColor = (ConsoleColor) r.Next( 16 );
Console.Write( 'x' );
}
}
}

The only way I could get it to run at a decent speed was by using
Console.WriteLine on each row, but that means I can't set the color for
individual characters.

It's a lot smoother (on my box at least) if you only set the cursor
position at the start of the line, then do Console.Write 70 times.

From what I remember of rogue and the like, you don't need to redraw
the whole screen very often - I wouldn't have thought it would be a
problem.
 
N

Nik Coughlin

Jon said:
It's a lot smoother (on my box at least) if you only set the cursor
position at the start of the line, then do Console.Write 70 times.

Yep, it's smoother but still nowhere near the performace of, well, doing it
any other way I've tried :) SetCursorPosition and ForegroundColor seem to
be very slow.
From what I remember of rogue and the like, you don't need to redraw
the whole screen very often - I wouldn't have thought it would be a
problem.

In traditional roguelikes the maps fit into one screen and the player moves
around the screen, so you're right, but I'm trying to have large, scrolling
maps. I could do it in something else to get the speed, but damn it, .Net
should be able to do it and I'm stubborn :p
 
?

=?ISO-8859-1?Q?Lasse_V=E5gs=E6ther_Karlsen?=

Nik said:
System.Console is really slow. I wanted to make a retro text-only console
application game (a roguelike), but I can't get decent performance out of
it. Does anyone know how to get decent performance out of it? Is there
some way of buffering the text before outputting it? Here's my test code
(slow!):

Random r = new Random();

Console.Clear( );

while ( true ) {
for ( int y = 0; y < 20; y++ ) {
for ( int x = 0; x < 70; x++ ) {
Console.SetCursorPosition( x, y );
Console.ForegroundColor = (ConsoleColor) r.Next( 16 );
Console.Write( 'x' );
}
}
}

The only way I could get it to run at a decent speed was by using
Console.WriteLine on each row, but that means I can't set the color for
individual characters.

As an aside note, I fired up the oldest programming IDE I could find
(QuickBasic 4.5, ah the nostalgia) and tried this:

CLS

DO
FOR y% = 1 TO 20
FOR x% = 1 TO 70
LOCATE y%, x%
COLOR INT(RND * 16)
PRINT "x"
NEXT x%
NEXT y%
LOOP

It was blazingly fast. Surely a modern framework like .Net can do fast
console drawing, I must be missing something.

Please tell me I don't have to use the Win32 API :) I'm aiming to have it
work in Mono too, so I want to stay in managed code.

Try to do minimal updates. Try making a off-screen copy of the map and
update this, keeping track og what portions are visible. Then, when you
need to update the screen, compare what you had on the screen previously
with what you need to have there now, and only update the portions that
have changed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top