C# - 俄罗斯方块克隆 - 无法阻止箭头键组合正确响应

Dan*_*rip 4 c# keydown arrow-keys

我正在使用Visual C#2005编写一个俄罗斯方块游戏.这是我设计的最广泛的程序.

我创建了一个形状类和一个块类来控制不同俄罗斯方块的位置,移动和显示.我有每个形状的moveDown(),moveLeft()和moveRight()函数(和相应的canMoveDown(),canMoveLeft(),canMoveRight()布尔函数,验证它可以移动).这一切都很美妙.

我想使用向下,向右和向左箭头键让用户移动块,除了使用计时器使形状每隔几毫秒自动下降一行.

我正在使用KeyDown事件处理程序来检查用户何时按下向下,向左和向右箭头键.这不是那么难.问题是我想允许对角线运动,我希望它能够顺利运行.我已经尝试了一系列不同的方法来解决这个问题,并取得了不同程度的成功.但我不能说得对......

我最成功的方法是使用三个布尔变量来跟踪向下,向左和向右箭头键被按下的时间.我会在KeyDown事件中将布尔值设置为true,在KeyUp事件中将布尔值设置为false.在KeyDown事件中,我还将告诉块如何移动,使用布尔变量来检查当前正在按下哪个组合.除了一件事,它的效果非常好.

如果我按下其中一个箭头键并按住,然后按下第二个箭头键然后释放第二个键,该块将完全停止移动,而不是继续向第一个箭头键的方向移动,而第一个箭头键尚未释放然而.我认为这是因为第二个键触发了KeyDown事件,并且在释放时,KeyUp事件被触发,并且KeyDown事件完全停止触发,即使第一个键被触发.

我不能为我的生活找到一个满意的解决方案来解决这个问题.

任何帮助将不胜感激=)

BFr*_*ree 9

大多数游戏都不等​​待事件.他们在必要时轮询输入设备并采取相应的行动.事实上,如果你看过XNA,你会发现它们是你在更新例程中调用的Keyboard.GetState()方法(或Gamepad.GetState()),并且基于它更新你的游戏逻辑结果.使用Windows.Forms时,没有任何开箱即用的功能,但是你可以P/Invoke GetKeyBoardState()函数来利用它.这样做的好处是,您可以一次轮询多个键,因此您可以一次对多个按键做出反应.这是我在网上找到的一个简单的课程,有助于此:

http://sanity-free.org/17/obtaining_key_state_info_in_dotnet_csharp_getkeystate_implementation.html

为了演示,我写了一个简单的Windows应用程序,基本上根据键盘输入移动球.它使用我链接到的类来轮询键盘的状态.您会注意到,如果您一次按下两个键,它将对角移动.

首先,Ball.cs:

    public class Ball
    {
        private Brush brush;

        public float X { get; set; }
        public float Y { get; set; }
        public float DX { get; set; }
        public float DY { get; set; }
        public Color Color { get; set; }
        public float Size { get; set; }

        public void Draw(Graphics g)
        {
            if (this.brush == null)
            {
                this.brush = new SolidBrush(this.Color);
            }
            g.FillEllipse(this.brush, X, Y, Size, Size);
        }

        public void MoveRight()
        {
            this.X += DX;
        }

        public void MoveLeft()
        {
            this.X -= this.DX;
        }

        public void MoveUp()
        {
            this.Y -= this.DY;
        }

        public void MoveDown()
        {
            this.Y += this.DY;
        }
    }
Run Code Online (Sandbox Code Playgroud)

真的没什么特别的....

那么这是Form1代码:

    public partial class Form1 : Form
    {
        private Ball ball;
        private Timer timer;
        public Form1()
        {
            InitializeComponent();
            this.ball = new Ball
            {
                X = 10f,
                Y = 10f,
                DX = 2f,
                DY = 2f,
                Color = Color.Red,
                Size = 10f
            };
            this.timer = new Timer();
            timer.Interval = 20;
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            var left = KeyboardInfo.GetKeyState(Keys.Left);
            var right = KeyboardInfo.GetKeyState(Keys.Right);
            var up = KeyboardInfo.GetKeyState(Keys.Up);
            var down = KeyboardInfo.GetKeyState(Keys.Down);

            if (left.IsPressed)
            {
                ball.MoveLeft();
                this.Invalidate();
            }

            if (right.IsPressed)
            {
                ball.MoveRight();
                this.Invalidate();
            }

            if (up.IsPressed)
            {
                ball.MoveUp();
                this.Invalidate();
            }

            if (down.IsPressed)
            {
                ball.MoveDown();
                this.Invalidate();
            }


        }


        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (this.ball != null)
            {
                this.ball.Draw(e.Graphics);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

简单的小应用.只需创建一个球和一个计时器.每隔20毫秒,它会检查键盘状态,如果按下一个键,它会移动它并使其无效,以便重新绘制.