1. 程式人生 > >C#期末大作業 消消樂

C#期末大作業 消消樂

鄰近期末,忙於刷題之餘意識到期末大作業來不及了,匆匆趕下了作業,雖說做的很是粗糙,但完全原創的

下載連結

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 = "暫停";
                }
            }
        }

    }
}