2009-12-22 33 views
5

Tôi có một trò chơi mà tôi đang làm việc trong một ứng dụng giao diện điều khiển C#, hoàn toàn là thực hành trước khi tiếp tục các phương pháp tốt hơn. Trái với việc sử dụng một cái gì đó như Windows Forms App, có chức năng nút được xây dựng, tôi cố gắng lấy vị trí con trỏ (mà tôi biết cách làm) và so sánh nó với một số khu vực bên trong một ứng dụng giao diện điều khiển như được định nghĩa bởi có lẽ vị trí pixel, nhưng tôi cũng không biết nếu có một số loại được xây dựng trong đơn vị không gian khác với pixel (bit cuối cùng này là một phần tôi không thể tìm).Bàn điều khiển Ứng dụng Chuột-Nhấn X Y Phối hợp Phát hiện/So sánh

P.S. Tôi biết điều này nói chung, không có mã đã được cung cấp, nhưng tôi không cảm thấy rằng nó là cần thiết vì tất cả những gì tôi yêu cầu là giải thích ngắn gọn về cách lấy tọa độ XY bên trong một ứng dụng giao diện điều khiển và gắn chúng vào các biến int .

Rất cám ơn trước! : D

+3

** Ứng dụng giao diện ** thường không tương tác với chuột và cũng không có nhiều quan tâm về hệ tọa độ pixel. Trong khi tôi chắc chắn bạn sắp nhận được một loạt các câu trả lời mô tả cách nắm bắt chuột và điều gì đó, tôi nghĩ bạn nên lùi lại một bước và xem xét lại những gì bạn đang làm. –

+2

Cảm ơn rất nhiều vì đã bình luận, nhưng tôi đang học nhiều nhất có thể về các ứng dụng giao diện điều khiển C#. Trong khoảng 3 tháng, tôi sẽ hài lòng, và chuyển sang các hình thức, và cuối cùng là các ngôn ngữ mới. Tôi đã đọc một phần blog của bạn và đánh giá cao quan điểm của bạn về việc học ngôn ngữ nào trước tiên. Bắt một ngôn ngữ để làm một cái gì đó bình thường không trong một số trường hợp chỉ là một phần của thách thức. – Bloodyaugust

Trả lời

4

@Frank Krueger nói gì. Bạn có thực sự muốn làm điều này? Windows Forms được thiết kế để làm cho số này nhiều hơn dễ dàng hơn.

Nếu bạn làm như vậy, bạn cần sử dụng PInvoke vào API Windows cấp thấp. Hãy thử this làm điểm bắt đầu - nhưng lưu ý rằng điều này phức tạp hơn nhiều so với ứng dụng Windows Forms.

+0

Chà, điều đó cực kỳ phức tạp. Tôi đã có ấn tượng rằng các trò chơi được viết dưới dạng một ứng dụng giao diện điều khiển, hoặc một cái gì đó như nó trái ngược với Windows Forms và như vậy, vì chúng là sự kiện dựa trên. Có cách nào đơn giản hơn không? – Bloodyaugust

+0

Chúng tôi đã cảnh báo bạn! Ứng dụng Console thực sự chỉ được sử dụng cho các tiện ích xử lý văn bản hoặc tệp. Trên PC đồ họa chuyên sâu trò chơi sử dụng thường sử dụng DirectX, WPF hoặc Windows Forms - Windows Forms có lẽ là dễ nhất để bắt đầu với. Các khung công tác UI như Windows Forms là tất cả về các sự kiện và cách xử lý chúng như bạn sẽ tìm thấy. –

+0

Vậy tại sao tôi luôn nghe rằng trò chơi không dựa trên sự kiện, mà là dựa trên vòng lặp? – Bloodyaugust

3

Khi bạn viết một trò chơi mà không sử dụng các sự kiện ... tất cả các bạn thực sự đang tự thực hiện các sự kiện. Điều này là thuận lợi, bởi vì bạn có thể làm cho nó hiệu quả hơn rất nhiều so với việc sử dụng các sự kiện tích hợp trong ngôn ngữ của bạn. Trò chơi được viết theo cách này ít bị lỗi hơn nếu bạn biết mình đang làm gì.

Ví dụ: khi tôi cố gắng dạy cho anh trai tôi cách trò chơi được viết, tôi đã viết một trò chơi rắn đơn giản cho anh ấy. Tôi đã có vòng lặp chính trong một sợi, di chuyển con rắn và vẽ nó ở vị trí mới của nó trong một chu kỳ. Tôi sẽ có một sợi chạy cùng một lúc liên tục kiểm tra 4 thứ:

1) Nếu con rắn bị rơi vào chính nó (trò chơi kết thúc); nếu trò chơi kết thúc xảy ra, tạm dừng chủ đề chính cập nhật vị trí chính của con rắn, in trò chơi lên trên màn hình, chờ đầu vào chính, sau đó khởi động lại trò chơi.

2) Nếu con rắn đã ăn táo; tăng biến số lượt truy cập cho biết có bao nhiêu quả táo đã được ăn và in giá trị mới này trên màn hình, ghi đè lên những gì đã có trước đây.

3) Nếu con rắn đã ăn một lượng táo chia hết cho 10 (con rắn mọc bởi 1 tế bào, trừ từ một biến chờ đợi mà nói bao nhiêu thời gian phải vượt qua giữa mỗi phong trào rắn làm)

4) Nếu một phím mũi tên đã được nhấn. Nếu trái, thiết lập di chuyển đến 0, nếu thiết lập phải di chuyển đến 1, nếu thiết lập xuống di chuyển đến 2, nếu thiết lập di chuyển đến 3. int rằng điều này được lưu trữ trong là một con trỏ đến một mảng của 4 đại biểu mà làm cho con rắn di chuyển đi đúng hướng.

Vòng lặp chính cập nhật vị trí của con rắn sẽ cho chủ đề kiểm tra 4 điều mà con rắn đang làm. Cách tôi làm điều này là tôi có tất cả các tế bào trên màn hình mà đầu con rắn di chuyển để tham khảo một mảng 2 chiều của các đại biểu. Giới thiệu về mảng đại biểu này:

Trò chơi được viết ở chế độ bảng điều khiển và sử dụng màu bảng điều khiển. Bảng điều khiển được đặt thành 80x50 ký tự. Một đại biểu như sau: "delegate void ptr()"; sau đó tôi tạo mảng với: "ptr [,] pos = new ptr [80,50]". Nói đầu của con rắn ở vị trí (4,5) trên màn hình, sau khi nó đã di chuyển ở đó vòng lặp chính sẽ thực thi "pos [4,5] .Invoke();".

Một trong số chúng: Khi con rắn di chuyển đến vị trí mới, chuỗi vòng lặp chính sẽ lấy từng ô mà con rắn nằm trên màn hình và đặt đại biểu tại vị trí đó để trỏ đến một hàm có tên là "void gameover() "sẽ đặt biến gameover_ thành true. Vì vậy, khi các chủ đề vòng lặp kiểm tra tình trạng của trò chơi kiểm tra cho gameover, nó đóng băng các trò chơi và in trò chơi trên màn hình.

Khác: Khi quả táo được vẽ trên màn hình, vị trí đại biểu được vẽ tại (được chọn ngẫu nhiên) được đặt thành "void increment_apple()" tăng bộ đếm táo, xóa táo hiện tại khỏi xem, và vẽ một quả táo mới trên màn hình, thiết lập vị trí táo cũ để trỏ đến một "void nop()" mà không có gì, và vị trí táo mới để trỏ đến "void increment_apple()".

Đây là cơ bản cách hoạt động của trò chơi. Như bạn có thể thấy, con rắn di chuyển đến các vị trí này trên màn hình và nó không thực hiện bất kỳ kiểm tra rõ ràng nào như "if (snake_position == some_position)", trò chơi sẽ tự động thực hiện mọi thứ cần thiết cho mọi thứ xảy ra trong trò chơi, giống như cách bạn bấm vào một nút trên một biểu mẫu, một hành động được gán cho sự kiện đó được tự động thực hiện, mà không cần phải tự kiểm tra sự kiện đó.

Vì vậy, bạn thấy đấy, tôi có thể đã sử dụng biểu mẫu và các sự kiện mặc định mà C# cung cấp, nhưng tôi thì không. Tôi đã sử dụng giao diện điều khiển và triển khai hệ thống sự kiện của riêng mình.

Đây là cách hoạt động của cảnh sau: vòng lặp chính cho ứng dụng biểu mẫu của bạn sẽ chạy trong chuỗi kiểm tra đầu vào từ tất cả các nút, v.v. trên màn hình. Mỗi mục này sẽ thiết lập một biến boolean mà chúng sử dụng thành true. Khi bạn nhấp vào nút này, một chuỗi khác chạy vòng lặp kiểm tra những gì bạn đã nhấn và nói rằng bạn đã nhấn một nút có tên là "button1", nút đó sẽ có một đại biểu được gán cho nó; rằng người được ủy quyền sau đó được thực hiện với bất cứ điều gì nó chỉ ra.

Loại khó giải thích, nhưng điều này có hợp lý với bạn không?

5

Ngoài ra, bảng điều khiển không chỉ dành cho xử lý văn bản. Bạn có thể viết các trình quản lý cửa sổ khá tốt cho nó. Bạn có thể làm bất cứ điều gì với nó. Nó khó hơn.

Mặc dù chậm hơn. Tôi đã triển khai một máy ảo trong C# bằng giao diện điều khiển cho giao diện người dùng. Nó không in dòng văn bản sau cái kia; nó [giao diện] hoạt động khá giống GUI.

Nếu bạn muốn đầu vào chuột trên giao diện điều khiển, hãy thử móc này: http://blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx?PageIndex=2#comments

5

Sau khi tìm kiếm trong một thời gian dài cuối cùng tôi thấy this example. Tải xuống example program trên trang. Nó cung cấp cho bạn, trong số những thứ khác, vị trí chuột trong cửa sổ giao diện điều khiển (dựa trên ký tự).

EDIT: Đây là lớp học ConsoleListener của tôi (với một phần của lớp NativeMethods).
Bạn có thể đính kèm trình xử lý vào MouseEvent (sau khi gọi phương thức Start()).

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

    } 
} 


Để làm cho nó hoạt động đúng, có thể bạn muốn thực thi mã này đầu tiên:

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

Với phần đầu tập tin này:

using System; 
using static ConsoleLib.NativeMethods; 
+1

Đây là một tìm kiếm tuyệt vời! Giúp tôi rất nhiều, cảm ơn! – WolfyD

1

Sau khi nghiên cứu nhiều, tôi tìm thấy một giải pháp. Với lớp Button và GUI mà tôi đã tạo, có thể tạo một nút và được bấm bằng chuột hoặc chuột (nó không hoạt động hoàn hảo). Và bạn cần nhập System.Windows.Forms và System.Drawing.

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

} 
} 
Các vấn đề liên quan