我无法使用keydown事件移动我的图像[重复]

时间:2021-01-30 00:24:16

This question already has an answer here:

这个问题在这里已有答案:

I am making a 2d top-down game where the player controls a cat. To do this, the person uses the WASD keys to move. I have Form1, GameManager, Cat, and Moveable classes. Form1 sends GameManager the cat imagelist and e.graphics (for the picturebox). GameManager has a timer and each tick checks to see if the cat has moved. Cat handles the move logic. When I run the program, the cat sprite shows up at its initial position, but does not move upon pressing a key. I can't figure out my issue, could somebody please help?

我正在制作一个2D自上而下的游戏,玩家控制着一只猫。为此,此人使用WASD键移动。我有Form1,GameManager,Cat和Moveable类。 Form1向GameManager发送cat imagelist和e.graphics(用于图片框)。 GameManager有一个计时器,每个勾选检查猫是否已经移动。 Cat处理移动逻辑。当我运行程序时,cat精灵显示在其初始位置,但是在按下键时不会移动。我无法弄清楚我的问题,有人可以帮忙吗?

Here are my classes:

这是我的课程:

Form1:

Form1中:

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

namespace CatAndMouse
{
    public partial class Form1 : Form
    {
        GameManager myGM = new GameManager();
        public Form1()
        {
            InitializeComponent();
            newGame();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (this.myGM != null)
                this.myGM.paint(e.Graphics);
        }

        public void newGame()
        {
            myGM.newGame(imgCat);
        }
    }
}

GameManager:

游戏管理:

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

namespace CatAndMouse
{
    class GameManager
    {
        Cat ca1 = new Cat();
        int amount = 5;
        Timer time = new Timer();
        public ImageList imgCat = new ImageList();

        public void newGame(ImageList cat)
        {
            imgCat = cat;
            time.Start();
        }

        public void move()
        {
            ca1.Move(amount);
        }

        public void paint(Graphics g)
        {
            g.DrawImage(imgCat.Images[0], ca1.getLocation());
        }

        private void time_Tick(object sender, EventArgs e)
        {
            move();
        }
    }
}

Cat:

猫:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace CatAndMouse
{
    class Cat: Moveable
    {
        Random myCLoc = new Random();
        private Moveable myCatMove;
        public Point p = new Point(100, 100);
        int dir = 0;

        public void Move(int n)
        {
            if (dir == 0)
            {
                p.Y = p.Y - n;
            }
            if (dir == 1)
            {
                p.X = p.X + n;
            }
            if (dir == 2)
            {
                p.Y = p.Y + n;
            }
            if (dir == 3)
            {
                p.X = p.X - n;
            }
        }
        private void KeyDown(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up)
            {
                dir = 0;
            }
            if (e.KeyCode == Keys.Right)
            {
                dir = 1;
            }
            if (e.KeyCode == Keys.Down)
            {
                dir = 2;
            }
            if (e.KeyCode == Keys.Left)
            {
                dir = 3;
            }
        }
        public void changeDirection()
        {

        }

        public Point getLocation()
        {
            return p;
        }

        public void paint(PaintEventArgs e)
        {

        }
    }
}

Moveable:

活动:

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

namespace CatAndMouse
{
    public interface Moveable
    {
        void Move(int n);
        void changeDirection();
        //Point getLocation();
        void paint(PaintEventArgs e);
    }
}

So, I don't have anything calling KeyDown(). How do I make something call KeyDown() if it needs KeyEventArgs e?

所以,我没有任何调用KeyDown()的东西。如果需要KeyEventArgs e,如何调用KeyDown()?

Picturebox1 does not have a keydown event, form1 does. I also need to use the keydown event in the cat class so it knows what direction it is facing, so it knows what direction to move.

Picturebox1没有keydown事件,form1也没有。我还需要在cat类中使用keydown事件,因此它知道它面向的方向,因此它知道要移动的方向。

This question DOES NOT have an answer in the other question. That one tells me to fix the keydown event, here I am ask HOW to fix the keydown event!

这个问题在另一个问题上没有答案。那个告诉我修复keydown事件,在这里我要问如何修复keydown事件!

I REALLY NEED HELP WITH PAINTING THE IMAGE!

我真的需要帮助绘制图像!

3 个解决方案

#1


0  

I think your problem is a misunderstanding of the event mechanism. You appear to have made an event handler for the 'KeyDown' event but not attached it to the event itself.

我认为你的问题是对事件机制的误解。您似乎已为“KeyDown”事件创建了事件处理程序,但未将其附加到事件本身。

You need to add the attachment code to the event, like so:

您需要将附件代码添加到事件中,如下所示:

Cat cat1 = new Cat();
KeyDown += cat1.cat1_KeyDown;

This could be done in the constructor of the form1 class.

这可以在form1类的构造函数中完成。

You then need to modify the parameters of the event handler in the Cat class to match the event handler signature. e.g.

然后,您需要修改Cat类中事件处理程序的参数以匹配事件处理程序签名。例如

public void cat1_KeyDown(object sender, KeyEventArgs e)
{
    // Do the movement logic here....
}

#2


1  

Is there any reason you're using Windows Forms for a game, as opposed to using XNA or something? It would be more appropriate, and it would make this task a LOT easier.

您是否有任何理由将Windows窗体用于游戏,而不是使用XNA或其他东西?它会更合适,它会使这项任务变得更容易。

Regarding the question itself, you need to call the forms paint event after moving, and to hook keyboard input you should have an event for the form itself (go to form view, click the lightning bolt in the properties window, look for Keydown). Utilizing this event should allow you to get the output you want.

关于问题本身,您需要在移动后调用表单绘制事件,并且要挂钩键盘输入,您应该有一个表单本身的事件(转到表单视图,单击属性窗口中的闪电,查找Keydown)。利用此事件可以让您获得所需的输出。

The method which is called when the event is raised will look a little like this:

引发事件时调用的方法看起来有点像这样:

public void KeyPressed(object sender, KeyPressEventArgs ex)
{
    switch (ex.KeyChar) // Get the value of the key pressed
    {
        case 'a':
            // Do stuff if the pressed key is the letter "a"
        case 'b':
            // Do stuff if the pressed key is the letter "b"
    }
}

#3


1  

  • @XtrmJosh is right, XNA would be more appropriate for such task

    @XtrmJosh是对的,XNA会更适合这样的任务

  • You are better off asking such questions in https://gamedev.stackexchange.com/ than in SO, it is the place about game development questions

    你最好在https://gamedev.stackexchange.com/上询问这些问题,而不是在SO中,它是关于游戏开发问题的地方

  • Make your cat move in ProcessCmdKey instead, events will be always caught as opposed to using Control.KeyDown which catches them only if that control has the focus.

    让您的cat在ProcessCmdKey中移动,事件将始终被捕获,而不是使用仅在该控件具有焦点时捕获它们的Control.KeyDown。

Code :

代码:

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

    private void Form1_Load(object sender, EventArgs e)
    {
    }

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        // Move your cat here
        return base.ProcessCmdKey(ref msg, keyData);
    }
}
  • When are you hooking to your timer tick event in GameManager ?

    你什么时候在GameManager中挂钩你的计时器嘀嗒事件?

    private void Form1_Load(object sender, EventArgs e)
    {
        Timer timer = new Timer();
        timer.Tick += timer_Tick;
    }
    
    void timer_Tick(object sender, EventArgs e)
    {
        // Do your thing
    }
    
  • In that same tick event you are moving things but you don't draw them.

    在同一个刻度事件中,你正在移动东西,但你不会绘制它们。

  • Use Cat.Move(int n) to move your cat, the Cat.KeyDown is irrelevant unless Cat is a Control (it will never get called). But put that logic in the ProcessCmdKey instead. Consider using Keys rather than an integer. And the others 'if' should be 'else if'. (see switch instead as it's less error-prone)

    使用Cat.Move(int n)来移动你的猫,Cat.KeyDown是无关紧要的,除非Cat是一个Control(它永远不会被调用)。但是将该逻辑放在ProcessCmdKey中。考虑使用Keys而不是整数。而其他人'如果'应该是'否则,如果'。 (请参阅开关,因为它不易出错)

Code :

代码:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    // Move your Cat here
    switch (keyData)
    {
        case Keys.Left:
            cat.Move(keyData);
            break;
        case Keys.Right:
            break;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

public class Cat
{
    public void Move(Keys keyData)
    {
        switch (keyData)
        {
            case Keys.Left:
                // act accordingly ...
                break;
            case Keys.Right:
                break;
        }
    }
}

#1


0  

I think your problem is a misunderstanding of the event mechanism. You appear to have made an event handler for the 'KeyDown' event but not attached it to the event itself.

我认为你的问题是对事件机制的误解。您似乎已为“KeyDown”事件创建了事件处理程序,但未将其附加到事件本身。

You need to add the attachment code to the event, like so:

您需要将附件代码添加到事件中,如下所示:

Cat cat1 = new Cat();
KeyDown += cat1.cat1_KeyDown;

This could be done in the constructor of the form1 class.

这可以在form1类的构造函数中完成。

You then need to modify the parameters of the event handler in the Cat class to match the event handler signature. e.g.

然后,您需要修改Cat类中事件处理程序的参数以匹配事件处理程序签名。例如

public void cat1_KeyDown(object sender, KeyEventArgs e)
{
    // Do the movement logic here....
}

#2


1  

Is there any reason you're using Windows Forms for a game, as opposed to using XNA or something? It would be more appropriate, and it would make this task a LOT easier.

您是否有任何理由将Windows窗体用于游戏,而不是使用XNA或其他东西?它会更合适,它会使这项任务变得更容易。

Regarding the question itself, you need to call the forms paint event after moving, and to hook keyboard input you should have an event for the form itself (go to form view, click the lightning bolt in the properties window, look for Keydown). Utilizing this event should allow you to get the output you want.

关于问题本身,您需要在移动后调用表单绘制事件,并且要挂钩键盘输入,您应该有一个表单本身的事件(转到表单视图,单击属性窗口中的闪电,查找Keydown)。利用此事件可以让您获得所需的输出。

The method which is called when the event is raised will look a little like this:

引发事件时调用的方法看起来有点像这样:

public void KeyPressed(object sender, KeyPressEventArgs ex)
{
    switch (ex.KeyChar) // Get the value of the key pressed
    {
        case 'a':
            // Do stuff if the pressed key is the letter "a"
        case 'b':
            // Do stuff if the pressed key is the letter "b"
    }
}

#3


1  

  • @XtrmJosh is right, XNA would be more appropriate for such task

    @XtrmJosh是对的,XNA会更适合这样的任务

  • You are better off asking such questions in https://gamedev.stackexchange.com/ than in SO, it is the place about game development questions

    你最好在https://gamedev.stackexchange.com/上询问这些问题,而不是在SO中,它是关于游戏开发问题的地方

  • Make your cat move in ProcessCmdKey instead, events will be always caught as opposed to using Control.KeyDown which catches them only if that control has the focus.

    让您的cat在ProcessCmdKey中移动,事件将始终被捕获,而不是使用仅在该控件具有焦点时捕获它们的Control.KeyDown。

Code :

代码:

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

    private void Form1_Load(object sender, EventArgs e)
    {
    }

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        // Move your cat here
        return base.ProcessCmdKey(ref msg, keyData);
    }
}
  • When are you hooking to your timer tick event in GameManager ?

    你什么时候在GameManager中挂钩你的计时器嘀嗒事件?

    private void Form1_Load(object sender, EventArgs e)
    {
        Timer timer = new Timer();
        timer.Tick += timer_Tick;
    }
    
    void timer_Tick(object sender, EventArgs e)
    {
        // Do your thing
    }
    
  • In that same tick event you are moving things but you don't draw them.

    在同一个刻度事件中,你正在移动东西,但你不会绘制它们。

  • Use Cat.Move(int n) to move your cat, the Cat.KeyDown is irrelevant unless Cat is a Control (it will never get called). But put that logic in the ProcessCmdKey instead. Consider using Keys rather than an integer. And the others 'if' should be 'else if'. (see switch instead as it's less error-prone)

    使用Cat.Move(int n)来移动你的猫,Cat.KeyDown是无关紧要的,除非Cat是一个Control(它永远不会被调用)。但是将该逻辑放在ProcessCmdKey中。考虑使用Keys而不是整数。而其他人'如果'应该是'否则,如果'。 (请参阅开关,因为它不易出错)

Code :

代码:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    // Move your Cat here
    switch (keyData)
    {
        case Keys.Left:
            cat.Move(keyData);
            break;
        case Keys.Right:
            break;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

public class Cat
{
    public void Move(Keys keyData)
    {
        switch (keyData)
        {
            case Keys.Left:
                // act accordingly ...
                break;
            case Keys.Right:
                break;
        }
    }
}