C# 如何在运行时移动游戏块(控件)?

C# 如何在运行时移动游戏块(控件)?,c#,C#,我正在做一个简单的C#程序的游戏骑士巡回赛在C#艰难的方式学习所有我能的C#。我有一个棋盘和一个骑士棋子,骑士是一个定制面板,上面有骑士的照片 我试图做的是允许用户在运行时单击并拖动knight piece控件(与您在设计时移动控件放置控件的方式完全相同),但无论出于何种原因,我都会得到一些非常不希望的结果 private void KTmain_Load(object sender, EventArgs e) { boolKnightmoves = false;

我正在做一个简单的C#程序的游戏骑士巡回赛在C#艰难的方式学习所有我能的C#。我有一个棋盘和一个骑士棋子,骑士是一个定制面板,上面有骑士的照片

我试图做的是允许用户在运行时单击并拖动knight piece控件(与您在设计时移动控件放置控件的方式完全相同),但无论出于何种原因,我都会得到一些非常不希望的结果

    private void KTmain_Load(object sender, EventArgs e)
    {
        boolKnightmoves = false;
    }

    private void kpcKnight_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        switch (e.Button)
        {
            case MouseButtons.Left:
                boolKnightmoves = true;

                intCurMouseX = e.X;
                intCurMouseY = e.Y;

                break;
            case MouseButtons.Right:

            case MouseButtons.Middle:

            case MouseButtons.XButton1:

            case MouseButtons.XButton2:

            case MouseButtons.None:
            default:
                boolKnightmoves = false;
                break;
        }
    }

    private void kpcKnight_MouseUp(object sender, MouseEventArgs e)
    {
        switch (e.Button)
        {
            case MouseButtons.Left:
                boolKnightmoves = false;
                break;
            case MouseButtons.Right:

            case MouseButtons.Middle:

            case MouseButtons.XButton1:

            case MouseButtons.XButton2:

            case MouseButtons.None:
            default:
                boolKnightmoves = false;
                break;
        }
    }

    private void kpcKnight_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        if (boolKnightmoves)
        {                
            txtTest.Text = e.X + ", " + e.Y;
            txtTest.Text += Environment.NewLine + kpcKnight.Location;

            int i = e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1;
            int j = e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1;

            txtTest.Text += Environment.NewLine + i.ToString() + ", " + j.ToString();

            kpcKnight.Location = new Point(
                 kpcKnight.Location.X + i,
                 kpcKnight.Location.Y + j);//e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1);
                                            //e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1,
            intCurMouseX = e.X;
            intCurMouseY = e.Y;
        }
    }

    private void kpcKnight_MouseLeave(object sender, EventArgs e)
    {
        boolKnightmoves = false;
    }

    private void kpcKnight_LocationChanged(object sender, EventArgs e)
    {
        kpcKnight.Refresh();
    }
我看不出这段代码不做同样事情的真正原因,但我显然遗漏了一些东西。当我点击骑士并移动它时,它的移动速度与鼠标的移动速度不同,它的移动速度要慢得多。当移动到你看不见的地方时,它也会褪色

我如何使骑士棋子以与窗体设计器中相同的方式移动,使棋子在棋盘上移动更有意义

任何协助都将不胜感激


我对代码进行了一点更新,看起来确实有所帮助,但动画方面仍然很不稳定,面板在移动和放置时会拾取一些背景

它是如何在表单设计器中如此顺利地完成的

    private void kpcKnight_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        if (boolKnightmoves)
        {                
            txtTest.Text = e.X + ", " + e.Y;
            txtTest.Text += Environment.NewLine + kpcKnight.Location;

            int x = kpcKnight.Location.X + e.X - intCurMouseX;
            int y = kpcKnight.Location.Y + e.Y - intCurMouseY;

            kpcKnight.Location = new Point(x, y);
            kpcKnight.Refresh();
            /*
            int i = e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1;
            int j = e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1;

            txtTest.Text += Environment.NewLine + i.ToString() + ", " + j.ToString();

            kpcKnight.Location = new Point(
                 kpcKnight.Location.X + i,
                 kpcKnight.Location.Y + j);//e.Y == intCurMouseY ? 0 : e.Y > intCurMouseY ? 1 : -1);
                                            //e.X == intCurMouseX ? 0 : e.X > intCurMouseX ? 1 : -1,
            intCurMouseX = e.X;
            intCurMouseY = e.Y;*/
        }
    }

你为什么不把骑士的位置设置为鼠标移动法中的鼠标位置呢

比如:

kpcKnight.Location = new Point(e.X, e.Y)

显然,你可以通过知道骑士最初被点击的位置来让它移动得更好,并根据这个增量平滑地移动,而不会有最初的抖动

你为什么不把骑士的位置设置为鼠标移动法中的鼠标位置

比如:

kpcKnight.Location = new Point(e.X, e.Y)

显然,你可以通过知道骑士最初被点击的位置来让它移动得更好,并根据这个增量平滑地移动,而不会有最初的抖动

它的绘制速度非常慢,因为每次鼠标移动都会移动面板。这意味着表单本身需要多次重画,而一个完整的表单重画代价高昂

基本的解决方案是——不要经常改变面板的位置

我看到两种方法

  • 第一种方法很简单,但可能看起来很不自然。不要画每一个鼠标移动。每五个一画一次,或者任意设置一个数字。基本上,在鼠标按下时保持一个设置为0的计数器,每次鼠标移动时,检查++计数器%n==0。如果是,请绘制实际图形。也要确保画上鼠标。或者,同样有效的是,仅当一次鼠标移动距离上一个位置x或y上的点数达到一定数量时才进行绘制

  • 第二个想法更复杂,但应该是你能做的最快、最不急促的事情。鼠标移动时,不要移动面板。相反,使面板消失,并将光标设置为显示骑士的自定义光标。鼠标向上移动时,重置光标,移动面板并使其可见。这应该是最快的速度了

  • 编辑 我将进入隐喻的领域,只是为了让大家明白一些事情。动画是C#的一个方面,但它不是C#的特征之一。(也就是说,你可以完成它,但它没有太多让这些事情对你来说很容易,而且它不是一个简单的关键特性。)所以。。。隐喻

    想象一下,你在屏幕上放置的控件,使你的棋盘和骑士像一堆汽车紧紧地挤在停车场里。你所做的就是从高空的直升机上看停车场。每次移动组件时,您都会告诉运行时要做的是将车辆完全推离停车场,然后用起重机将其放置在新位置。当我说“一个完整的表单重画是昂贵的”时,这就是我所说的范围

    相反,你想从直升机上看到的是,汽车正在神奇地改变位置。不要用推土机和起重机,只需清空直升机视图,拍下你想看到的快照,然后一点一点地更改快照,直到它看起来像你想要的样子。这就是第二个建议——不要强迫表单重新计算每个组件的外观。相反,将动画置于窗体上方,并且仅在完成后更改窗体

    要搜索的关键字是“gdi+”(.NET图形包)和动画。MouseMove不会造成伤害,而Paint是您可能需要制作动画的事件。你可以找到很多地方,不过这可能是一个好的开始

    编辑#2
    我还有最后一个建议。除了制作任何动画外,还可以使用此选项。在功能上,它本身就满足了您的需求,但它可能不是您想要的。跟踪鼠标,并修改鼠标悬停在任何面板上的背景图像。在这种情况下,您需要查看
    ImageList
    ,以及控件
    BackgroundImage
    等简单属性。这可能很好,即使你有一个更好的动画工作。你可以很容易地用它来显示“骑士不能在这里移动”或“骑士已经在这里移动了”。因为它改变了你的组件而不是移动你的组件,这样做非常便宜,并且可以很容易地跟上你的鼠标移动。这可能足以暗示您想要的移动,并且它将教会您winforms的一些方面,这些方面比动画和GDI+渲染更重要和更常用。

    它的绘制速度非常慢,因为每次鼠标移动都会移动面板。这意味着表单本身需要多次重画,而一个完整的表单重画代价高昂

    基本的解决方案是——不要经常改变面板的位置

    我看到两种方法

  • 第一种方法很简单,但可能看起来很不自然。不要画每一个鼠标移动。每五个一画一次,或者任意设置一个数字。基本上保持一个计数器,在鼠标按下时将其设置为0,每次获得mou时
        private void Form1_Load(object sender, EventArgs e)
        {
            // perform this for all your PictureBox pieces:
            this.ClipPictureBoxPiece(this.kpcKnight);
            // ...
            // ...
        }
    
        private void ClipPictureBoxPiece(PictureBox pb)
        {
            if (pb != null && pb.Image != null)
            {
                System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();
                using (Bitmap bmp = new Bitmap(pb.Image))
                {
                    Color mask = bmp.GetPixel(0, 0);
                    for (int x = 0; x < bmp.Width; x++)
                    {
                        for (int y = 0; y < bmp.Height; y++)
                        {
                            if (!bmp.GetPixel(x, y).Equals(mask))
                            {
                                gp.AddRectangle(new Rectangle(x, y, 1, 1));
                            }
                        }
                    }
                }
                pb.Region = new Region(gp);
            }
        }