[英]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)
顯然,您可以知道騎士最初被單擊的位置,並根據該增量平穩移動,而不會產生初始抖動,從而使其移動更好。
它繪制得太慢了,因為每次鼠標移動時都在移動面板。 這意味着表單需要多次重繪,而完整的表單重繪是昂貴的。
基本解決方案是-不要經常更改面板的位置。
我看到了兩種方法。
第一種方法很簡單,但看起來可能比較生澀。 不要畫所有的鼠標動作。 每第5個或您設置的任意數字繪制一次。 基本上保持一個在鼠標按下時設置為0的計數器,並且每次移動鼠標時,請檢查++ counter%n ==0。如果是,則進行實際繪制。 只需確保將鼠標也拉起即可。 或者,同樣有效的是,僅當一個鼠標移動距離先前位置x或y中一定數量的點時才繪制。
第二個想法比較復雜,但是應該是最快,最不容易做的事情。 鼠標移動時,請勿移動面板。 而是使面板消失,並將光標設置為顯示騎士的自定義光標。 向上移動鼠標,重置光標,移動面板並使之可見。 這應該盡可能快。
我將在這里進入隱喻的領域,只是為了了解一些事情。 動畫是C#的一個方面,但不是其功能之一。 (即,您可以實現它,但是並沒有太多的事情可以使您輕松完成,並且這不是一個簡單的關鍵功能。)所以……隱喻。
考慮一下您放置在屏幕上的控件,這些控件使您的董事會和騎士成為一堆緊緊塞進停車場的汽車。 您要做的就是從高高的直升機望着停車場。 每次移動組件時,您要告訴運行時要做的是完全從停車場上推開汽車,然后用起重機將其放置在新位置。 當我說“完整的表單重繪非常昂貴”時,這就是我要討論的范圍。
相反,您想從直升機上執行的操作是確定汽車正在神奇地改變位置。 無需使用推土機和起重機,只需將直升機視圖空白,為要查看的內容拍攝快照,然后一點一點地更改快照,直到看起來像您想要的樣子為止。 這就是第二個建議-不要立即強迫表單重新計算每個組件的外觀。 而是將動畫放在表單上方,並僅在完成后更改表單。
您要搜索的關鍵字是“ gdi +”(。NET圖形包)和動畫。 MouseMove不會受到傷害,Paint是您可能需要制作動畫的事件。 有很多地方可以找到,盡管如何在MouseDown / Move c#上繪制矩形可能是一個不錯的開始。
我有最后一個建議。 除制作任何動畫外,還可以使用此功能。 從功能上講,它可以單獨滿足您的要求,但可能不是您想要的。 跟蹤鼠標,並修改鼠標懸停在其上的面板的背景圖像。 在這種情況下,您將需要查看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.