【问题标题】:C#: Moving Two Rectangles At The Same Time With Different KeysC#:使用不同的键同时移动两个矩形
【发布时间】:2017-02-01 23:12:05
【问题描述】:

我正在制作一个小程序,其中两个矩形围绕赛车轨道行驶。当我运行程序时,一切都按计划进行,我可以使用箭头键在轨道上移动矩形,另一个是 A、S、D、W。问题是,如果我用箭头键移动一个矩形并尝试按 D 将另一个矩形同时向右移动,用箭头键移动的矩形停止。目标是让他们能够同时移动。我该怎么办?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Race_Game
{
        public partial class Form1 : Form
        {
            private int x1 = 24;
            private int y1 = 16;
            private int size1 = 115;
            private int size2 = 50;
            private Rectangle _rect1;
            private int x2 = 24;
            private int y2 = 74;
            private int size3 = 115;
            private int size4 = 50;
            private Rectangle _rect2;

        public Form1()
        {
            InitializeComponent();
        }

        private void pictureBox1_Paint_1(object sender, PaintEventArgs e)
        {
            _rect1 = new Rectangle(x1, y1, size1, size2);
            e.Graphics.FillRectangle(Brushes.Red, _rect1);
            _rect2 = new Rectangle(x2, y2, size3, size4);
            e.Graphics.FillRectangle(Brushes.Black, _rect2);
        }

        private void pictureBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            this.KeyPreview = true;

            this.KeyDown += new KeyEventHandler(Form1_KeyDown);
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        { 
            if (e.KeyData == Keys.Right)
            {
                x1 += 15;
            }
            if (e.KeyData == Keys.Left)
            {
                x1 -= 15;
            }
            if (e.KeyData == Keys.Up)
            {
                y1 -= 15;
            }
            if (e.KeyData == Keys.Down)
            {
                y1 += 15;
            }
            if (e.KeyData == Keys.D)
            {
                x2 += 15;
            }
            if (e.KeyData == Keys.A)
            {
                x2 -= 15;
            }
            if (e.KeyData == Keys.W)
            {
                y2 -= 15;
            }
            if (e.KeyData == Keys.S)
            {
                y2 += 15;
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            pictureBox1.Invalidate();
        }
    }
}

Visual Studio 生成的设计代码:

namespace Race_Game
{
    partial class Form1
    {
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
        this.timer1 = new System.Windows.Forms.Timer(this.components);
        this.pictureBox1 = new System.Windows.Forms.PictureBox();
        ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
        this.SuspendLayout();
        // 
        // timer1
        // 
        this.timer1.Enabled = true;
        this.timer1.Interval = 1;
        this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
        // 
        // pictureBox1
        // 
        this.pictureBox1.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBox1.BackgroundImage")));
        this.pictureBox1.Location = new System.Drawing.Point(0, 0);
        this.pictureBox1.Name = "pictureBox1";
        this.pictureBox1.Size = new System.Drawing.Size(1944, 1066);
        this.pictureBox1.TabIndex = 0;
        this.pictureBox1.TabStop = false;
        this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint_1);
        this.pictureBox1.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.pictureBox1_PreviewKeyDown);
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(1916, 1053);
        this.Controls.Add(this.pictureBox1);
        this.Name = "Form1";
        this.Text = "Form1";
        this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
        this.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint_1);
        this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
        ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
        this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.Timer timer1;
    private System.Windows.Forms.PictureBox pictureBox1;
}

}

【问题讨论】:

  • 这是一个常见的设计问题。这个问题应该保持开放。
  • private Rectangle _rect1 = new Rectangle(); 不是必需的,因为Rectangle 是一个值类型,并且在绘制事件时它也会被覆盖。
  • 感谢您的提示,但它并没有解决问题:/ @ja72
  • 我知道。这不是一个解决方案,只是一个观察。
  • 与所问的问题完全不相关,但您可以考虑使用 switch 语句而不是所有那些 if/end if 条件。它使您的代码更易于阅读。

标签: c# .net winforms keydown


【解决方案1】:

我决定在按下键时分配速度,并在按下键时将速度归零。并将 x 和 y 坐标组合成 PointSize 对象。

您可以独立且连续地移动盒子。

public partial class Form1 : Form
{
    const int velocity = 15;
    Point position_A = new Point(24, 16);
    Point position_B = new Point(24, 74);
    Size size_A = new Size(115, 50);
    Size size_B = new Size(115, 50);
    Size velocity_A = new Size(0, 0);
    Size velocity_B = new Size(0, 0);

    public Rectangle Shape_A
    {
        get
        {
            return new Rectangle(position_A, size_A);
        }
    }
    public Rectangle Shape_B
    {
        get
        {
            return new Rectangle(position_B, size_B);
        }
    }
    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox1_Resize(object sender, EventArgs e)
    {
        pictureBox1.Refresh();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.FillRectangle(Brushes.Red, Shape_A);
        e.Graphics.FillRectangle(Brushes.Black, Shape_B);
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        this.position_A+=velocity_A;
        this.position_B+=velocity_B;
        pictureBox1.Refresh();
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        Debug.WriteLine($"KeyDown Code:{e.KeyCode}");
        switch (e.KeyCode)
        {
            case Keys.Up:
                this.velocity_A=new Size(velocity_A.Width, -velocity);
                break;
            case Keys.Down:
                this.velocity_A=new Size(velocity_A.Width, +velocity);
                break;
            case Keys.Left:
                this.velocity_A=new Size(-velocity, velocity_A.Height);
                break;
            case Keys.Right:
                this.velocity_A=new Size(+velocity, velocity_A.Height);
                break;
            case Keys.W:
                this.velocity_B=new Size(velocity_B.Width, -velocity);
                break;
            case Keys.S:
                this.velocity_B=new Size(velocity_B.Width, +velocity);
                break;
            case Keys.A:
                this.velocity_B=new Size(-velocity, velocity_B.Height);
                break;
            case Keys.D:
                this.velocity_B=new Size(+velocity, velocity_B.Height);
                break;
            case Keys.Escape:
                this.Close();
                break;
        }
        pictureBox1.Invalidate();
    }

    private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        switch (e.KeyCode)
        {
            case Keys.Up:
            case Keys.Down:
                this.velocity_A=new Size(velocity_A.Width, 0);
                break;
            case Keys.Right:
            case Keys.Left:
                this.velocity_A=new Size(0, velocity_A.Height);
                break;
            case Keys.W:
            case Keys.S:
                this.velocity_B=new Size(velocity_B.Width, 0);
                break;
            case Keys.A:
            case Keys.D:
                this.velocity_B=new Size(0, velocity_B.Height);
                break;
        }
    }
}

【讨论】:

  • 我试图看看是否可以绕过 get 语句,但为了安全起见,我决定冒险让我的代码与您的代码相同。此外,我认为我的问题措辞很奇怪,并且可能存在误解。例如,我的目标是能够按住 D 键并使黑色矩形向右移动,同时按住右箭头键并使红色矩形与黑色矩形同时向右移动。我可以再次检查以确保我拥有您所说的所有内容,但到目前为止,这似乎不起作用@ja72
  • 现在我明白问题所在了。从我上面修改过的代码中尝试这个新方法。
  • 谢谢!我理解这一点并且可以使用它,但是如果在矩形水平移动时按下向上箭头,我将如何制作它以便矩形不会沿对角线移动? @ja72
  • 例如将KeyDown 事件替换为this.velocity_A=new Size(0, +velocity);。因此,它不使用现有的 velocity_A 值,而是使用 0
【解决方案2】:

不要对按键事件做出反应,而是使用一个计时器,通过 WinAPI 函数GetKeyState 定期轮询各个按键的状态。

对于以下示例设置,我使用了一个带有两个 NumericUpDown 控件(“numericUpDownA”和“numericUpDownLeft”)和一个间隔为 100 毫秒并设置为启用的计时器“timerCheckKeyboard”的表单。 Timer 具有 OnClick 事件处理程序“timerCheckKeyboard_Tick”。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    [DllImport("USER32.dll")]
    static extern short GetKeyState(int nVirtKey);


    private const int KEY_PRESSED = 0x8000;

    private const int VK_W = (int)'W';
    private const int VK_A = (int)'A';
    private const int VK_S = (int)'S';
    private const int VK_D = (int)'D';
    private const int VK_LEFT = 0x25;
    private const int VK_UP = 0x26;
    private const int VK_RIGHT = 0x27;
    private const int VK_DOWN = 0x28;

    private bool IsKeyPressed(int key)
    {
        return (GetKeyState(key) & KEY_PRESSED) != 0;
    }

    private void timerCheckKeyboard_Tick(object sender, EventArgs e)
    {
        if (IsKeyPressed(VK_A))
        {
            numericUpDownA.Value++;
        }

        if (IsKeyPressed(VK_LEFT))
        {
            numericUpDownLeft.Value++;
        }
    }
}

按下 A 键时,NumericUpDownA 控件中的值会增加。按下 Cursor Left 键时,NumericUpDownLeft 控件中的值会增加。 您可以同时按“A”和“向左光标”,两个 NumericUpDown 控件中的值都会增加。


请注意,当您的应用程序未处于活动状态时按下按键时,这甚至会起作用。因此,您可能希望首先在 Timer-Tick-Event 中对其进行测试,或者在表单没有焦点时完全禁用计时器。 (事件ActivateDeactivate 的表单)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多