2009-12-22 3 views
5

У меня есть игра, в которой я работаю в консольном приложении C#, только как практика, прежде чем переходить к лучшим методам. В отличие от использования чего-то вроде приложения Windows Forms, в котором встроена функция кнопки, я пытаюсь захватить позицию курсора (что я знаю, как это сделать) и сравнить ее с рядом областей внутри консольного приложения, как определено возможно, расположение пикселей, но я также не знаю, есть ли какая-то встроенная единица пространства, отличная от пикселей (этот последний бит - это часть, которую я не могу понять).Консольное приложение Мышь-клик X Y Обнаружение/сравнение координат

P.S. Я знаю, что это в общих чертах, без кода, уже предоставленного, но я не чувствую, что это необходимо, поскольку все, о чем я прошу, - это краткое объяснение того, как захватить координаты XY внутри консольного приложения и привязать их к переменным int ,

Большое спасибо заранее! : D

+3

** Консольные приложения ** обычно не взаимодействуют с мышью, и у них нет много забот о системах координат пикселей. Хотя я уверен, что вы собираетесь получить кучу ответов, описывающих, как захватить мышь и многое другое, я думаю, вам лучше сделать шаг назад и пересмотреть то, что вы делаете. –

+2

Большое спасибо за комментарий, но я изучаю как можно больше о консольных приложениях C#. Примерно через 3 месяца я буду удовлетворен и перейду к формам и, в конечном итоге, новым языкам. Я прочитал часть вашего блога и ценю ваши взгляды на изучение языков. Получение языка для выполнения чего-то, что обычно не происходит в некоторых случаях, является лишь частью проблемы. – Bloodyaugust

ответ

4

Что сказал @Frank Крюгер. Вы действительно хотите это сделать? Windows Forms спроектирован таким образом, чтобы сделать это намного более удобным, чем.

Если вы это сделаете, вам нужно будет использовать PInvoke в низкоуровневом Windows API. Попробуйте this в качестве отправной точки - но имейте в виду, что это значительно сложнее, чем приложение Windows Forms.

+0

Ничего себе, это чрезвычайно сложно. У меня создалось впечатление, что игры написаны как консольное приложение или что-то вроде этого, в отличие от Windows Forms, и такие, как они основаны на событиях. Нет ли более простого способа? – Bloodyaugust

+0

Мы предупреждали вас! Консольные приложения действительно используются только для утилит, обрабатывающих текст или файлы. На ПК графически интенсивные игры обычно используют DirectX, WPF или Windows Forms - Windows Forms, вероятно, проще всего начать. Интерфейсы пользовательского интерфейса, такие как Windows Forms, посвящены событиям и способам их обработки, как вы найдете. –

+0

Тогда почему я всегда слышал, что игры не основаны на событиях, а скорее петлеобразны? – Bloodyaugust

3

Когда вы пишете игру без использования событий ... все, что вы действительно делаете, осуществляете сами. Это выгодно, потому что вы можете сделать его намного более эффективным, чем при использовании встроенных событий вашего языка. Игры, написанные таким образом, менее подвержены ошибкам, если вы знаете, что делаете.

Например, когда я пытался научить своего брата тому, как написаны игры, я написал для него простую змеиную игру. У меня была основная петля в потоке, переместите змею и нарисуйте ее на новом месте в цикле. У меня будет поток, работающий в то же время, который непрерывно проверяет 4 вещи:

1) Если змея врезалась в себя (игра закончилась); если происходит игра, остановите основной поток, который обновляет основное положение змеи, печатайте игру на экране, ожидайте ввод ключа, затем перезапустите игру.

2) Если змея съела яблоко; увеличьте переменную счетчика, в которой указано, сколько яблок было съедено, и напечатайте это новое значение на экране, переписав то, что было раньше.

3) Если змея съела количество яблок, кратных 10 (змея вырастает на 1 клетку, вычесть из переменного ожидания, что говорит, сколько времени должно пройти между каждым движением змей делает)

4) Если нажата клавиша со стрелкой. Если влево, установите для перемещения в 0, если правое задание переместится в 1, если набор вниз переместится на 2, если набор вверх переместится на 3. Интенс, в котором он хранится, является указателем на массив из 4 делегатов, которые заставляют перемещение змеи в правильном направлении.

Основная петля, которая обновляет положение змеи, сообщит нить, проверяющую эти 4 вещи, что делает змея. То, как я это делаю, - это то, что у меня есть каждая ячейка на экране, на которую движется голова змеи, чтобы ссылаться на двумерный массив делегатов. Об этом массиве делегатов:

Игра написана в консольном режиме и использует цвета консоли. Консоль установлена ​​в 80x50 символов. Делегат следующим образом: «delegate void ptr()»; то я создаю массив с помощью: «ptr [,] pos = new ptr [80,50]». Скажем, что голова змеи находится в положении (4,5) на экране, после того, как она переместилась туда, основной цикл выполнит «pos [4,5] .Invoke();».

Один из них: Когда змея переместится в новое положение, основной поток цикла получит каждую ячейку, которую змея покрывает на экране, и установите делегат в этом положении, чтобы указать на функцию, называемую «void gameover»() ", который установил бы переменную gameover_ в значение true. Поэтому, когда поток цикла, который проверяет состояние игры, проверяет, что происходит в игре, он замораживает игру и печатает игру на экране.

Другое: Когда на экране изображено яблоко, позиция делегата, на которую он нарисована (рандомизирована), устанавливается на «void increment_apple()», которая увеличивает счетчик яблока, удаляет текущее яблоко из просмотреть и нарисовать новое яблоко на экране, установив старую позицию яблока на «void nop()», которая ничего не делает, а в новой позиции яблока указывается «void increment_apple()».

В основном, как работает игра. Как вы можете видеть, змея перемещается в эти позиции на экране и без каких-либо явных проверок типа «if (snake_position == some_position)», игра автоматически делает все, что должно быть для всего, что происходит в игре, очень похоже на то, как при нажатии кнопки на форме действие, назначенное этому событию, выполняется автоматически, без необходимости самостоятельно проверять событие.

Итак, вы могли бы использовать форму и события по умолчанию, которые предоставляет C#, но я этого не сделал. Я использовал консольный интерфейс и реализовал собственную систему событий.

Вот как это работает за кулисами: Основной цикл для вашего приложения формы будет работать в потоке, который проверяет ввод всех кнопок и т. Д. На экране. Каждый из этих элементов будет устанавливать логическую переменную, которую они используют для истины. Когда вы нажимаете эту кнопку, другой поток, выполняющий цикл, проверяет, что вы нажали, и говорите, что нажал кнопку «button1», эта кнопка имела бы назначенный ей делегат; этот делегат затем выполняется с учетом того, на что он указывает.

Трудно объяснить, но имеет ли это смысл для вас?

5

Кроме того, консоль предназначена не только для обработки текста. Вы можете написать для этого довольно приличных оконных менеджеров. Вы можете с ним что-то сделать. Это сложнее.

Это медленнее. Я реализовал виртуальную машину в C#, используя консоль для пользовательского интерфейса. Он не печатает строки текста один за другим; он [интерфейс] действует скорее как GUI.

Если вы хотите ввод мыши на консоли, попробуйте этот крючок: http://blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx?PageIndex=2#comments

5

После поиска в течение длительного времени я, наконец, нашел this example. Загрузите example program на странице. Это дает вам, помимо прочего, местоположение мыши в окне консоли (на основе символов).

EDIT: Это мой ConsoleListener класс (с частью моего NativeMethods класса).
Вы можете прикрепить обработчик к MouseEvent (после вызова метода 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); 

    } 
} 


Чтобы заставить его работать должным образом, вы, вероятно, хотите, чтобы выполнить этот код первым:

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

Это удивительная находка! Большое спасибо, спасибо! – WolfyD

1

После долгого изучения, я нашел решение. С классом Button и графическим интерфейсом, который я создал, можно сделать кнопку, и ее можно щелкнуть мышью или мышью (это не работает отлично). И вам нужно импортировать System.Windows.Forms и 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; 
    } 

} 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^