学习C#从俄罗斯方块开始(三)俄罗斯方块的优化和美化

前两节地址:

概述

DEMO制作

按照我们第一节课程《学习C#从俄罗斯方块开始(一)概述》的规划。我们在完成了俄罗斯方块Demo后,我们将要对Demo进行优化和美化设置,使得俄罗斯的可玩性增强。本节课程我们就从算法的优化、游戏的美化和可玩性的扩展性上进行改进,让我们的游戏变得强大起来,也让我们的开发技术上一个小小的台阶。

第一、算法的优化:

Demo中,我们基本上都是用循环来完成向下、向左、向右的移动、检查是否存在可以得分的行等动作。在这些循环中我们使用了从0到最大值的循环。本算法的优化,我们主要着重于缩小循环的范围开始。经过我们的观察发现。在检测是否满行和绘制背景的时候,我们采用了历边所有的背景数组。我们可以缩小到只在俄罗斯方块完成落下的最小高度上进行检测,这样就大大的缩小了我们的循环范围。

所以我们申明了一个参数:lowY.

private int lowY = 19; //初始化的时候为到最下面。然后随着lowY的增加,循环范围会原来越大

原来我们的检测是否得分的函数:

private void CheckSore() { for (int y = 19; y > -1; y--) { bool isFull = true; for (int x = 13; x > -1; x--) { if (bgGraoud[y, x] == 0) { isFull = false; break; } } if (isFull) { //增加积分 Sorce = Sorce + 100; for (int yy = y; yy > 0; yy--) { for (int xx = 0; xx < 14; xx++) { int temp = bgGraoud[yy - 1, xx]; bgGraoud[yy, xx] = temp; } } y++; label1.Text = Sorce.ToString(); ; Draw(); } } }

就可以优化为:

private void CheckSore() { for (int y = 19; y > lowY; y--) { bool isFull = true; for (int x = 13; x > -1; x--) { if (bgGraoud[y, x] == 0) { isFull = false; break; } } if (isFull) { //增加积分 lowY++; //减少了一行,循环就可以减少一行 Sorce = Sorce + 100; for (int yy = y; yy > 0; yy--) { for (int xx = 0; xx < 14; xx++) { int temp = bgGraoud[yy - 1, xx]; bgGraoud[yy, xx] = temp; } } y++; label1.Text = Sorce.ToString(); ; Draw(); } } }

原来的绘图函数

private void Draw() { Graphics g = Graphics.FromImage(myImage); g.Clear(this.BackColor); for (int bgy = 0; bgy < 20; bgy++) { for (int bgx = 0; bgx < 14; bgx++) { if (bgGraoud[bgy, bgx] == 1) { g.FillRectangle(new SolidBrush(Color.Blue), bgx * 20, bgy * 20, 20, 20); } } } //绘制当前的图片 for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { g.FillRectangle(new SolidBrush(Color.Blue), (x + CurrentX) * 20, (y + CurrentY) * 20, 20, 20); } } } Graphics gg = panel1.CreateGraphics(); gg.DrawImage(myImage, 0, 0); }

则可以优化为:

private void Draw() { Graphics g = Graphics.FromImage(myImage); g.Clear(this.BackColor); for (int bgy = lowY; bgy < 20; bgy++) { for (int bgx = 0; bgx < 14; bgx++) { if (bgGraoud[bgy, bgx] == 1) { g.FillRectangle(new SolidBrush(Color.Blue), bgx * 20, bgy * 20, 20, 20); } } } //绘制当前的图片 for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { g.FillRectangle(new SolidBrush(Color.Blue), (x + CurrentX) * 20, (y + CurrentY) * 20, 20, 20); } } } Graphics gg = panel1.CreateGraphics(); gg.DrawImage(myImage, 0, 0); }

关于游戏的美化:

我们着重美化了游戏的砖块,把蓝色的惨不忍睹的砖块,变成多个颜色,仿三维样式的方块。效果图如下学习C#从俄罗斯方块开始(三)俄罗斯方块的优化和美化

在这里因为需要变成不同的颜色,所以背景必须有以前的x,y轴的两维信息,变成一个x,y的数字 和 color的三维信息。所以背景数组变化为:

#region 定义背景 private int[,,] bgGraoud ={ {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}, }; #endregion

同时我们定义了一个TricksColor的颜色数组,每个砖块对照三个颜色信息,分别表示显示出来的三个面的颜色:(具体的颜色各位可以再自己的游戏中随便变换,以达到美观为目的.)

private Color[,] TricksColor = { {Color.FromArgb(0,0,255),Color.FromArgb(200,200,253),Color.FromArgb(98,98,140)}, {Color.FromArgb(255,255,0),Color.FromArgb(253,253,200),Color.FromArgb(189,189,84)}, {Color.FromArgb(0,0,255),Color.FromArgb(200,200,253),Color.FromArgb(98,98,140)}, {Color.FromArgb(255,255,0),Color.FromArgb(253,253,200),Color.FromArgb(189,189,84)} };

因为背景数组发生了变化,所以我们的当前砖块也相应的变成了三维数组,代码都随之改动。现在我们主要贴出来draw的变化,关于其他代码的变化。大家可以去源文件中查看详细的注释:

private void Draw() { Graphics g = Graphics.FromImage(myImage); g.Clear(panel1.BackColor); for (int bgy = 19; bgy > lowY - 1; bgy--) { for (int bgx = 0; bgx < 14; bgx++) { if (bgGraoud[bgy, bgx, 0] == 1) { //首先我们绘制一个框 g.FillRectangle(new SolidBrush(TricksColor[bgGraoud[bgy, bgx, 1], 0]), bgx * 20, bgy * 20, 20, 20); //绘制上边 g.DrawRectangle(new Pen(panel1.BackColor), bgx * 20, bgy * 20, 20, 20); Point[] myPoints1 = { new Point(bgx * 20 + 5, bgy * 20 - 5), new Point(bgx * 20 + 25, bgy * 20 - 5), new Point(bgx * 20 + 20, bgy * 20), new Point(bgx * 20, bgy * 20) }; g.FillPolygon(new SolidBrush(TricksColor[bgGraoud[bgy, bgx, 1], 1]), myPoints1); g.DrawPolygon(new Pen(panel1.BackColor), myPoints1); //绘制右边 Point[] myPoints2 = { new Point(bgx * 20 + 20, bgy*20), new Point(bgx * 20 + 25, bgy * 20 - 5), new Point(bgx * 20 + 25, bgy * 20 + 15), new Point(bgx * 20 + 20, bgy * 20 + 20) }; g.FillPolygon(new SolidBrush(TricksColor[bgGraoud[bgy, bgx, 1], 2]), myPoints2); } } } //绘制当前的图片 for (int y = 3; y >= 0; y--) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x,0] == 1) { g.FillRectangle(new SolidBrush(TricksColor[CurrentTrick[y,x,1], 0]), (x + CurrentX) * 20, (y + CurrentY) * 20, 20, 20); g.DrawRectangle(new Pen(panel1.BackColor), (x + CurrentX) * 20, (y + CurrentY) * 20, 20, 20); //绘制上边 //绘制右边 if (x + 1 + CurrentX < 14) { if (bgGraoud[y + CurrentY, x + 1 + CurrentX, 0] == 0) { Point[] myPoints1 = { new Point((x + CurrentX) * 20 + 5, (y + CurrentY) * 20 - 5), new Point((x + CurrentX) * 20 + 25, (y + CurrentY) * 20 - 5), new Point((x + CurrentX) * 20 + 20, (y + CurrentY) * 20), new Point((x + CurrentX) * 20, (y + CurrentY) * 20) }; g.FillPolygon(new SolidBrush(TricksColor[CurrentTrick[y, x, 1], 1]), myPoints1); g.DrawPolygon(new Pen(panel1.BackColor), myPoints1); Point[] myPoints2 = { new Point((x + CurrentX) * 20 + 20, (y + CurrentY) * 20), new Point((x + CurrentX) * 20 + 25, (y + CurrentY) * 20 - 5), new Point((x + CurrentX) * 20 + 25, (y + CurrentY) * 20 + 15), new Point((x + CurrentX) * 20 + 20, (y + CurrentY) * 20 + 20) }; g.FillPolygon(new SolidBrush(TricksColor[CurrentTrick[y, x, 1], 2]), myPoints2); } else { Point[] myPoints1 = { new Point((x + CurrentX) * 20 + 5, (y + CurrentY) * 20 - 5), new Point((x + CurrentX) * 20 + 20, (y + CurrentY) * 20 - 5), new Point((x + CurrentX) * 20 + 20, (y + CurrentY) * 20), new Point((x + CurrentX) * 20, (y + CurrentY) * 20) }; g.FillPolygon(new SolidBrush(TricksColor[CurrentTrick[y, x, 1], 1]), myPoints1); g.DrawPolygon(new Pen(panel1.BackColor), myPoints1); } } else { Point[] myPoints1 = { new Point((x + CurrentX) * 20 + 5, (y + CurrentY) * 20 - 5), new Point((x + CurrentX) * 20 + 20, (y + CurrentY) * 20 - 5), new Point((x + CurrentX) * 20 + 20, (y + CurrentY) * 20), new Point((x + CurrentX) * 20, (y + CurrentY) * 20) }; g.FillPolygon(new SolidBrush(TricksColor[CurrentTrick[y, x, 1], 1]), myPoints1); g.DrawPolygon(new Pen(panel1.BackColor), myPoints1); } } } } Graphics gg = panel1.CreateGraphics(); gg.DrawImage(myImage, 0, 0); }

关于绘图的代码其实也很容易理解,我们首先通过在原来图片的基础上在斜上方和斜右进行绘制,使得大家看起来像三维的砖块了。另外在绘制砖块的时候,采用了对背景判断,已经砖块衍生出来的色块会覆盖背景。

可玩性的优化:

首先,我们针对我们的游戏进行了关卡设置。我们使得游戏每增加1000分。游戏进入一关。没进入一关,速度都变快.用技术的语言讲:每进入一关,把timer的时间间隔缩小一部分即可。

private int Step = 1; //我们首先来申明个关卡的变量。

CheckSorce的函数相应的改变为:

/// <summary> /// 检测是否应该得分,可以优化 /// </summary> private void CheckSore() { for (int y = 19; y > lowY; y--) { bool isFull = true; for (int x = 13; x > -1; x--) { if (bgGraoud[y, x,0] == 0) { isFull = false; break; } } if (isFull) { //增加积分 lowY++; //减少了一行,循环就可以减少一行 Sorce = Sorce + 100; Step = Sorce / 1000 + 1; if (Step == 11) { timer1.Stop(); MessageBox.Show("恭喜恭喜,你的游戏过通关了"); } else { timer1.Interval = (11 - Step) * 100; for (int yy = y; yy > 0; yy--) { for (int xx = 0; xx < 14; xx++) { int temp = bgGraoud[yy - 1, xx, 0]; int temp2 = bgGraoud[yy - 1, xx, 1]; bgGraoud[yy, xx, 0] = temp; bgGraoud[yy, xx, 1] = temp2; } } y++; } label1.Text = "您现在的分数为:"+Sorce.ToString(); label1.Text += "/r/n您现在在:"; label1.Text += Step.ToString(); label1.Text += "关"; Draw(); } } }

其次,我们可以增加砖块的种类来优化游戏性:在这里只需要增加砖块数组和颜色数组的元素即可。

具体的可以看源码:俄罗斯方块.rar

此外如果你对这个游戏有任何问题,或者有任何建议,欢迎去csdn论坛一起讨论:

http://topic.csdn.net/u/20100218/15/d5c8a93f-5690-4efb-841e-5a290e7c183e.html

如果你在看这篇文章的话。你可以继续看看这个

http://blog.csdn.net/aofengdaxia/archive/2010/10/15/5944193.aspx