14

私はC#コンソールアプリケーションで作業しているゲームを持っています。純粋に、より良い方法に進む前の練習としてです。ボタン機能が組み込まれているWindowsフォームアプリなどを使用するのとは対照的に、私はカーソル位置(私はその方法を知っています)を取得し、それをコンソールアプリケーション内のいくつかの領域と比較するように努めています。おそらくピクセルの位置ですが、ピクセル以外に何らかの組み込みの空間単位があるかどうかもわかりません(この最後のビットは私が理解できない部分です)。

PSこれは一般的な用語であり、コードはまだ提供されていませんが、コンソールアプリケーション内でXY座標を取得し、それらをintに貼り付ける方法の簡単な説明だけを求めているので、必要だとは思いません。変数。

よろしくお願いします!:D

4

7 に答える 7

15

長い間検索した後、私はついにこの例を見つけました。ページからサンプルプログラムをダウンロードします。特に、コンソールウィンドウ内のマウスの位置(文字ベース)が表示されます。

編集:これは私のConsoleListenerクラスです(私のクラスの一部をNativeMethods含む)。(メソッドを呼び出した後)
にハンドラーをアタッチできます。MouseEventStart()

using System;
using System.Runtime.InteropServices;
using System.Threading;
using static ConsoleLib.NativeMethods;

namespace ConsoleLib
{
    public static class ConsoleListener
    {
        public static event ConsoleMouseEvent MouseEvent;

        public static event ConsoleKeyEvent KeyEvent;

        public static event ConsoleWindowBufferSizeEvent WindowBufferSizeEvent;

        private static bool Run = false;


        public static void Start()
        {
            if (!Run)
            {
                Run = true;
                IntPtr handleIn = GetStdHandle(STD_INPUT_HANDLE);
                new Thread(() =>
                {
                    while (true)
                    {
                        uint numRead = 0;
                        INPUT_RECORD[] record = new INPUT_RECORD[1];
                        record[0] = new INPUT_RECORD();
                        ReadConsoleInput(handleIn, record, 1, ref numRead);
                        if (Run)
                            switch (record[0].EventType)
                            {
                                case INPUT_RECORD.MOUSE_EVENT:
                                    MouseEvent?.Invoke(record[0].MouseEvent);
                                    break;
                                case INPUT_RECORD.KEY_EVENT:
                                    KeyEvent?.Invoke(record[0].KeyEvent);
                                    break;
                                case INPUT_RECORD.WINDOW_BUFFER_SIZE_EVENT:
                                    WindowBufferSizeEvent?.Invoke(record[0].WindowBufferSizeEvent);
                                    break;
                            }
                        else
                        {
                            uint numWritten = 0;
                            WriteConsoleInput(handleIn, record, 1, ref numWritten);
                            return;
                        }
                    }
                }).Start();
            }
        }

        public static void Stop() => Run = false;


        public delegate void ConsoleMouseEvent(MOUSE_EVENT_RECORD r);

        public delegate void ConsoleKeyEvent(KEY_EVENT_RECORD r);

        public delegate void ConsoleWindowBufferSizeEvent(WINDOW_BUFFER_SIZE_RECORD r);

    }


    public static class NativeMethods
    {
        public struct COORD
        {
            public short X;
            public short Y;

            public COORD(short x, short y)
            {
                X = x;
                Y = y;
            }
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct INPUT_RECORD
        {
            public const ushort KEY_EVENT = 0x0001,
                MOUSE_EVENT = 0x0002,
                WINDOW_BUFFER_SIZE_EVENT = 0x0004; //more

            [FieldOffset(0)]
            public ushort EventType;
            [FieldOffset(4)]
            public KEY_EVENT_RECORD KeyEvent;
            [FieldOffset(4)]
            public MOUSE_EVENT_RECORD MouseEvent;
            [FieldOffset(4)]
            public WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
            /*
            and:
             MENU_EVENT_RECORD MenuEvent;
             FOCUS_EVENT_RECORD FocusEvent;
             */
        }

        public struct MOUSE_EVENT_RECORD
        {
            public COORD dwMousePosition;

            public const uint FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001,
                FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004,
                FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008,
                FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010,
                RIGHTMOST_BUTTON_PRESSED = 0x0002;
            public uint dwButtonState;

            public const int CAPSLOCK_ON = 0x0080,
                ENHANCED_KEY = 0x0100,
                LEFT_ALT_PRESSED = 0x0002,
                LEFT_CTRL_PRESSED = 0x0008,
                NUMLOCK_ON = 0x0020,
                RIGHT_ALT_PRESSED = 0x0001,
                RIGHT_CTRL_PRESSED = 0x0004,
                SCROLLLOCK_ON = 0x0040,
                SHIFT_PRESSED = 0x0010;
            public uint dwControlKeyState;

            public const int DOUBLE_CLICK = 0x0002,
                MOUSE_HWHEELED = 0x0008,
                MOUSE_MOVED = 0x0001,
                MOUSE_WHEELED = 0x0004;
            public uint dwEventFlags;
        }

        [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
        public struct KEY_EVENT_RECORD
        {
            [FieldOffset(0)]
            public bool bKeyDown;
            [FieldOffset(4)]
            public ushort wRepeatCount;
            [FieldOffset(6)]
            public ushort wVirtualKeyCode;
            [FieldOffset(8)]
            public ushort wVirtualScanCode;
            [FieldOffset(10)]
            public char UnicodeChar;
            [FieldOffset(10)]
            public byte AsciiChar;

            public const int CAPSLOCK_ON = 0x0080,
                ENHANCED_KEY = 0x0100,
                LEFT_ALT_PRESSED = 0x0002,
                LEFT_CTRL_PRESSED = 0x0008,
                NUMLOCK_ON = 0x0020,
                RIGHT_ALT_PRESSED = 0x0001,
                RIGHT_CTRL_PRESSED = 0x0004,
                SCROLLLOCK_ON = 0x0040,
                SHIFT_PRESSED = 0x0010;
            [FieldOffset(12)]
            public uint dwControlKeyState;
        }

        public struct WINDOW_BUFFER_SIZE_RECORD
        {
            public COORD dwSize;
        }

        public const uint STD_INPUT_HANDLE = unchecked((uint)-10),
            STD_OUTPUT_HANDLE = unchecked((uint)-11),
            STD_ERROR_HANDLE = unchecked((uint)-12);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetStdHandle(uint nStdHandle);


        public const uint ENABLE_MOUSE_INPUT = 0x0010,
            ENABLE_QUICK_EDIT_MODE = 0x0040,
            ENABLE_EXTENDED_FLAGS = 0x0080,
            ENABLE_ECHO_INPUT = 0x0004,
            ENABLE_WINDOW_INPUT = 0x0008; //more

        [DllImportAttribute("kernel32.dll")]
        public static extern bool GetConsoleMode(IntPtr hConsoleInput, ref uint lpMode);

        [DllImportAttribute("kernel32.dll")]
        public static extern bool SetConsoleMode(IntPtr hConsoleInput, uint dwMode);


        [DllImportAttribute("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern bool ReadConsoleInput(IntPtr hConsoleInput, [Out] INPUT_RECORD[] lpBuffer, uint nLength, ref uint lpNumberOfEventsRead);

        [DllImportAttribute("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern bool WriteConsoleInput(IntPtr hConsoleInput, INPUT_RECORD[] lpBuffer, uint nLength, ref uint lpNumberOfEventsWritten);

    }
}


正しく機能させるには、最初に次のコードを実行することをお勧めします。

IntPtr inHandle = GetStdHandle(STD_INPUT_HANDLE);
uint mode = 0;
GetConsoleMode(inHandle, ref mode);
mode &= ~ENABLE_QUICK_EDIT_MODE; //disable
mode |= ENABLE_WINDOW_INPUT; //enable (if you want)
mode |= ENABLE_MOUSE_INPUT; //enable
SetConsoleMode(inHandle, mode);

このファイルヘッダーを使用すると、次のようになります。

using System;
using static ConsoleLib.NativeMethods;
于 2015-04-30T15:03:52.187 に答える
7

また、コンソールはテキスト処理専用ではありません。あなたはそれのためにかなりまともなウィンドウマネージャーを書くことができます。あなたはそれで何でもすることができます。それはただ難しいです。

ただし、速度は遅くなります。ユーザーインターフェイスのコンソールを使用して、C#で仮想マシンを実装しました。テキストの行を次々に印刷しません。それ[インターフェース]はむしろGUIのように機能します。

コンソールでマウス入力が必要な場合は、次のフックを試してください:http: //blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx ?PageIndex=2#comments

于 2010-06-17T13:43:12.787 に答える
4

イベントを使用せずにゲームを作成する場合...実際に実行しているのは、イベントを自分で実装することだけです。これは、言語の組み込みイベントを使用するよりもはるかに効率的にできるため、有利です。このように書かれたゲームは、自分が何をしているのかを知っていれば、エラーが発生しにくくなります。

たとえば、兄にゲームの書き方を教えようとしたとき、兄のために簡単なヘビゲームを書きました。メインループをスレッドに入れ、ヘビを動かして、サイクルの新しい位置に描画します。4つのことを継続的にチェックするスレッドを同時に実行します。

  1. ヘビが自分自身に衝突した場合(ゲームオーバー); ゲームオーバーが発生した場合は、ヘビのメイン位置を更新するメインスレッドを停止し、ゲームオーバーを画面に印刷し、キー入力を待ってからゲームを再開します。

  2. ヘビがリンゴを食べていたら; 食べたリンゴの数を示すカウンター変数をインクリメントし、この新しい値を画面に出力して、以前にあったものを上書きします。

  3. ヘビが10で割り切れる数のリンゴを食べた場合(ヘビは1セル成長し、ヘビが行う各動きの間にどのくらいの時間が経過するかを示す待機変数から減算します)

  4. 矢印キーが押された場合。左の場合は0に、右の場合は1に、下の場合は2に、上にある場合は3に移動します。これが格納されているintは、ヘビを移動させる4つのデリゲートの配列へのポインタです。正しい方向に。

ヘビの位置を更新するメインループは、これらの4つのことをチェックするスレッドにヘビが何をしているのかを伝えます。私がこれを行う方法は、ヘビの頭が移動する画面上のすべてのセルを持って、デリゲートの2次元配列を参照することです。この一連の代理人について:

ゲームはコンソールモードで書かれており、コンソールの色を使用しています。コンソールは80x50文字に設定されています。次のようなデリゲート: "delegate void ptr()"; 次に、「ptr [、] pos = newptr[80,50]」で配列を作成します。ヘビの頭が画面上の位置(4,5)にあるとすると、そこに移動した後、メインループは「pos [4,5] .Invoke();」を実行します。

そのうちの1つ:ヘビが新しい位置に移動すると、メインループスレッドは、ヘビが画面上でカバーする各セルを取得し、その位置にデリゲートを設定して、「void gameover()」と呼ばれる関数をポイントします。 gameover_変数をtrueに設定します。したがって、ゲームのステータスをチェックするループスレッドがゲームオーバーをチェックすると、ゲームがフリーズし、ゲームオーバーが画面に印刷されます。

もう1つ:アップルが画面に描画されると、(ランダム化された)描画されるデリゲート位置は、アップルカウンターをインクリメントし、現在のアップルをビューから削除して、画面上の新しいアップル。古いアップルの位置を何もしない「voidnop()」を指すように設定し、新しいアップルの位置を「voidincrement_apple()」を指すように設定します。

これが基本的にゲームの仕組みです。ご覧のとおり、ヘビは画面上のこれらの位置に移動し、「if(snake_position == some_position)」のような明示的なチェックを実行せずに、ゲームはゲーム内で発生するすべてのことに対して想定されるすべてのことを自動的に実行します。フォームのボタンをクリックしたときと同じように、そのイベントに割り当てられたアクションは、イベントを自分でチェックしなくても自動的に実行されます。

ご覧のとおり、C#が提供するフォームとデフォルトのイベントを使用することもできましたが、使用しませんでした。コンソールインターフェイスを使用して、独自のイベントシステムを実装しました。

これが舞台裏での仕組みです。フォームアプリのメインループは、画面上のすべてのボタンなどからの入力をチェックするスレッドで実行されます。これらの各項目は、使用するブール変数をtrueに設定します。このボタンをクリックすると、ループを実行している別のスレッドが何を押したかをチェックし、「button1」というボタンを押したとすると、そのボタンにはデリゲートが割り当てられます。次に、そのデリゲートは、それが指すものを使用して実行されます。

説明するのは難しいですが、これはあなたにとって意味がありますか?

于 2010-06-17T13:38:41.363 に答える
2

@フランククルーガーが言ったこと。本当にこれをしたいですか?Windowsフォームは、これをはるかに簡単にするように設計されています。

その場合は、低レベルのWindowsAPIでPInvokeを使用する必要があります。これを出発点として試してください。ただし、これはWindowsフォームアプリケーションよりもかなり複雑であることに注意してください。

于 2009-12-22T06:52:10.327 に答える
1

これは少し前のことですが、コンソールでマウスの位置を取得するのはそれほど難しくありません。他の誰かが答えを求めている場合に備えて、私が使用するコードを紹介します。

public static class Input
{
    [DllImport("user32.dll")]
    static extern bool GetCursorPos(out POINT point);

    struct POINT
    {
        public int x;
        public int y;
    }
    public static POINT GetMousePosition()
    {
        POINT pos;
        GetCursorPos(out pos);
        return pos;
    }
}

楽しみ!

編集:マウスクリックを取得する簡単な方法を見つけました(これはキーボードボタンでも機能します。https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-を参照してください)。 code?redirectedfrom=MSDN必要なもの

[DllImport("user32.dll")]
public static extern bool GetAsyncKeyState(int button);
public static bool IsMouseButtonPressed(MouseButton button)
{
    return GetAsyncKeyState((int)button);
}
public enum MouseButton
{
    LeftMouseButton = 0x01,
    RightMouseButton = 0x02,
    MiddleMouseButton = 0x04,
}
于 2021-08-03T03:50:43.597 に答える
0

たくさん勉強した後、私は解決策を見つけました。

以下で作成したButtonクラスとGUIを使用すると、ボタンを作成することができ、またはマウスでクリックします(完全には機能しません)。そして、あなたはインポートする必要がありSystem.Windows.FormsますSystem.Drawing

于 2017-04-15T22:24:18.367 に答える
-2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Traingames.NetElements;
//using System.Windows.Forms;
using System.Drawing;

namespace ConsoleTools.NET
{
    class Program
    {
        static ConsoleFramework c = new ConsoleFramework();
        static public Point MousePos;
        static Button One = new Button();
        static Pixel Mouse = new Pixel();

        static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.White;
            // t.Draw(10, 40, ConsoleColor.Gray);
            One.Set(0, 10, "░░1░░", ConsoleColor.Gray);

            GUI.Add(One);
            GUI.CalculateOnStart();
            for (;;)
            {
                MousePos = new Point(System.Windows.Forms.Control.MousePosition.X / (Console.LargestWindowWidth / 24), System.Windows.Forms.Control.MousePosition.Y / (Console.LargestWindowHeight / 7));
                if (One.Pressed(MousePos))
                {
                    Console.Write("1");
                }
                //   Console.Clear();
            }
        }
    }
    }

    namespace Traingames.NetElements
    {
        public class ConsoleFramework
        {
        public char[] chars = { '█', '▓', '▒', '░' };

        Point MousePos()
        {
            return new Point((System.Windows.Forms.Control.MousePosition.X / (Console.LargestWindowWidth / 24)) - 100, System.Windows.Forms.Control.MousePosition.Y / (Console.LargestWindowHeight / 7));
        }

        public void SetPixel(int x, int Y, ConsoleColor color)
        {
            int y = (int)Math.Floor(Y / 1.5f);

            for (int i = 0; i < y; i++)
            {
                Console.WriteLine("");
            }

            for (int i = 0; i < x - 1; i++)
            {
                Console.Write(" ");
            }
            Console.BackgroundColor = color;
            Console.Write(" ");
            Console.BackgroundColor = ConsoleColor.Black;
        }
    }

    public class Pixel : GUI
    {
        public void Set(int X, int Y, string text)
        {
            ConsoleColor backColor = ConsoleColor.Black;
            BackColor = backColor;
            int yyyyyy = (int)Math.Floor(Y / 1.5f);
            Text = text;
            y = Y;
            x = X;
        }
    }

    public class GUI
    {
        public int x, y;
        public static GUI[,] GraphicalUserInterfaces = new GUI[1000, 1000];
        public ConsoleColor BackColor;
        public string Text;

        public void Draw()
        {
            int X = x;
            int Y = y;
            ConsoleColor backColor = BackColor;
            string text = Text;


            for (int i = 0; i < y; i++)
            {
                Console.WriteLine("");
            }

            for (int i = 0; i < x - 1; i++)
            {
                Console.Write(" ");
            }
            Console.BackgroundColor = BackColor;
            Console.Write("[" + text + "]");
            Console.BackgroundColor = ConsoleColor.Black;
            Point M = ConsoleTools.NET.Program.MousePos;

            // return M.X >= xx && M.X <= (xx + Text.Length + 1) && M.Y >= yy && M.Y <= yy + 2 && Control.MouseButtons == MouseButtons.Left;
        }
        static GUI Last;
        public static void Add(GUI gui)
        {
            GraphicalUserInterfaces[gui.x, gui.y] = gui;
        }

        public static void CalculateOnStart()
        {
            for (int x = 0; x < 1000; x++)
            {
                for (int y = 0; y < 1000; y++)
                {
                    if (GraphicalUserInterfaces[x, y] != null)
                    {

                        if (Last != null && y < Last.y)
                        {
                            GraphicalUserInterfaces[x, y].x = Last.x - GraphicalUserInterfaces[x, y].x;
                            GraphicalUserInterfaces[x, y].y = Last.y - GraphicalUserInterfaces[x, y].y;
                        }
                        GraphicalUserInterfaces[x, y].Draw();
                        GraphicalUserInterfaces[x, y].x = x;
                        GraphicalUserInterfaces[x, y].y = y;
                        Last = GraphicalUserInterfaces[x, y];
                    }

                }
            }
        }

    }

    public class Button : GUI
    {

        public bool Over(Point M)
        {
            int yy = ((y * 2) - y / 3) + 2;

            int xx = (x / (Console.LargestWindowWidth / 24)) + Text.Length;

            if (M.X >= xx && M.X <= (xx + Text.Length + 1) && M.Y >= yy && M.Y <= yy + 2)
                Console.BackgroundColor = ConsoleColor.DarkBlue;

            return M.X >= xx && M.X <= (xx + Text.Length + 1) && M.Y >= yy && M.Y <= yy + 2;
        }

        public bool Pressed(Point M)
        {
            int yy = ((y * 2) - y / 3) + 1;

            int xx = (x / (Console.LargestWindowWidth / 24));

            return M.X >= xx && M.X <= (xx + Text.Length * 1.5f) && M.Y >= yy && M.Y <= yy + 2 && System.Windows.Forms.Control.MouseButtons == System.Windows.Forms.MouseButtons.Left;
        }

        public void CalculateClick(Point M)
        {
            if (Pressed(M))
            {
                Console.Clear();
                Draw();
            }
        }

        public void Set(int X, int Y, string text, ConsoleColor backColor)
        {
            BackColor = backColor;
            int yyyyyy = (int)Math.Floor(Y / 1.5f);
            Text = text;
            y = Y;
            x = X;

            int xx = (x / (Console.LargestWindowWidth / 24)) + Text.Length;
        }
    }
}

于 2017-04-15T22:32:24.580 に答える