C#期末大作業 消消樂
阿新 • • 發佈:2019-02-04
鄰近期末,忙於刷題之餘意識到期末大作業來不及了,匆匆趕下了作業,雖說做的很是粗糙,但完全原創的
下載連結
https://pan.baidu.com/s/1cCNLr4
大體的做大約3天完成了:
第一天:確定了主題做消消樂,網上找素材P圖,確定佈局
第二天:正式開做,上午大約把整體繪製出來了,實現了基礎的交換,下午重點攻克了交換和下落的動畫效果,這點確實感覺有點難
第三天:加了點花哨的技能積分金錢和音樂
時間真的有限,草草的完成了作業,可能bug比較多,發現可以聯絡我,不勝感激。
在網上的素材中用ps扣出了方塊,由於數量不夠,其中兩個改了色相飽和度
繪製出基礎的遊戲介面
預處理大約就這麼點。
由於習慣了acm的套路,程式碼基本都是面向過程寫的,幾乎沒面向物件,只寫了一個方格的類
下面貼一下核心的cs程式碼
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Media; namespace JellyCancellation { public partial class JellyCancellation : Form { private int _height = 10;//地圖大小 private int _width = 8; private Jelly[,] _map = new Jelly[11, 9];//儲存地圖資訊 private int _size = 40;//每一格寬度 private Point _topleft = new Point(40, 100);//記錄左上角座標 private int _istart = 0;//記錄遊戲是否開始 private int _stop = 0; private int _ispic = 0;//記錄是否選中方塊 private int _pickRow = 0;//記錄選中的行 private int _pickCol = 0;//記錄選中的列 private int _dropRow = 0; private int _dropCol = 0; private int _changeFlag = 0;//記錄是否交換成功 private Jelly j1 = new Jelly(jcolor.無, new Point(0, 0), 40, 0);//臨時交換用 private Jelly j2 = new Jelly(jcolor.無, new Point(0, 0), 40, 0); private int _x1 = 0; private int _y1 = 0; private int _x2 = 0; private int _y2 = 0; private int _time = 40;//記錄時間 private int _step = 8;//交換移動步長 private int _skill1 = 0;//記錄每個技能的數量 private int _skill2 = 0; private int _skill3 = 0; private int _skill4 = 0; private int _money = 0;//記錄金錢 private int _point = 0;//記錄分數 public void BuildMap()//隨機生成地圖 { Random myRand = new Random(DateTime.Now.Second); for (int i = 1; i <= _height; i++) for (int j = 1; j <= _width; j++) { _map[i, j] = new Jelly((jcolor)myRand.Next(1, 7), new Point(_topleft.X + (j - 1) * _size, _topleft.Y + (i - 1) * _size), _size, 0); } } public void DrawMap(Graphics g)//繪製出地圖 { for (int i = 1; i <= _height; i++) for (int j = 1; j <= _width; j++) { _map[i, j].Drawme(g); } } //獲取與使用者滑鼠點選位置距離最近的棋盤交叉點的行號和列號 public bool ConvertPointToRowCol(Point point, out int row, out int col) { int tempRow = (point.Y - _topleft.Y) / _size + 1; int tempCol = (point.X - _topleft.X) / _size + 1; if ((tempRow <= 10) && (tempRow >= 1) && (tempCol <= 8) && (tempCol >= 1)) { //返回行號和列號,並返回true,表示該點選有效 row = tempRow; col = tempCol; return true; } else { //把行號和列號都設定為-1,並返回false,表示無效點選 row = -1; col = -1; return false; } } //消除圖中方塊 public bool clean() { int tot = 0; bool isclean = false; //初始化消除標記 for (int i = 1; i <= _height; i++) for (int j = 1; j <= _width; j++) { _map[i, j]._Willclean = 0; } //遍歷每個方格,每個都向右向下搜尋 for (int i = 1; i <= _height; i++) for (int j = 1; j <= _width; j++) { if (_map[i, j]._Color != jcolor.無)//如果有顏色則搜尋 { //縱向搜 int cnt = 1;//記錄相連的同色方塊個數 int x = i + 1; while (x <= _height) { if (_map[x, j]._Color == _map[i, j]._Color)//如果顏色相同記錄個數 { x++; cnt++; } else break; } if (cnt >= 3)//如果大於等於3個,標記將消除 { isclean = true; for (int k = i; k < i + cnt; k++) _map[k, j]._Willclean = 1; tot += cnt; } //橫向搜 cnt = 1; int y = j + 1; while (y <= _width) { if (_map[i, y]._Color == _map[i, j]._Color)//如果顏色相同記錄個數 { y++; cnt++; } else break; } if (cnt >= 3)//如果大於等於3個,標記將消除 { isclean = true; for (int k = j; k < j + cnt; k++) _map[i, k]._Willclean = 1; tot += cnt; } } } //注意這裡一定要先標記再同意消除,如果直接在上面消除,會導致十字不可消 for (int i = 1; i <= _height; i++)//將待消除的方塊消除 for (int j = 1; j <= _width; j++) { if (_map[i, j]._Willclean == 1) _map[i, j]._Color = jcolor.無; } _time += tot /= 3;//獎勵時間 _time = Math.Min(_time, 40);//時間不能超過最大的40 _point += tot * 10;//獎勵分數 _money += tot;//獎勵金錢 timelabel.Text = _time.ToString() + "s";//更新標籤 money1.Text = _money.ToString(); point1.Text = _point.ToString(); return isclean;//返回是否可消 } //交換方塊顏色 public void swap(int x, int y, int tox, int toy) { //交換的實質是兩個顏色的互換 jcolor color = _map[x, y]._Color; _map[x, y]._Color = _map[tox, toy]._Color; _map[tox, toy]._Color = color; } //建構函式 public JellyCancellation() { InitializeComponent(); SetStyle(ControlStyles.AllPaintingInWmPaint, true); SetStyle(ControlStyles.DoubleBuffer, true); } //遊戲開始 private void BeginMenuItem_Click(object sender, EventArgs e) { Bitmap a = new Bitmap("Image\\mouse.png");//自定義滑鼠 SetCursor(a, new Point(0, 0)); axWindowsMediaPlayer2.URL = "Music\\bj.mp3"; axWindowsMediaPlayer2.Ctlcontrols.play(); BuildMap();//隨機生成地圖 _istart = 1;//標記遊戲開始 _stop = 0; _time = 40;//初始化時間 _money = 0; _point = 0; pictureBox1.Invalidate(); timer3.Enabled = true;//生成的圖可能能消除,重新整理 timer1.Enabled = true;//開始計時 } //記錄遊戲剩餘時間 private void timer1_Tick(object sender, EventArgs e) { if (_time == 0)//時間到則GG { _istart = 0; timer1.Enabled = false; MessageBox.Show("Game Over~"); } timelabel.Text = _time.ToString() + "s";//更新標籤 _time--;//更新時間 } //技能1釋放 隨機消除一種顏色 private void skillbutton1_Click(object sender, EventArgs e) { if (_istart == 1 && _stop == 0) { if (_skill1 > 0)//數量至少有1 { _skill1--;//技能消耗1個 skillbutton1.Text = skillbutton1.Text = "使用(" + _skill1.ToString() + ")";//更新標籤 Random myRand = new Random(DateTime.Now.Second);//隨機選擇一種顏色 int x = myRand.Next(1, 7); for (int i = 1; i <= _height; i++)//搜尋所有方塊,若是選擇的顏色則消除 for (int j = 1; j <= _width; j++) { if ((int)_map[i, j]._Color == x) _map[i, j]._Color = jcolor.無; } timer3.Enabled = true;//執行下落 pictureBox1.Invalidate(); } else//道具不夠提示 { timer1.Enabled = false;//暫停計時 timelabel.Text = "暫停"; MessageBox.Show("對不起,道具數量不足,請購買~", "使用失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); timer1.Enabled = true;//回覆計時 } } } //釋放技能2 重新重新整理所有方塊 private void skillbutton2_Click(object sender, EventArgs e) { if (_istart == 1 && _stop == 0) { if (_skill2 > 0)//至少有一個技能2 { timer1.Enabled = false;//暫停計時 _skill2--;//技能消耗 skillbutton2.Text = skillbutton2.Text = "使用(" + _skill2.ToString() + ")"; BuildMap();//重新整理就是重新建個圖 timer3.Enabled = true;//執行下落 timer1.Enabled = true;//回覆計時 pictureBox1.Invalidate(); } else//道具不夠提示 { timer1.Enabled = false; timelabel.Text = "暫停"; MessageBox.Show("對不起,道具數量不足,請購買~", "使用失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); timer1.Enabled = true; } } } //釋放技能3 +10s private void skillbutton3_Click(object sender, EventArgs e) { if (_istart == 1 && _stop == 0) { if (_skill3 > 0)//至少有一個技能2 { _skill3--; //技能消耗 skillbutton3.Text = skillbutton3.Text = "使用(" + _skill3.ToString() + ")"; _time += 10; //時間增加 timelabel.Text = _time.ToString() + "s"; //更新標籤 } else //道具不夠提示 { timer1.Enabled = false; //暫停計時 timelabel.Text = "暫停"; MessageBox.Show("對不起,道具數量不足,請購買~", "使用失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); timer1.Enabled = true; //回覆計時 } } } //釋放技能4 隨機消除一個十字 private void skillbutton4_Click(object sender, EventArgs e) { if (_istart == 1 && _stop == 0) { if (_skill4 > 0) //技能數量至少1個 { timer1.Enabled = false; //暫停計時 _skill4--; //技能消耗 skillbutton4.Text = skillbutton4.Text = "使用(" + _skill4.ToString() + ")"; Random myRand = new Random(DateTime.Now.Second); //隨機選擇圖中的點 int x = myRand.Next(1, 11); int y = myRand.Next(1, 9); for (int i = 1; i <= _height; i++) //消除列 { _map[i, y]._Color = jcolor.無; } for (int i = 1; i <= _width; i++) //消除行 { _map[x, i]._Color = jcolor.無; } timer3.Enabled = true; //執行下落 timer1.Enabled = true; //回覆計時 pictureBox1.Invalidate(); } else //道具不足提示 { timer1.Enabled = false; //暫停計時 timelabel.Text = "暫停"; MessageBox.Show("對不起,道具數量不足,請購買~", "使用失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); timer1.Enabled = true; //回覆計時 } } } //繪製函式 private void pictureBox1_Paint(object sender, PaintEventArgs e) { if (_istart == 1)//如果已經開始,畫出圖 DrawMap(e.Graphics); if (timer2.Enabled == true) //如果正在交換 畫出臨時變數 { j1.Drawme(e.Graphics); j2.Drawme(e.Graphics); } } //滑鼠點選 private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { if (timer3.Enabled == false && _istart == 1 && _stop == 0) { axWindowsMediaPlayer1.URL = "Music\\click.wav"; axWindowsMediaPlayer1.Ctlcontrols.play(); if (_ispic == 0)//如果沒有點選過,標記點選位置 { int row, col; bool value = ConvertPointToRowCol(new Point(e.X, e.Y), out row, out col); //捕捉行列 if (value == true) { if (_map[row, col]._Color != jcolor.無) //如果不是無,就選擇 { _pickRow = row; _pickCol = col; _ispic = 1; _map[_pickRow, _pickCol].change();//將選擇方塊變樣子 } } } else//如果已經點選過 { int row, col; bool value = ConvertPointToRowCol(new Point(e.X, e.Y), out row, out col); if (value == true) { if (_map[row, col]._Color != jcolor.無) { //如果點選和標記位置相連,交換 if ((row == _pickRow && Math.Abs(col - _pickCol) == 1) || (col == _pickCol && Math.Abs(row - _pickRow) == 1)) { _dropRow = row; _dropCol = col; _map[_pickRow, _pickCol]._Flag = 0; j1 = new Jelly(_map[_pickRow, _pickCol]._Color, _map[_pickRow, _pickCol]._Top, _map[_pickRow, _pickCol]._Size, _map[_pickRow, _pickCol]._Flag); j2 = new Jelly(_map[_dropRow, _dropCol]._Color, _map[_dropRow, _dropCol]._Top, _map[_dropRow, _dropCol]._Size, _map[_dropRow, _dropCol]._Flag); // swap(row, col, _pickRow, _pickCol); _map[_pickRow, _pickCol]._Color = jcolor.無;//交換好了先隱藏 _map[_dropRow, _dropCol]._Color = jcolor.無; pictureBox1.Invalidate(); _x1 = j1._Top.X;//記錄一系列臨時變數 _y1 = j1._Top.Y; _x2 = j2._Top.X; _y2 = j2._Top.Y; _changeFlag = 0; timer1.Enabled = false;//暫停計時 timer2.Enabled = true;//執行交換 } else//不相鄰就重新標記 { _map[_pickRow, _pickCol]._Flag = 0; _pickRow = row; _pickCol = col; _map[_pickRow, _pickCol].change(); _ispic = 1; } } } } } pictureBox1.Invalidate(); } //技能介紹 private void skill1label_Click(object sender, EventArgs e) { textBox1.Text = "隨機消除一種\r\n顏色的方塊!"; } private void skill2label_Click(object sender, EventArgs e) { textBox1.Text = "重新重新整理\r\n所有方塊!"; } private void skill3label_Click(object sender, EventArgs e) { textBox1.Text = "增加10s\r\n遊戲時間!"; } private void skill4label_Click(object sender, EventArgs e) { textBox1.Text = "隨機消除\r\n十字方塊!"; } //執行交換 private void timer2_Tick(object sender, EventArgs e) { pictureBox1.Invalidate(); int flag = 0; if (_y1 == _y2) { if (_x1 < _x2) { j1._Top = new Point(j1._Top.X + _step, j1._Top.Y); j2._Top = new Point(j2._Top.X - _step, j2._Top.Y); if (j1._Top.X >= _x2) flag = 1; } else { j1._Top = new Point(j1._Top.X - _step, j1._Top.Y); j2._Top = new Point(j2._Top.X + _step, j2._Top.Y); if (j1._Top.X <= _x2) flag = 1; } } else if (_x1 == _x2) { if (_y1 < _y2) { j1._Top = new Point(j1._Top.X, j1._Top.Y + _step); j2._Top = new Point(j2._Top.X, j2._Top.Y - _step); if (j1._Top.Y >= _y2) flag = 1; } else { j1._Top = new Point(j1._Top.X, j1._Top.Y - _step); j2._Top = new Point(j2._Top.X, j2._Top.Y + _step); if (j1._Top.Y <= _y2) flag = 1; } } if (flag == 1)//如果交換好了 { timer2.Enabled = false;//關閉交換計時器 timer1.Enabled = true;//繼續計時 _map[_pickRow, _pickCol]._Color = j2._Color; _map[_dropRow, _dropCol]._Color = j1._Color; pictureBox1.Invalidate(); if (_changeFlag == 0) { if (!clean())//如果不能消除那麼換回來,重新標記 { j1 = new Jelly(_map[_pickRow, _pickCol]._Color, _map[_pickRow, _pickCol]._Top, _map[_pickRow, _pickCol]._Size, _map[_pickRow, _pickCol]._Flag); j2 = new Jelly(_map[_dropRow, _dropCol]._Color, _map[_dropRow, _dropCol]._Top, _map[_dropRow, _dropCol]._Size, _map[_dropRow, _dropCol]._Flag); // swap(_dropRow, _dropCol, _pickRow, _pickCol); _map[_pickRow, _pickCol]._Color = jcolor.無;//交換好了先隱藏 _map[_dropRow, _dropCol]._Color = jcolor.無; timer1.Enabled = false; timer2.Enabled = true; _map[_pickRow, _pickCol]._Flag = 0; _ispic = 0; _changeFlag = 1; } else//交換成功 { timer3.Enabled = true;//執行下落 _pickRow = 0; _pickCol = 0; _ispic = 0; } } } } //執行下落 及判斷是否還可消 private void timer3_Tick(object sender, EventArgs e) { //搜尋每一列,把最下面的空白慢慢換上來,類似氣泡排序 for (int j = 1; j <= _width; j++) { for (int i = _height; i >= 2; i--) { if (_map[i, j]._Color == jcolor.無) { for (int k = i; k >= 2; k--) swap(k, j, k - 1, j); break; } } } //空白的第一行隨機生成 Random myRand = new Random(); for (int j = 1; j <= _width; j++) if (_map[1, j]._Color == jcolor.無) _map[1, j]._Color = (jcolor)myRand.Next(1, 7); pictureBox1.Invalidate(); int flag = 0;//判斷是否還能下落 for (int i = 1; i <= _height; i++) { for (int j = 1; j <= _width; j++) { if (_map[i, j]._Color == jcolor.無) { flag = 1; break; } } if (flag == 1) break; } if (flag == 0)//果果不能下落了 { if (!clean())//判斷是否還可消 如果不可消,下落結束 timer3.Enabled = false; } } //購買技能 private void buybutton1_Click(object sender, EventArgs e) { if (_istart == 1 && _stop == 0) { timer1.Enabled = false; timelabel.Text = "暫停"; if (MessageBox.Show("你確定要花40大洋購買一個星辰墜落嗎?", "購買", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { if (_money >= 40) { _money -= 40; _skill1 += 1; skillbutton1.Text = "使用(" + _skill1.ToString() + ")"; } else { MessageBox.Show("對不起,餘額不足,請聯絡作者充值或擼起袖子加油幹,努力賺錢~", "購買失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } money1.Text = _money.ToString(); timer1.Enabled = true; } } private void buybutton2_Click(object sender, EventArgs e) { if (_istart == 1 && _stop == 0) { timer1.Enabled = false; timelabel.Text = "暫停"; if (MessageBox.Show("你確定要花40大洋購買一個移形換影嗎?", "購買", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { if (_money >= 40) { _money -= 40; _skill2 += 1; skillbutton2.Text = "使用(" + _skill2.ToString() + ")"; } else { MessageBox.Show("對不起,餘額不足,請聯絡作者充值或擼起袖子加油幹,努力賺錢~", "購買失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } money1.Text = _money.ToString(); timer1.Enabled = true; } } private void buybutton3_Click(object sender, EventArgs e) { if (_istart == 1&&_stop==0) { timer1.Enabled = false; timelabel.Text = "暫停"; if (MessageBox.Show("你確定要花30大洋購買一個如沐春風嗎?", "購買", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { if (_money >= 30) { _money -= 30; _skill3 += 1; skillbutton3.Text = "使用(" + _skill3.ToString() + ")"; } else { MessageBox.Show("對不起,餘額不足,請聯絡作者充值或擼起袖子加油幹,努力賺錢~", "購買失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } money1.Text = _money.ToString(); timer1.Enabled = true; } } private void buybutton4_Click(object sender, EventArgs e) { if (_istart == 1 && _stop == 0) { timer1.Enabled = false; timelabel.Text = "暫停"; if (MessageBox.Show("你確定要花35大洋購買一個橫掃千軍嗎?", "購買", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) { if (_money >= 35) { _money -= 35; _skill4 += 1; skillbutton4.Text = "使用(" + _skill4.ToString() + ")"; } else { MessageBox.Show("對不起,餘額不足,請聯絡作者充值或擼起袖子加油幹,努力賺錢~", "購買失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } money1.Text = _money.ToString(); timer1.Enabled = true; } } //自定義游標,參考網上 public void SetCursor(Bitmap cursor, Point hotPoint) { int hotX = hotPoint.X; int hotY = hotPoint.Y; Bitmap myNewCursor = new Bitmap(cursor.Width * 2 - hotX, cursor.Height * 2 - hotY); Graphics g = Graphics.FromImage(myNewCursor); g.Clear(Color.FromArgb(0, 0, 0, 0)); g.DrawImage(cursor, cursor.Width - hotX, cursor.Height - hotY, cursor.Width, cursor.Height); this.Cursor = new Cursor(myNewCursor.GetHicon()); g.Dispose(); myNewCursor.Dispose(); } private void stopbutton_Click(object sender, EventArgs e) { if (_istart == 1) { if (_stop == 0) { _stop = 1; timer1.Enabled = false; timelabel.Text = "暫停"; stopbutton.Text = "繼續"; } else { _stop = 0; timer1.Enabled = true; stopbutton.Text = "暫停"; } } } } }