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 方法会在调用函数的那一刻确定是否按下了键 - 所以我需要一个循环来测试键是否按下。问题是它仍然不能捕获所有击键 - 我猜我的循环太慢了。

第二个选择是覆盖 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 回答