1

http://www.microsoft.com/windowsxp/using/accessibility/characterrepeatrate.mspx-Windowsには、繰り返し遅延を設定するためのオプションがあります。これは、キーを押し続けた場合の最初のキーストロークと他のキーストロークの間の遅延を意味します。私はある種のゲームを作成しているので、この「機能」を取り除く必要があります。

これまでのところ、私はこの方法を見つけることができました:



[DllImport("user32.dll")]
static extern ushort GetAsyncKeyState(int vKey);

public static bool IsKeyPushedDown(Keys keyData)
{
   return 0 != (GetAsyncKeyState((int)keyData) & 0x8000);
}

しかし、メソッドIsKeyPushedDownは、関数を呼び出す瞬間にキーが押されたかどうかを検出します。そのため、キーが押されているかどうかをテストするためのループが必要です。問題は、それでもすべてのキーストロークをキャッチできないことです-ループが遅すぎると思います。

2番目の選択肢は、ProcessCmdKeyのオーバーライドです。


protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
  // processing keys
            if (keyData == Keys.Left || keyData == Keys.Right || keyData == Keys.Up || keyData == Keys.Down)
            {
                return true;
            }
            else
            {
                return base.ProcessCmdKey(ref msg, keyData);
            }

}

これは本当にうまく機能しますが、繰り返しの遅延の影響を受けるため、ゲーム内のモンスターの動きは次のようになります。

私の問題の解決策はありますか?ありがとう

編集:私は両方の手順を組み合わせることで問題を解決しました。しかし、それは非常に醜い解決策です。私はまだより良い解決策があることを願っています。

4

2 に答える 2

5

キーが押されてから離されるまでの間に何が起こるかをより細かく制御したい場合KeyDownKeyUpはなく、処理する必要があります。ProcessCmdKey

シナリオで絶対に簡単なことは、モンスターを動かすタイマーをフォームに設定することです。起動時にタイマーを有効にし(そして、モンスターの移動方法を示す何らかの変数またはdeltaXとdeltaYを設定し)、KeyDown起動時にタイマーを停止KeyUpします。

編集

例として(非常に必要最低限​​)

public class MyForm : Form
{
    private int deltaX;
    private int deltaY;

    private const int movementAmount = 10;

    private Timer movementTimer = new Timer();

    public MyForm()
    {
        movementTimer.Interval = 100; // make this whatever interval you'd like there to be in between movements

        movementTimer.Tick += new EventHandler(movementTimer_Tick);
    }

    void movementTimer_Tick(object sender, EventArgs e)
    {
        myMonster.Location = new Point(myMonster.X + deltaX, myMonster.Y + deltaY);
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);

        switch (e.KeyCode)
        {
            case Keys.Left:
                {
                    deltaX -=movementAmount;
                } break;
            case Keys.Right:
                {
                    deltaX += movementAmount;
                } break;
            case Keys.Up:
                {
                    deltaY -= movementAmount;
                } break;
            case Keys.Down:
                {
                    deltaY += movementAmount;
                } break;
        }

        UpdateTimer();
    }

    protected override void OnKeyUp(KeyEventArgs e)
    {
        base.OnKeyUp(e);

        switch (e.KeyCode)
        {
            case Keys.Left:
                {
                    deltaX += movementAmount;
                } break;
            case Keys.Right:
                {
                    deltaX -= movementAmount;
                } break;
            case Keys.Up:
                {
                    deltaY += movementAmount;
                } break;
            case Keys.Down:
                {
                    deltaY -= movementAmount;
                } break;
        }

        UpdateTimer();
    }

    private void UpdateTimer()
    {
        movementTimer.Enabled = deltaX != 0 || deltaY != 0;
    }
}
于 2009-07-23T15:36:23.807 に答える
0

私はタイマーとpInvokeが好きではありません。

WinFormsプログラムで、次のように不要なキーの繰り返しを解決しました

    List<Keys> cKeys = new List<Keys>() { Keys.Q, Keys.W, Keys.E, Keys.R,
       Keys.T, Keys.Y, Keys.U, Keys.I, Keys.O, Keys.P, 
       Keys.OemOpenBrackets, Keys.OemCloseBrackets };  // define relevant keys
  
    Keys keepc = Keys.IMENonconvert; // some key which is not relevant

    private void Form2_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode!=keepc) // repeater detect
        {
            keepc = e.KeyCode;
            if (cKeys.IndexOf(e.KeyCode) >= 0) // if relevant key..
            {
                // do press key action
            }
        }         
    }

    private void Form2_KeyUp(object sender, KeyEventArgs e)
    { 
        keepc = Keys.IMENonconvert; // reset the repeater detect
        if (cKeys.IndexOf(e.KeyCode) >= 0) // if relevant key..
        {
            // do release key action
        }
    }
于 2020-12-05T17:23:00.010 に答える