簡體   English   中英

如何在運行時移動游戲塊(控件)?

[英]How do I move a game piece(control) during runtime?

我正在用C#做一個Knights Tour游戲的簡單C#程序,這是我學習C#的全部方法。 我有一塊板子和一塊騎士,而騎士是一個定制的面板,上面有騎士的照片。

我正在嘗試做的是允許用戶在運行時單擊並拖動騎士部件控件(正是您可以在設計時移動控件的方式來放置它),但是由於任何原因,我都得到了一些非常不希望的結果。

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

您為什么不將Knights的位置設置為與Mouse_Move方法中的鼠標位置相同?

就像是:

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

顯然,您可以知道騎士最初被單擊的位置,並根據該增量平穩移動,而不會產生初始抖動,從而使其移動更好。

它繪制得太慢了,因為每次鼠標移動時都在移動面板。 這意味着表單需要多次重繪,而完整的表單重繪是昂貴的。

基本解決方案是-不要經常更改面板的位置。

我看到了兩種方法。

  1. 第一種方法很簡單,但看起來可能比較生澀。 不要畫所有的鼠標動作。 每第5個或您設置的任意數字繪制一次。 基本上保持一個在鼠標按下時設置為0的計數器,並且每次移動鼠標時,請檢查++ counter%n ==0。如果是,則進行實際繪制。 只需確保將鼠標也拉起即可。 或者,同樣有效的是,僅當一個鼠標移動距離先前位置x或y中一定數量的點時才繪制。

  2. 第二個想法比較復雜,但是應該是最快,最不容易做的事情。 鼠標移動時,請勿移動面板。 而是使面板消失,並將光標設置為顯示騎士的自定義光標。 向上移動鼠標,重置光標,移動面板並使之可見。 這應該盡可能快。

編輯

我將在這里進入隱喻的領域,只是為了了解一些事情。 動畫是C#的一個方面,但不是其功能之一。 (即,您可以實現它,但是並沒有太多的事情可以使您輕松完成,並且這不是一個簡單的關鍵功能。)所以……隱喻。

考慮一下您放置在屏幕上的控件,這些控件使您的董事會和騎士成為一堆緊緊塞進停車場的汽車。 您要做的就是從高高的直升機望着停車場。 每次移動組件時,您要告訴運行時要做的是完全從停車場上推開汽車,然后用起重機將其放置在新位置。 當我說“完整的表單重繪非常昂貴”時,這就是我要討論的范圍。

相反,您想從直升機上執行的操作是確定汽車正在神奇地改變位置。 無需使用推土機和起重機,只需將直升機視圖空白,為要查看的內容拍攝快照,然后一點一點地更改快照,直到看起來像您想要的樣子為止。 這就是第二個建議-不要立即強迫表單重新計算每個組件的外觀。 而是將動畫放在表單上方,並僅在完成后更改表單。

您要搜索的關鍵字是“ gdi +”(。NET圖形包)和動畫。 MouseMove不會受到傷害,Paint是您可能需要制作動畫的事件。 有很多地方可以找到,盡管如何在MouseDown / Move c#上繪制矩形可能是一個不錯的開始。

編輯#2

我有最后一個建議。 除制作任何動畫外,還可以使用此功能。 從功能上講,它可以單獨滿足您的要求,但可能不是您想要的。 跟蹤鼠標,並修改鼠標懸停在其上的面板的背景圖像。 在這種情況下,您將需要查看ImageList和諸如控件BackgroundImage簡單屬性。 即使您的動畫效果更好,這也可能很好。 您可以輕松地使用它來顯示“騎士不能移到這里”或“騎士已經移到這里”。 由於它是在更改您的組件而不是移動您的組件,因此這樣做的確很便宜,並且可以輕松跟上鼠標的移動。 暗示您想要的運動可能就足夠了,它將教您Winform的各個方面,這些方面比動畫和GDI +渲染更重要且更常用。

所有你需要的是:

    private int intCurMouseX, intCurMouseY;

    private void kpcKnight_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
                intCurMouseX = e.X;
                intCurMouseY = e.Y;
        }
    }

    private void kpcKnight_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            kpcKnight.Location = new Point(
                kpcKnight.Location.X + (e.X - intCurMouseX),
                kpcKnight.Location.Y + (e.Y - intCurMouseY));
        }
    }

.Net的透明度有點用詞不當。 背景只是成為父容器的顏色。 當控件與每個控件重疊時(就像將棋子拖到板上一樣),由於控件是矩形的,因此您會看到棋子的“背景”。 一種選擇是實際將PictureBox剪輯成不規則形狀。 這可以通過從GraphicsPath()創建Region(),然后將其分配給PictureBox的Region()屬性來實現。 一種簡單的方法是使用圖像左上角的任何顏色,並將其用作“遮罩”顏色。 接下來遍歷整個圖像,並僅將像素不是遮罩顏色的位置添加到GraphicsPath()。 在分配了Image()之后,只需要用PictureBox完成一次。 再次,此方法要求圖像的“背景”(不想保留的部分)都具有相同的顏色,並且該顏色也不應作為要保留的圖像的一部分出現在任何地方。 這是一個例子:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM