亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#拼圖游戲編寫代碼(2)

2019-10-29 21:11:35
字體:
來源:轉載
供稿:網友

前言:在C#拼圖游戲編寫代碼程序設計 之 C#實現《拼圖游戲》(上),上傳了各模塊代碼,而在本文中將詳細剖析原理,使讀者更容易理解并學習,程序有諸多問題,歡迎指出,共同學習成長!

C#,拼圖,游戲

正文:

拼圖是一個非常經典的游戲,基本每個人都知道他的玩法,他的開始,運行,結束。那么,當我們想要做拼圖的時候如何入手呢?答案是:從現實出發,去描述需求(盡量描述為文檔),當我們擁有了全面的需求,就能夠提供可靠的策略,從而在代碼中實現,最終成為作品!

(一)需求: (這個需求書寫較為潦草,為廣大小白定制,按照最最最普通人的思維來,按照參與游戲的流程來)

   1.圖片:我們玩拼圖 最起碼有個圖

   2.切割:拼圖不是一個圖,我們需要把一個整圖它切割成N*N的小圖

   3.打亂:把這N*N的小圖打亂順序,但是要保證通過游戲規則行走能還原回來

   4.判斷:判拼圖成功

   5.交互:我們使用哪一種交互方式,這里我選擇鼠標點擊

      6.展示原圖片完整的縮略圖

以上為基本功能,以下為擴展功能

     7.記錄步數:記錄完成需要多少步

     8.更換圖片:一個圖片玩久了我們是不是可以換一換啊 哈哈

     9.選擇難度:太簡單?不要!3*3搞定了有5*5,5*5搞定了有9*9,舍友挑戰最高難度 3000多步,心疼我的鼠標TAT

(二)分析:

有了需求,我們就可以分析如何去實現它(把現實需求映射在計算機中),其中包括:

1.開發平臺:這里選擇C#語言

 1).存儲:其中包括我們要存什么?我們用什么結構存?我們反觀需求,會發現,有一些需要存儲的資源

      圖片:使用 Image 對象存儲

      單元(原圖片切割后的子圖像集合):自定義結構體 struct Node ,其中包括Image對象用來存儲單元小圖片,和用整形存儲的編號(切割以后,每個小單元都弄個編號,利于檢驗游戲是否完成)。

      各單元(原圖片切割后的子圖像集合):使用二維數組(像拼圖,五子棋,消消樂,連連看,俄羅斯方塊等平面點陣游戲都可以用他來存儲,為什么?因為長得像嘛!)來存儲

      難度:使用自定義的枚舉類型(簡單and普通and困難)存儲

      步數:整形變量 int Num存儲 

  有了存儲,我們就可以去思考模塊的劃分(正確的邏輯劃分已于擴展,也可以使通信變得更加清晰)并搭建,并實現各模塊涉及到的具體算法

      首先程序的模塊分為四個:

  邏輯型:

    1.拼圖類:用于描述拼圖

    2.配置類:存儲配置變量

  交互型:

    3.游戲菜單窗口:進行菜單選項

    4.游戲運行窗口:游戲的主要界面

C#,拼圖,游戲

  1.通過游戲菜單可以操縱配置,如難度或圖片。

  2.運行窗口可以訪問并獲得游戲配置,并利用其對應構造拼圖對象。

  3.用戶通過運行窗口進行交互,間接使拼圖對象調用移動方法,獲得圖案方法

  看代碼的同學,我覺得最有問題的地方,不合理的地方就是把 難度的枚舉類型寫在了拼圖類中,應該寫在配置類中,或單獨成類,讀者們自行更改

 public enum Diff //游戲難度 {  simple,//簡單  ordinary,//普通  difficulty//困難 } 

我們可以認為,配置類就像數據存儲,而拼圖類呢作為邏輯處理,菜單和運行窗口作為表現用于交互,我承認這種設計不是很合理,但是在問題規模不夠大的時候,過分的考慮設計,會不會使程序變得臃腫?我想一定是有一個度,具體是多少,我不得而知,但我感覺,針對這個程序,實現就好,沉迷設計(套路型),有時得不償失。(個人不成熟的小觀點)

(三)代碼實現:

說明:本塊重點描述 Puzzle(拼圖)類與游戲運行類的具體實現及實體通訊:

拼圖的構造方法:

1.賦值 :

public Puzzle(Image Img,int Width, Diff GameDif)

// 拼圖的圖片,寬度(解釋:正方形的邊長,單位是像素,名字有歧義,抱歉),游戲的難度 

 游戲的難度決定你分割的程度,分割的程度,決定你存儲的數組的大小,如簡單對應3行3列,普通對應5行5列,困難對應9行9列

 switch(this._gameDif)  {  case Diff.simple:    //簡單則單元格數組保存為3*3的二維數組   this.N = 3;   node=new Node[3,3];   break;  case Diff.ordinary:   //一般則為5*5   this.N = 5;   node = new Node[5, 5];   break;  case Diff.difficulty:  //困難則為9*9   this.N = 9;   node = new Node[9, 9];   break;  }

2.分割圖片

 //分割圖片形成各單元保存在數組中  int Count = 0;  for (int x = 0; x < this.N; x++)  {  for (int y = 0; y < this.N; y++)  {   node[x, y].Img = CaptureImage(this._img, this.Width / this.N, this.Width / this.N, x * (this.Width / this.N), y * (this.Width / this.N));   node[x, y].Num = Count;   Count++;  }  }

其實對單元數組進行賦值的過程,使用雙層for循環對二維數組進行遍歷操作,然后按序賦值編號node[x,y].Num; 

然后對node[x,y].Img,也就是單元的小圖片賦值,賦值的方法是,C#的圖像的類庫,寫一個截圖方法,使用這個方法,將大圖中對應對位置的對應大小的小圖截取下來,并保存在node[x,y].Img中;

width/N是什么?是邊長除以行數,也就是間隔嘛,間隔也就是每個單元的邊長嘛!然后起始坐標(X,Y)起始就是在說,隔了幾個單元后,我的位置,

即 :(x,y)=(單元邊長*距離起始X軸相距單元數,單元邊長*距離起始點Y軸相距單元數);

關于此類問題,希望讀者能夠多畫畫圖,然后自然就明白了;

public  Image CaptureImage(Image fromImage, int width, int height, int spaceX, int spaceY)

C#,拼圖,游戲

主要邏輯:利用DrawImage方法:

//創建新圖位圖  Bitmap bitmap = new Bitmap(width, height);//創建作圖區域 Graphics graphic = Graphics.FromImage(bitmap);//截取原圖相應區域寫入作圖區  graphic.DrawImage(fromImage, 0, 0, new Rectangle(x, y, width, height), GraphicsUnit.Pixel);//從作圖區生成新圖  Image saveImage = Image.FromHbitmap(bitmap.GetHbitmap());

分割了以后,我們要做一個特殊處理,因為我們知道,總有那么一個位置是白的吧?我們默認為最后一個位置,即node[N-1,N-1];

就是寫改成了個白色的圖片,然后四周的邊線都給畫成紅色,已于被人發現,顯著一些,之前的其他單元我也畫了邊線,但是是白色,也是為了在拼圖的觀賞性上得到區分。該代碼不做介紹。

3.打亂圖片:

其實就是將二維數組打亂,我們可以采取一些排序打亂方法,但是請注意!不是每一種打亂都能夠復原的!

那么如何做到可行呢?方法理解起來很簡單,就是讓我們的電腦在開局之前,將完整的有序的單元按照規則中提供的行走方式進行無規則,大次數的行走!也就是說這種方法一定能走回去!

先理解,具體打亂方法,在后面講解。 

移動方法(Move):

拼圖游戲中方格的移動,其實就是兩個相鄰單元的交換,而這兩個單元中,必定存在一個白色單元(即上面提到的node[N-1,N-1]單元,他的編號為N*N-1,建議自己動筆算一算)

所以我們的判斷條件是,如果移動一個方塊,他的上下左右四個方向中,一旦有一個相鄰的是白色單元,即N*N-1號單元,則與其交換。這是基本邏輯,但不包括約束條件,當我們的數組達到邊界的時候,我們就不能對越界數據進行訪問,如當單元為node[0,0]時,你就不能對他上面和右面的數據進行訪問,因為Node[-1,0] Node[0,-1]都會越界,發生異常

移動成功,返回TRUE

移動失敗,返回FALSE

/// <summary> /// 移動坐標(x,y)拼圖單元 /// </summary> /// <param name="x">拼圖單元x坐標</param> /// <param name="y">拼圖單元y坐標</param> public bool Move(int x,int y) {  //MessageBox.Show(" " + node[2, 2].Num);  if (x + 1 != N && node[x + 1, y].Num == N * N - 1)  {  Swap(new Point(x + 1, y), new Point(x, y));  return true;  }  if (y + 1 != N && node[x, y + 1].Num == N * N - 1)  {  Swap(new Point(x, y + 1), new Point(x, y));  return true;  }    if (x - 1 != -1 && node[x - 1, y].Num == N * N - 1)  {  Swap(new Point(x - 1, y), new Point(x, y));  return true;  }   if (y - 1 != -1 && node[x, y - 1].Num == N * N - 1)  {  Swap(new Point(x, y - 1), new Point(x, y));  return true;  }  return false;   }

交換方法(Swap):

交換數組中兩個元素的位置,該方法不應該被類外訪問,顧設置為private私有權限

 //交換兩個單元格 private void Swap(Point a, Point b) {  Node temp = new Node();  temp = this.node[a.X, a.Y];  this.node[a.X, a.Y] = this.node[b.X, b.Y];  this.node[b.X, b.Y] = temp; }

打亂方法:

前面提到,其實就是讓電腦幫著亂走一通,說白了就是大量的調用Move(int X,int y)方法,也就是對空白位置的上下左右四個相鄰的方塊中隨機抽取一個,并把它的坐標傳遞給Move使其進行移動,同樣要進行越界考慮,這樣的操作大量重復!代碼自己看吧 ,利用隨機數。

/// <summary> /// 打亂拼圖 /// </summary> public void Upset() {  int sum = 100000;  if (this._gameDif == Diff.simple) sum = 10000;  //if (this._gameDif == Diff.ordinary) sum = 100000;  Random ran = new Random();  for (int i = 0, x = N - 1, y = N - 1; i < sum; i++)  {  long tick = DateTime.Now.Ticks;  ran = new Random((int)(tick & 0xffffffffL) | (int)(tick >> 32)|ran.Next());  switch (ran.Next(0, 4))  {   case 0:   if (x + 1 != N)   {    Move(x + 1, y);    x = x + 1;   }       break;   case 1:   if (y + 1 != N)   {    Move(x, y + 1);    y = y + 1;   }    break;   case 2:   if (x - 1 != -1)   {    Move(x - 1, y);    x = x - 1;   }    break;   case 3:   if (y - 1 != -1)   {    Move(x, y - 1);    y = y - 1;   }   break;  }  } }

返回圖片的方法:

當時怎么起了個這樣的鬼名字。。。DisPlay。。。

這個方法與分割方法剛好相背,這個方法其實就是遍歷數組,并將其進行組合,組合的方法很簡單,就是將他們一個一個的按位置畫在一張與原圖相等大小的空白圖紙上!最后提交圖紙,也就是return一個Image;

 public Image Display() {  Bitmap bitmap = new Bitmap(this.Width, this.Width);  //創建作圖區域   Graphics newGra = Graphics.FromImage(bitmap);  for (int x = 0; x < this.N; x++)  for (int y = 0; y < this.N; y++)   newGra.DrawImage(node[x, y].Img, new Point(x * this.Width / this.N, y * this.Width / this.N));  return bitmap; }

同樣利用的是DrawImage方法,知道如何分割,這個應該很容易理解,自己算一算,在紙上比劃比劃就明白了;

判斷方法:

該方法很容易理解,就是按序按序!遍歷所有單元,如果他們的結果中有一個單元的編號

node[x, y].Num 不等于遍歷的序號,那么說明,該單元不在原有位置上,即整個圖片還沒有完成,我們就可以直接返回假值false
如果所有遍歷結果都正確,我們可認為,圖片已復原,此時返回真值true

 public bool Judge() {  int count=0;  for (int x = 0; x < this.N; x++)  {  for (int y = 0; y < this.N; y++)  {   if (this.node[x, y].Num != count)   return false;   count++;  }  }  return true; } 

游戲運行窗口:即游戲玩耍時用于交互的窗口

這里只講一個方法:即當接受用戶鼠標點擊事件時我們應該怎么處理并作出什么樣反應

其實說白了就這句難懂:

puzzle.Move(e.X / (puzzle.Width / puzzle.N), e.Y / (puzzle.Width / puzzle.N))

調用了移動方法,移動方塊

橫坐標為:e.X / (puzzle.Width / puzzle.N)
縱坐標為:e.Y / (puzzle.Width / puzzle.N)

我們編程中的整數除法和數學里的除法是不一樣的!比如10/4數學上等于2余2或者2.5,計算機里直接就是等于2了,只取整數部分

C#,拼圖,游戲

行數=行坐標 / 方塊邊長

列數=列坐標 / 方塊邊長

我們看P1,P2這兩點

P1:40/30*30=1
P2:50/30*30=1

我們會發現同在一個單元格中,無論點擊哪個位置,通過這個算法都能轉化為
同一個坐標。

(e.x,e.y)為鼠標點擊事件點擊坐標

 private void pictureBox1_MouseClick(object sender, MouseEventArgs e) {  if (puzzle.Move(e.X / (puzzle.Width / puzzle.N), e.Y / (puzzle.Width / puzzle.N)))  {  Num++;  pictureBox1.Image = puzzle.Display();  if (puzzle.Judge())  {    if (MessageBox.Show("恭喜過關", "是否重新玩一把", MessageBoxButtons.OKCancel) == DialogResult.OK)   {   Num = 0;   puzzle.Upset();   pictureBox1.Image = puzzle.Display();      }   else   {   Num = 0;   closefather();   this.Close();   }  }  }  NumLabel.Text = Num.ToString(); }

好,那么大體的邏輯,程序中最需要思考的算法已經講完了,還有不太懂的地方,歡迎交流~么么噠~

C#,拼圖,游戲

C#,拼圖,游戲

加了點小功能 音樂歷史成績

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
社区色欧美激情 | 91免费电影网站| 欧美午夜精品久久久久久久| 亚洲第一页在线| 国产精品成人v| 国产精欧美一区二区三区| 欧美激情二区三区| 久久久久久国产精品美女| 国产一区二区三区丝袜| 日韩暖暖在线视频| 久久人人爽人人爽爽久久| 亚洲激情自拍图| 日韩av有码在线| 美日韩精品免费观看视频| 精品国产一区二区三区四区在线观看| 在线观看中文字幕亚洲| 美女久久久久久久| 亚洲男人7777| 亚洲精品国产品国语在线| 懂色aⅴ精品一区二区三区蜜月| 国产精品久久久久久网站| 热久久免费国产视频| 成人免费视频网址| 九九热99久久久国产盗摄| 国产91色在线|| 久久国内精品一国内精品| 91精品成人久久| 国产主播精品在线| 国产精品精品一区二区三区午夜版| 日韩电影大全免费观看2023年上| 日韩电影中文 亚洲精品乱码| 欧美国产欧美亚洲国产日韩mv天天看完整| 日韩一区二区福利| 亚洲欧洲成视频免费观看| 欧美理论电影在线观看| 久久亚洲一区二区三区四区五区高| 国产精品99久久久久久人| 亚洲黄页视频免费观看| 91香蕉嫩草影院入口| 久久婷婷国产麻豆91天堂| 欧美亚洲日本网站| 亚洲精品v天堂中文字幕| 欧美午夜影院在线视频| 91色视频在线导航| 北条麻妃99精品青青久久| 久久久久久久色| 欧美另类精品xxxx孕妇| 欧美视频在线免费| 国内精品美女av在线播放| 精品福利在线视频| 久久99精品国产99久久6尤物| 国产精品旅馆在线| 26uuu另类亚洲欧美日本一| 亚洲激情国产精品| 亚洲毛片在线观看| 韩曰欧美视频免费观看| 成人免费看片视频| 亚洲片在线观看| 久久精品视频在线| 国产精品久久久久久亚洲调教| 91精品国产91久久久久久吃药| 欧美人成在线视频| 亲爱的老师9免费观看全集电视剧| 国产日本欧美一区二区三区在线| 色妞在线综合亚洲欧美| 精品视频9999| 久久精品精品电影网| 久久久久久一区二区三区| 国产成人午夜视频网址| 亚洲精品xxx| 国产日韩欧美黄色| 欧美精品videos| 欧美亚州一区二区三区| 在线观看欧美日韩国产| 日韩久久免费电影| 精品久久久久久| 欧亚精品在线观看| 亚洲第一福利视频| 中文在线不卡视频| 国产亚洲综合久久| 高跟丝袜欧美一区| 人人澡人人澡人人看欧美| 深夜精品寂寞黄网站在线观看| 亚洲另类欧美自拍| 色噜噜久久综合伊人一本| 成人a免费视频| 永久555www成人免费| 亚洲成年人影院在线| 欧美电影院免费观看| 欧美日韩午夜视频在线观看| 久久99精品久久久久久噜噜| 欧美日韩一二三四五区| 日本精品久久中文字幕佐佐木| 97精品视频在线| 日韩欧美中文免费| 91成人天堂久久成人| 亚洲国内精品视频| 久久综合色影院| 成人激情视频免费在线| 九九热精品视频国产| 成人久久久久久久| 国产一区二区黑人欧美xxxx| 国产成人+综合亚洲+天堂| 欧美黑人国产人伦爽爽爽| 亚洲精品久久久久久久久久久久久| 亚洲高清久久久久久| 欧美精品videofree1080p| 日韩av在线天堂网| 国产成人综合亚洲| 综合久久五月天| 久久精品在线视频| 人九九综合九九宗合| 日韩精品亚洲元码| 成人福利视频网| 亚洲天堂免费观看| 91在线观看欧美日韩| 91丨九色丨国产在线| 成人久久久久久| 45www国产精品网站| 久久久久久有精品国产| 国产精品高清在线观看| 亚洲天堂精品在线| 日韩av在线免费看| 在线视频欧美性高潮| 久久久久九九九九| 欧美又大又硬又粗bbbbb| 欧美成人午夜影院| 91精品一区二区| 国产精品视频免费在线| 日韩视频在线观看免费| 欧美精品video| 久久久久久有精品国产| 国产噜噜噜噜久久久久久久久| 欧美视频在线免费看| 亚洲国产成人爱av在线播放| 日韩中文字幕精品| 久久理论片午夜琪琪电影网| 欧美电影在线观看网站| 亚洲欧美日韩中文在线| 亚洲天堂av在线免费| 日本电影亚洲天堂| 一区二区三区动漫| 91av中文字幕| 欧美激情久久久| 日韩欧美在线免费观看| 日本中文字幕不卡免费| 欧美电影免费在线观看| 日韩精品在线观看一区二区| 日本国产精品视频| 热久久视久久精品18亚洲精品| 久久久亚洲国产天美传媒修理工| 成人免费网站在线观看| 亚洲精品电影网在线观看| 欧美三级欧美成人高清www| 日韩电影免费在线观看| 欧美性猛交xxxx乱大交| 97在线视频免费播放| 国产91精品久久久久| 亚洲成人av中文字幕| 91九色在线视频| 日韩欧美高清在线视频| 国产精品国产自产拍高清av水多| 久久久久久久电影一区| 亚洲精品欧美日韩专区|