1

私は ac# コンソール テトリス ゲームを書いています。アプリケーションの準備ができたという部分に到達したら。遅れを解決しなければならない部分にたどり着きました。私は次のように書いています。

static void writeCol(string a, ConsoleColor b)
        {
            ConsoleColor c = Console.ForegroundColor;
            Console.ForegroundColor = b;
            Console.Write(a);
            Console.ForegroundColor = c;
        }

だから、新しいブロックが来たら/私は何かを動かしたい:

writeCol(blokk, ConsoleColor.Magenta);

ブロックの場所:

private const string blokk = "█";

コンソールへの「書き込み」を高速化する方法を見つけました。

using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace ConsoleApplication1
{
  class Program
  {

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern SafeFileHandle CreateFile(
        string fileName,
        [MarshalAs(UnmanagedType.U4)] uint fileAccess,
        [MarshalAs(UnmanagedType.U4)] uint fileShare,
        IntPtr securityAttributes,
        [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
        [MarshalAs(UnmanagedType.U4)] int flags,
        IntPtr template);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool WriteConsoleOutput(
      SafeFileHandle hConsoleOutput, 
      CharInfo[] lpBuffer, 
      Coord dwBufferSize, 
      Coord dwBufferCoord, 
      ref SmallRect lpWriteRegion);

    [StructLayout(LayoutKind.Sequential)]
    public struct Coord
    {
      public short X;
      public short Y;

      public Coord(short X, short Y)
      {
        this.X = X;
        this.Y = Y;
      }
    };

    [StructLayout(LayoutKind.Explicit)]
    public struct CharUnion
    {
      [FieldOffset(0)] public char UnicodeChar;
      [FieldOffset(0)] public byte AsciiChar;
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct CharInfo
    {
      [FieldOffset(0)] public CharUnion Char;
      [FieldOffset(2)] public short Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SmallRect
    {
      public short Left;
      public short Top;
      public short Right;
      public short Bottom;
    }


    [STAThread]
    static void Main(string[] args)
    {
      SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);

      if (!h.IsInvalid)
      {
        CharInfo[] buf = new CharInfo[80 * 25];
        SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = 80, Bottom = 25 };

        for (byte character = 65; character < 65 + 26; ++character)
        {
          for (short attribute = 0; attribute < 15; ++attribute)
          {
            for (int i = 0; i < buf.Length; ++i)
            {
              buf[i].Attributes = attribute;
              buf[i].Char.AsciiChar = character;
            }

            bool b = WriteConsoleOutput(h, buf,
              new Coord() { X = 80, Y = 25 },
              new Coord() { X = 0, Y = 0 },
              ref rect);
          }
        }
      }
      Console.ReadKey();
    }
  }
}

(このコードは、AZ からのすべての文字を出力します)。最後の質問: このコードを変更してそれを利用するにはどうすればよいですか?

前もって感謝します。良い1日を。

編集: 1つの方法を見つけましたが、バグのあるテキストが表示されます。何か案は?

 public static void Writetocol(string s)
            {
               var kiir = s;
            byte[] barr;
            kiir = Convert.ToString(kiir);
            barr = Encoding.ASCII.GetBytes(kiir);
            SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);

            if (!h.IsInvalid)
            {
                CharInfo[] buf = new CharInfo[80 * 25];
                SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = 80, Bottom = 25 };
                for (short attribute = 0; attribute < 15; ++attribute)
                {
                    for (int i = 0; i < barr.Length; ++i)
                    {
                        buf[i].Attributes = attribute;
                        buf[i].Char.AsciiChar = barr[i];
                    }

                    bool b = WriteConsoleOutput(h, buf,
                      new Coord() { X = 80, Y = 25 },
                      new Coord() { X = 0, Y = 0 },
                      ref rect);
                }
            }
         }

それは私にこれを与えます: それは私にこれを与える 1 べき時: 2

(誰かが疑問に思うなら、それはハンガリー語で書かれています)

4

1 に答える 1

1

次のように、独自の改行と位置を処理することで、指定した文字列を解析してバッファーを埋めることができます。

    static void writeCol(string a, ConsoleColor b)
    {
        byte x = 0, y = 0;
        // parsing to make it  fly
        // fill the buffer with the string 
        for(int ci=0; ci<a.Length;ci++)
        {
            switch (a[ci])
            {
                case '\n': // newline char, move to next line, aka y=y+1
                    y++;
                    break;
                case '\r': // carriage return, aka back to start of line
                    x = 0;
                    break;
                case ' ': // a space, move the cursor to the right
                    x++;
                    break;
                default:
                    // calculate where we should be in the buffer
                    int i = y * 80 + x;
                    // color
                    buf[i].Attributes= (short) b;
                    // put the current char from the string in the buffer
                    buf[i].Char.AsciiChar = (byte) a[ci];
                    x++;
                    break;
            }
        }
        // we handled our string, let's write the whole screen at once
        bool success = WriteConsoleOutput(h, buf,
                     new Coord() { X = 80, Y = 25 },
                     new Coord() { X = 0, Y = 0 },
                     ref rect);
    }

hセーフハンドルとネイティブ バッファーを既に静的な状態にリファクタリングしてbufいるため、アプリでこれを 1 回だけ使用していることに注意してください。

static IntPtr h= GetStdHandle(STD_OUTPUT_HANDLE); 
static CharInfo[] buf = new CharInfo[80 * 25];
static SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = 80, Bottom = 25 };

GetStdHandleを追加しました

    //http://www.pinvoke.net/default.aspx/kernel32/GetStdHandle.html
    const int STD_OUTPUT_HANDLE = -11;
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);

その場合、代わりにWriteConsoleOutputを受け入れるようにメソッド署名を変更する必要があります。IntPtrSafeFileHandle

このメソッドを次のテスト コールでテストしました。

writeCol(@"

     TEST
     ======
     1 test

     FuBar", ConsoleColor.Blue);

これにより、次の結果が得られます。

ここに画像の説明を入力

bufしたがって、最初に正しい位置でバッファを埋めてWriteConsoleOutputから、すぐにバッファを画面にコピーするために呼び出すことを覚えておいてください。それを非常に頻繁に呼び出すと、振り出しに戻ります...

画面全体を記述する必要はないことに注意してください。さまざまな長方形を使用することで、画面の一部だけを書き込むことができます。

このデモでは、すべてのエラー チェックを省略しました。それはあなた次第です。

msdn のドキュメントで使用されているネイティブ コールについて調べてみるとよいでしょう。

于 2015-02-08T22:39:27.880 に答える