大体的做大约3天完成了:

第一天:确定了主题做消消乐,网上找素材P图,确定布局

第二天:正式开做,上午大约把整体绘制出来了,实现了基础的交换,下午重点攻克了交换和下落的动画效果,这点确实感觉有点难

第三天:加了点花哨的技能积分金钱和音乐



时间真的有限,草草的完成了作业,可能bug比较多,发现可以联系我,不胜感激。



在网上的素材中用ps扣出了方块,由于数量不够,其中两个改了色相饱和度

android studio消消乐小游戏_i++

绘制出基础的游戏界面

android studio消消乐小游戏_Text_02

预处理大约就这么点。

由于习惯了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 = "暂停";
                }
            }
        }

    }
}