【问题标题】:I can't get my image to move, using keydown events [duplicate]我无法使用keydown事件移动我的图像[重复]
【发布时间】:2013-10-07 22:04:42
【问题描述】:

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

这是我的课程:

表格1:

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

游戏管理器:

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

猫:

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)
        {

        }
    }
}

可移动:

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

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

Picturebox1 没有 keydown 事件,而 form1 有。我还需要在 cat 类中使用 keydown 事件,这样它就知道它面对的方向,所以它知道要移动的方向。

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

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

【问题讨论】:

  • 对于这个问题here,您已有 2 个答案。我将此标记为重复。
  • @Brian 它看起来确实像另一个问题问“为什么它不动”,而不是“我如何识别键盘事件?”

标签: c# windows winforms 2d picturebox


【解决方案1】:

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

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

引发事件时调用的方法如下所示:

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

【讨论】:

  • 我必须按照老师的指示使用 windows 窗体进行游戏。如果我在 form1 中使用 keydown 事件,我将如何获得猫的前进方向?
  • 会有一些事件参数传递给事件发生时调用的方法,我相信它们是KeydownEventArgs,它们将包含一个存储按下字符的变量。我会尽快更新答案,提供更多相关信息
  • private void Form1_KeyDown(object sender, 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; }
  • 这也可以,但是如果您打算拥有多个控件(例如,可能是一个按钮来打开库存,或者一个重新启动,或者一个执行其他操作),您可能想要使用switch 语句,因为它们更容易阅读并且更适合多个选项。
【解决方案2】:
  • @XtrmJosh 是对的,XNA 更适合这样的任务

  • 您最好在https://gamedev.stackexchange.com/ 中提出此类问题,而不是在 SO,这是关于游戏开发问题的地方

  • 让你的猫移动到ProcessCmdKey,而不是使用Control.KeyDown,它在该控件具有焦点时才会捕获它们。

代码:

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);
    }
}
  • 你什么时候挂钩到 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
    }
    
  • 在同一滴答声事件中,您正在移动物体,但您没有绘制它们

  • 使用Cat.Move(int n) 移动你的猫,Cat.KeyDown无关,除非 Cat 是 Control(它永远不会被调用)。但是把这个逻辑放在 ProcessCmdKey 中。考虑使用Keys 而不是整数。而其他的'if'应该是'else if'。 (请参阅 switch,因为它不太容易出错)

代码:

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

【讨论】:

  • 关于焦点的有效点,但如果游戏不包含按钮和框等,我想我的方法会起作用。正输入,+'d。
  • 对于 OPs 参考,焦点意味着如果你点击一个按钮,那么那个按钮就会变成焦点。这意味着您通常传递给表单的事件(例如按键事件)将被发送到按钮对象,而不是表单对象。结果是没有为表单引发事件,因此使用我的方法,您需要为表单上的每个控件创建事件,以防它被选中。
  • 另外,尽量不要过多地为 OP 辩护,但是哦,他正在使用的代码与游戏开发没有太大关系,所以我觉得他在这里得到回应的机会比他会在游戏开发上。主要是因为他们几乎只会说出我们暗示的内容(使用 XNA)
  • 是的,我同意你的看法 :-)
【解决方案3】:

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

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

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

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

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

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

【讨论】:

  • 实际上 keydown 事件似乎也直接链接到 cat 对象,这意味着除非 cat 继承自基于 GUI 的对象,否则无法调用(我认为,至少!)
  • 对此进行了编辑。我的错。
  • 好的,所以我有 Cat cat1 = new Cat();和 KeyDown += cat1.cat1_KeyDown;在公共 Form1() 中,我使用密钥代码制作了 cat1_KeyDown 。但什么都没有动!
  • 您是否更新了 GameManager 中的“绘画”以使用 cat1 的位置?
  • 我有 g.DrawImage(imgCat.Images[0], ca1.getLocation());
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多