2013-05-25 4 views
3

Я делаю простую игру для гонки в стиле WinForm. У меня есть два объекта - машины, и они перемещаются по форме при нажатии клавиши (Form1KeyDown_Event).Ответьте на несколько событий KeyDown

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

Как прослушивать два игрока одновременно? Должен ли я использовать потоки и иметь каждый автомобиль в своей собственной нитке?

+1

У меня нет решения для вас, но могу сказать, что многопоточность - это НЕ ответ. Все события KeyDown обрабатываются в основном (UI) потоке. –

+1

Это может быть аппаратное ограничение на клавиатуре. Работает ли она, когда вы нажимаете одну клавишу, а другая нажимается, когда вы печатаете документ? –

+0

Вы пытались использовать keydown и keyup вместо этого и «запоминаете», какие клавиши находятся в состоянии «вниз»? – Patrick

ответ

1

Вот простой пример того, что вы можете сделать, чтобы прослушивать несколько ключей одновременно с использованием событий keyup и keydown.

using System; 
using System.Collections.Generic; 
using System.Windows.Forms; 

namespace WinFormTest { 
    public partial class Form1 : Form { 
     private readonly IDictionary<Keys, bool> downState; 

     public Form1() { 
      InitializeComponent(); 
      downState = new Dictionary<Keys, bool>(); 
      downState.Add(Keys.W, false); 
      downState.Add(Keys.D, false); 

      KeyDown += remember; 
      KeyUp += forget; 
     } 

     protected override void OnLoad(EventArgs e) { 
      base.OnLoad(e); 
      Timer timer = new Timer() { Interval = 100 }; 
      timer.Tick += updateGUI; 
      timer.Start(); 
     } 

     private void remember(object sender, KeyEventArgs e) { 
      downState[e.KeyCode] = true; 
     } 

     private void forget(object sender, KeyEventArgs e) { 
      downState[e.KeyCode] = false; 
     } 

     private void updateGUI(object sender, EventArgs e) { 
      label1.Text = downState[Keys.W] ? "Forward" : "-"; 
      label2.Text = downState[Keys.D] ? "Right" : "-"; 
     } 
    } 
} 
0

Возможно, вам захочется исследовать переход на нижний уровень и использование оконных крючков для обнаружения событий клавиатуры. Для этого требуется P/Invoking в нативных методах, но довольно прямолинейно. Крючок, который вы хотите, - WH_LL_KEYBOARD. Подробности можно найти по адресу: pinvoke.net.

Вы должны были бы немного шаблонный, но это как можно ближе к клавиатуре событий, как вы можете ожидать, чтобы получить:

[StructLayout(LayoutKind.Sequential)] 
public struct KBDLLHOOKSTRUCT 
{ 
    public uint vkCode; 
    public uint scanCode; 
    public uint flags; 
    public uint time; 
    public IntPtr dwExtraInfo; 
} 

public delegate IntPtr LowLevelKeyboardProc(int, IntPtr, KBDLLHOOKSTRUCT); 

[DllImport("kernel32.dll")] 
public static extern uint GetCurrentThreadId(); 

[DllImport("kernel32.dll", SetLastError = true)] 
public static extern IntPtr GetModuleHandle(string lpModuleName); 

[DllImport("user32.dll", SetLastError = true)] 
public static extern bool UnhookWindowsHookEx(IntPtr hhk); 

[DllImport("user32.dll", SetLastError = true)] 
public static extern IntPtr SetWindowsHookEx(int idhook, LowLevelKeyboardProc proc, IntPtr hMod, uint threadId); 

[DllImport("user32.dll")] 
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam); 

public static IntPtr SetHook(LowLevelKeyboardProc proc) 
{ 
    using (var curProc = Process.GetCurrentProcess()) 
    using (var curMod = curProc.MainModule) 
    { 
     return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curMod.ModuleName), 0u); 
    } 
} 

public IntPtr MyKeyboardHook(int code, IntPtr wParam, ref KBDLLHOOKSTRUCT keyboardInfo) 
{ 
    if (code < 0) 
    { 
     return CallNextHookEx(IntPtr.Zero, wParam, ref keyboardInfo); 
    } 

    // Do your thing with the keyboard info. 

    return CallNextHookEx(IntPtr.Zero, code, wParam, ref keyboardInfo); 
} 

Убедитесь отцепить свой обработчик, когда ваше приложение перестает нуждаясь его. KBDLLHOOKSTRUCT инкапсулирует всю информацию, которую Windows сообщит вам о событии клавиатуры; Детали его членов могут быть found at MSDN.

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

+0

Разве это не так, как использовать с клавиатуры? Я не понимаю из вашего примера, как OP может использовать его, чтобы увидеть, нажата ли клавиша или нет, не могли бы вы объяснить это? – Patrick

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