大体的做大约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 = "暂停";
}
}
}
}
}