简体   繁体   English

C#:使用不同的键同时移动两个矩形

[英]C#: Moving Two Rectangles At The Same Time With Different Keys

I am making a little program where two rectangles drive around a race car track. 我正在制作一个小程序,其中两个矩形围绕赛车轨道行驶。 When I run the program everything goes as planned and I can move the rectangles around the track using the arrow keys for one and A, S, D, W for the other. 当我运行程序时,一切都按计划进行,我可以使用一个箭头键和另一个A,S,D,W移动轨道周围的矩形。 The problem is that I if I am moving one with the arrow keys and I try to press D to move the other rectangle to the right at the same time, the one moving with the arrow keys stops. 问题是,如果我用箭头键移动一个,我试着按D同时向右移动另一个矩形,用箭头键移动的那个停止。 The goal is to have them be able to move concurrently. 目标是让他们能够同时移动。 What should I do? 我该怎么办?

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 Generated Design Code: 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;
}

} }

What I decided to do is on key-down to assign a velocity, and on key-up to zero the velocity. 我决定做的是按下键来分配速度,然后按键上升到零速度。 That and to combine the x and y coordinates into Point and Size objects. 那并将x和y坐标组合成PointSize对象。

You can do move the boxes independently and continuously. 您可以独立且连续地移动框。

SCR

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;
        }
    }
}

Instead of reacting to keypress events, use a timer that polls the state of the individual keys regularly via the WinAPI function GetKeyState . 而不是对按键事件做出反应,使用定时器通过WinAPI函数GetKeyState定期轮询各个键的状态。

For the following example setup, I use a form with two NumericUpDown controls ("numericUpDownA" and "numericUpDownLeft") and a Timer "timerCheckKeyboard" with interval 100ms and set to enabled. 对于以下示例设置,我使用具有两个NumericUpDown控件(“numericUpDownA”和“numericUpDownLeft”)和Timer“timerCheckKeyboard”的表单,间隔为100ms并设置为启用。 The Timer has the OnClick event handler "timerCheckKeyboard_Tick". 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++;
        }
    }
}

The value in the NumericUpDownA control increases while the A key is pressed. 按下A键时,NumericUpDownA控件中的值会增加。 The value in the NumericUpDownLeft control increases while the Cursor Left key is pressed. 按下Cursor Left键时,NumericUpDownLeft控件中的值会增加。 You can press "A" and "Cursor left" at the same time and the values in both NumericUpDown controls increase. 您可以同时按“A”和“向左光标”,两个NumericUpDown控件中的值都会增加。


Note that this will even work when the keys are pressed while your application is not the active one. 请注意,当您的应用程序不是活动应用程序时按下键时,这甚至可以工作。 So, you might want to test that first in the Timer-Tick-Event or disable the timer altogether while the form doesn't have the focus. 因此,您可能希望在Timer-Tick-Event中首先测试它,或者在表单没有焦点时完全禁用计时器。 (Events Activate , Deactivate of the form). (事件ActivateDeactivate表单)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM