您好,登錄后才能下訂單哦!
這篇“基于WPF如何實現經典紙牌游戲”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“基于WPF如何實現經典紙牌游戲”文章吧。
之所以產生這個無聊至極的念頭,是因為發現Unicode中竟然有這種字符。
這就意味著不用任何資源就可以實現一些紙牌游戲,效果如下圖所示
這就意味著不用任何資源就可以實現一些紙牌游戲,效果如下圖所示
#region 常量 private static readonly Dictionary<string, string[]> CardNames = new Dictionary<string, string[]>{ {"Spade", new string[13]{"????","????","????","????","????","????","????","????","????","????","????","????","????" } }, {"Heart", new string[13]{"????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????" } }, {"Diamond", new string[13]{"????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????" } }, {"Club" , new string[13]{"????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", "????"}} }; #endregion #region 卡牌類型 private class Card { public Card(string name, int number, string type, bool red, int index) { Name =name; Number = number; Type = type; Red = red; Index = index; } public int Index; public string Name; public int Number; public bool Red; public string Type; public int Region; } #endregion
在實現了紙牌類之后,將每個紙牌放到一個Button的Tag中,然后再 為Button添加各種事件,就能實現這個游戲了。
由于是動態布局,所以建議使用Canvas,xaml界面十分簡潔,除了一個刷新按鈕,剩下的就只有畫布了。
<StackPanel> <ToolBar DockPanel.Dock="Top" Margin="0 0 0 20"> <Button Content="????" Click="btnUpdate_Click"/> </ToolBar> <Canvas x:Name="cvMain" Height="400"/> </StackPanel>
經典紙牌游戲大致可以分為12個區域,如圖所示
這些個區域就可決定紙牌的位置,所以需要一個用來存放區間信息的變量
private List<int>[] cardIndex;
cardIndex是由12個List<int>組成的數組,然后每個Button的位置用下面的方式來設定
private void setBtnPosition(Button btn, int region) { Canvas.SetLeft(btn, region % 6 * dw); Canvas.SetTop(btn, region / 6 * dh); Canvas.SetZIndex(btn, cardIndex[region].Count); }
其中,SetLeft即控件據Canvas左端的距離,可以理解為x坐標;dw,dh為全局變量,用來存放每個區間的尺寸。SetTop對應的為y坐標。SetZIndex表示層級關系,值越大則越在上面。
初始化需要一個隨機數組,目的是將牌打散。這里用了一個非常Low的方案,即生成隨機數,然后交換自然序列中兩個隨機數所在位置的值。
private int[] RandomArray(int length) { int[] arr = new int[length]; for (int i = 0; i < length; i++) arr[i] = i; int times = rand.Next(10, 100); for (int i = 0; i < times; i++) { int a = rand.Next(0, length - 1); int b = rand.Next(0, length - 1); var temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } return arr; }
接下來就是初始化代碼,這里按照平時發牌的順序,先生成這個區域的紙牌
然后再生成牌堆。
public void InitCards() { cvMain.Children.Clear(); cards = new List<Card>(); cardIndex = new List<int>[12]; //所有的撲克被劃分為12個區域 for (int i = 0; i < 12; i++) cardIndex[i] = new List<int>(); int index = 0; foreach (var key in CardNames.Keys) for (int i = 0; i < 13; i++) cards.Add(new Card(CardNames[key][i], i, key, key == "Heart" || key == "Diamond", index++)); var orders = RandomArray(52); index = 0; for (int i = 0; i < 6; i++) for (int j = i; j < 6; j++) { var card = cards[orders[index++]]; cardIndex[6 + j].Add(cvMain.Children.Count); var btn = setOneButton(card); if (i == j) { coverCard(btn, false); //當i==j時翻面 SetOneColumn(i); } card.Region = 6 + j; setBtnPosition(btn, card.Region); } while (index<52) { var card = cards[orders[index++]]; cardIndex[0].Add(cvMain.Children.Count); var btn = setOneButton(card); card.Region = 0; setBtnPosition(btn, 0); btn.Click += Card_Click; } }
其中,SetOneColumn
用于下面牌的上下排序,定義為
private void SetOneColumn(int region) { var count = cardIndex[region].Count; var left = (region - 6) * dw; var top0 = dh; int i = 0; var ddh = (0.8 + 2.5 * count / 15) * dh / count; foreach (var index in cardIndex[region]) { var btn = cvMain.Children[index]; Canvas.SetLeft(btn, left); Canvas.SetTop(btn, top0 + ddh * (i++)); Canvas.SetZIndex(btn, i); } }
針對紙牌游戲來說,鼠標事件可分為兩類,一是點擊牌堆需要發牌;二是拖動其他位置的牌。
點擊牌堆需要注意,當牌堆中的牌沒有了之后,需要將1區的牌還給牌堆。
private void Card_Click(object sender, RoutedEventArgs e) { var btn = sender as Button; var card = btn.Tag as Card; if (card.Region > 0) return; var count = cardIndex[0].Count; var num = Math.Min(count, numCard); for (int _ = 0; _ < num; _++) { var index = cardIndex[0][count - num]; //canvas中的順序 cardIndex[0].Remove(index); cardIndex[1].Add(index); btn = cvMain.Children[index] as Button; btn.Click -= Card_Click; btn.PreviewMouseLeftButtonDown += Card_PreviewLeftDown; coverCard(btn, false); setBtnPosition(btn, 1); card = btn.Tag as Card; card.Region = 1; } if (cardIndex[0].Count > 0 || cardIndex[1].Count <= numCard) return; foreach (var index in cardIndex[1]) { cardIndex[0].Add(index); btn = cvMain.Children[index] as Button; btn.Click += Card_Click; btn.PreviewMouseLeftButtonDown -= Card_PreviewLeftDown; coverCard(btn, true); setBtnPosition(btn, 0); card = btn.Tag as Card; card.Region = 0; } cardIndex[1] = new List<int>(); }
拖動主要包含三個動作,即鼠標按下、鼠標挪動、鼠標彈開,所以對應三個函數,且當鼠標按下之后,才掛載鼠標挪動的事件。而鼠標彈起之后,則判斷我們拖動的牌的最終位置。
private void Card_PreviewLeftDown(object sender, MouseButtonEventArgs e) { btnNow = sender as Button; if (btnNow.Content.ToString() == bgCard) return; var card = btnNow.Tag as Card; regionNow = cardIndex[card.Region]; indexNow = regionNow.IndexOf( cvMain.Children.IndexOf(btnNow)); var count = regionNow.Count; offsets = new List<Point>(); for (int i = indexNow; i < count; i++) { var btn = cvMain.Children[regionNow[i]] as Button; offsets.Add(Mouse.GetPosition(btn)); Canvas.SetZIndex(btnNow, 100 + i); } btnNow.PreviewMouseLeftButtonUp += Card_PreviewLeftUp; btnNow.PreviewMouseMove += Card_PreviewMouseMove; } private void Card_PreviewMouseMove(object sender, MouseEventArgs e) { var p = Mouse.GetPosition(cvMain); for (int i = indexNow; i < regionNow.Count; i++) { var btn = cvMain.Children[regionNow[i]] as Button; Canvas.SetLeft(btn, p.X - offsets[i - indexNow].X); Canvas.SetTop(btn, p.Y - offsets[i - indexNow].Y); } } private void Card_PreviewLeftUp(object sender, MouseButtonEventArgs e) { btnNow.PreviewMouseLeftButtonUp -= Card_PreviewLeftUp; btnNow.PreviewMouseMove -= Card_PreviewMouseMove; var p = Mouse.GetPosition(cvMain); int region = (int)(p.X / dw) + (p.Y > dh ? 6 : 0); var index = cardIndex[region].Count - 1; //目標區域最上面的牌的序號 var card = btnNow.Tag as Card; int srcRegion = card.Region; //牌在挪動之后有兩種可能,一種是成功了,另一種是失敗了 bool suc = region != srcRegion; //如果挪動的區域相同,則必失敗 bool subSuc; suc &= region > 1; //如果向牌堆挪動,則必失敗。 if (index < 0) {//A和K的情況滿足任何一種即可成功 subSuc = region > 1 && region < 6 && card.Number == 0; subSuc |= region > 5 && card.Number == 12; } else { var tarBtn = cvMain.Children[cardIndex[region][index]] as Button; var tarCard = tarBtn.Tag as Card; var flag = tarCard.Type == card.Type; var minus = card.Number - tarCard.Number; subSuc = region > 1 && region < 6 && flag && (minus == 1); subSuc |= region > 5 && (!flag) && (minus == -1); } reGroup(suc & subSuc, card, srcRegion, region); }
通過reGroup
函數決定牌最終的狀態。
private void reGroup(bool suc, Card card, int srcRegion, int tarRegion) { if (suc) { if (tarRegion > 5) setNewRegion(srcRegion, tarRegion); else setNewRegion(btnNow, card, srcRegion, tarRegion); } if (srcRegion < 6) setBtnPosition(btnNow, srcRegion); else { SetOneColumn(srcRegion); var i = regionNow.Count; if (i > 0) { var btn = cvMain.Children[regionNow[i - 1]] as Button; coverCard(btn, false); } } } private void setNewRegion(Button btn, Card card, int src, int tar) { int i = cardIndex[src].Count - 1; cardIndex[tar].Add(cardIndex[src][i]); cardIndex[src].RemoveAt(i); card.Region = tar; setBtnPosition(btn, tar); } //src和tar均為大區 private void setNewRegion(int src, int tar) { var count = regionNow.Count; for (int i = indexNow; i < count; i++) { var btn = cvMain.Children[regionNow[indexNow]] as Button; cardIndex[tar].Add(regionNow[indexNow]); regionNow.RemoveAt(indexNow); var card = btn.Tag as Card; card.Region = tar; Canvas.SetZIndex(btn, cardIndex[tar].Count); } SetOneColumn(tar); if (regionNow.Count > 0) { var btn = cvMain.Children[regionNow[indexNow - 1]] as Button; coverCard(btn, false); } }
以上就是關于“基于WPF如何實現經典紙牌游戲”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。