学习C#从俄罗斯方块开始(二)俄罗斯方块的规则和算法的简单实现
2012-10-27 22:11
686 查看
根据上节我们规划好的开发过程,这节我们来实现一个简单的俄罗斯方块程序。当然完成俄罗斯方块的Demo是我们这节课的最终目标。在实现这个目标的同时,我还要跟大家一起去分析俄罗斯方块的需求、算法、具体开发的步骤。并且最终选择C#语言来实现这个demo。下面废话少说,翠花,上内容!
第一步、 思考俄罗斯方块的游戏规则:
任何时候我们去开发或者设计一个项目,首先需要思考的就是需求。
俄罗斯方块中,我们要做一个俄罗斯方块的游戏,那么俄罗斯方块游戏的游戏规则就是我们的需求。所以我们必须深入了解俄罗斯方块游戏的游戏规则。俄罗斯方块游戏可能产生下面五种形状的方块。这些方块有我们的方向键的控制可以产生旋转,左右移动和加速前进等,往下掉,只到遇到下面已经有方块挡住停下来。如果一行完全排列满,则会消掉,如果排列到了顶部,则会失败。
第二步、把我们的“需求”从计算机的角度去分析:
我们对任何一个项目的最初的需求是从使用者的角度去描述这个项目的,这种描述基本上涵盖了使用者可能用到的功能和要求。我们在做一个项目,特别是为一个非计算机专业做一个项目的时候,客户的描述,或者业务人员承接到项目的时候,他们和客户的沟通,基本上是基于这种初级的需求的,这种初级的需求的有点是:客户和业务人员比较容易理解,沟通起来非常的方便。但是他的缺点是非计算机专业用语,不够规范和严谨。不能拿这个文档和需求来直接要求开发人员。需要一个对市场(客户)比较了解,同时又是资深的程序员把这个需求编程一个专业开发人员相对比较容易理解的需求。甚至直接编程开发的具体思路。然后有开发人员去实现。我们的小游戏实在是太小了,不可能分出来业务人员、项目规划人员、项目架构、程序开发。。。。所以这一切也都有我们开发者一个人独揽了。不过麻雀虽小,五脏俱全哦。我们不是说了嘛,通过学习俄罗斯方块掌握项目开发的经验呢。所以希望各位看客认真的看这些个步骤,如果我哪里说错了,欢迎拍砖。
a、关于俄罗斯方块游戏中方块的产生。我们假设产生四种方块。实际上俄罗斯方块产生的方块要多余四个。但是咱们这节课是做一个Demo,所以先做四个,具体的四个请见图片1。(因为CSDN不能上传图片,我上传到下载中去了。大家可以下载使用,期待csdn可以正常的上传图片)。
b、俄罗斯方块当需要变化方块的时候,每个方块需要顺时针旋转90°,具体可能产生的形状也见图一。
从数学,或者计算机的角度来看:我们根据图1来看,我们可以把所有的方块看成一个4*4的二维数组。把有“砖”的地方表示为1,没有“砖”的地方表示为0,所以所有的的方块都可以表示为图二的样式。
c、我们也可以把背景看成是14*20的二维数组。
那么俄罗斯方块的需求,站在程序员的角度上就可以变成:我们随机从方块的4个4*4的矩阵中挑选出来一个,并且随机的挑选一个他的初始化状态(关于状态变化,我们同样可以把他们表示在一个4*4的矩阵中)。然后这个被挑选的矩阵,在一个14*20的矩阵中不断的按照一种速度进行往下运动。我们同时可以使用方向键,对这个举证进行控制,使得它可以左右运动,同时可以循环的变化他的状态。如果这个矩阵在运动的方向上遇到了数值为1的时候则停止运动,在左右运动上表现为不能移动,在往下运动的时候则表现为这个方块运动的结束。把这个矩阵的数值复制到背景矩阵中去。这个时候检查背景矩阵,如果背景矩阵中有一个行全部为1,那么在y轴上比该行小的所有行向下移动一行,用户得分增加100。同理,检查所有的行,并且做同样动作。检查完成后,进入下个方块的随机挑选,下落。当某个方块下落完成的时候。他的y坐标在背景中为0的时候。游戏结束。作为游戏的界面,我们需要在游戏的状态发生改变的时候,把背景矩阵和运动矩阵都绘制出来。数值为0的地方不绘图,数值为1的地方绘制图片。
---------------------------------------------------------------------------
到此为止。我们的游戏已经用人类语言。从计算机的角度来说分析完成了。剩下的就是使用计算机语言表达出来了,不管你是学习的C#,C语言,C++,Delphi,Java,python,Js,VB,……(汇编我不懂,暂时不包括吧)。只要你能理解了上述的“思路”。那么你可以用任何语言来写出来。我真希望用所有的语言都给大家写写,把IT老祖宗的那句:“编程靠的是思想(想法,思路),语言不重要。"的真理来验证下,可怜CSDN的blog写起来太麻烦了,而且我老婆催着我赶紧回家过年的,所以这次就暂时使用C#来给大家实现下。我们就从一个C#盲来开始看看需要如何学习,如何实现。
首先、确定我们要用的语言是C#,矩阵的运算需要多是多维数组,数组的运算多需要循环。另外对多种情况的判断需要if,switch等分支判断语句,我们的方块定时运动,需要用到timer控件。所以在开始咱们的项目前,请确保,你已经对C#的语法有了基本的了解,尤其对数组的操作、if语句,for循环语句,switch语句要会用。同时对基本的button、timer控件进行基本的了解。如果你在使用其他语言编程,找你所使用的语言中的类似的东西。其他的东西至少这个项目中不会经常用到。即时用到,查查即可。这个可能就是所谓的“语言没有思想重要吧”。如果你还不懂,去看看<C#入门经典吧>.
其次、俄罗斯方块需要绘制图形,这个需要你对C# GDI+有所了解。在其他语言中可能是GDI或者API了,这个你只需要google下即可。如果GDI+编程你还不懂,那么来下载个教程吧。我已经给大家上传到:http://download.csdn.net/source/2057311
上面的两个条件如果你已经具有了。那么开始我们的C#俄罗斯方块的代码之旅途吧。
不过在代码开始之前,还是先看看我们的界面吧。请看界面图;
下面我们来看代码。首先定义我们的砖块和背景吧。
[c-sharp] view plaincopyprint?
#region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行
private int[, , ,] Tricks = {{
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
}};
#endregion
#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}
};
#endregion
定义好了变量,我们来想想我们的几个函数吧。首先是变化砖块,变化砖块其实就是变化砖块的状态,把砖块数组中的状态位进行循环变化即可:
[c-sharp] view plaincopyprint?
/// <summary>
/// 变化方块
/// </summary>
private void ChangeTricks()
{
if (CurrentStatusNum < 3)
{
CurrentStatusNum++;
}
else
{
CurrentStatusNum = 0;
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y, x] = Tricks[CurrentTrickNum, CurrentStatusNum, y, x];
}
}
}
下面是绘制函数:没啥思路,循环画出即可
[c-sharp] view plaincopyprint?
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);
}
好像忘记了如何开始向下落的哦。看代码:太容易了,不解释了。
[c-sharp] view plaincopyprint?
private void BeginTricks()
{
//随机生成砖码和状态码
int i = rand.Next(0, TricksNum);
int j = rand.Next(0, StatusNum);
CurrentTrickNum = i;
CurrentStatusNum = j;
//分配数组
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y,x] = Tricks[i,j,y,x];
}
}
CurrentX = 0;
CurrentY = 0;
timer1.Start();
}
还有几个函数大家都可以看懂的,我就不讲解了。我把所有的代码都贴一遍。另外把所有的图片和源文件打包后上传到csdn,请大家下载。
代码下载地址:http://download.csdn.net/source/2057359
[c-sharp] view plaincopyprint?
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;
namespace Tetris
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行
private int[, , ,] Tricks = {{
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
}};
#endregion
#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}
};
#endregion
private int[,] CurrentTrick = new int[4, 4]; //当前的砖块
//CurrentTrickNum当前砖块的数目, CurrentStatusNum当前状态, CurrentX当前x, CurrentY当前y, Sorce分数
private int CurrentTrickNum, CurrentStatusNum, CurrentX, CurrentY, Sorce;
private int TricksNum = 4;
private int StatusNum = 4;
private Image myImage;
private Random rand = new Random();
private void Form1_Load(object sender, EventArgs e)
{
//初始化
myImage = new Bitmap(panel1.Width, panel1.Height);
Sorce = 0;
}
protected override void OnPaint(PaintEventArgs e)
{
Draw();
base.OnPaint(e);
}
private void button1_Click(object sender, EventArgs e)
{
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 14; x++)
{
bgGraoud[y, x] = 0;
}
}
timer1.Interval = 1000;
BeginTricks();
this.Focus();
}
/// <summary>
/// 随机生成方块和状态
/// </summary>
private void BeginTricks()
{
//随机生成砖码和状态码
int i = rand.Next(0, TricksNum);
int j = rand.Next(0, StatusNum);
CurrentTrickNum = i;
CurrentStatusNum = j;
//分配数组
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y,x] = Tricks[i,j,y,x];
}
}
CurrentX = 0;
CurrentY = 0;
timer1.Start();
}
/// <summary>
/// 变化方块
/// </summary>
private void ChangeTricks()
{
if (CurrentStatusNum < 3)
{
CurrentStatusNum++;
}
else
{
CurrentStatusNum = 0;
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y, x] = Tricks[CurrentTrickNum, CurrentStatusNum, y, x];
}
}
}
/// <summary>
/// 下落方块
/// </summary>
private void DownTricks()
{
if (CheckIsDown())
{
CurrentY++;
}
else
{
if (CurrentY == 0)
{
timer1.Stop();
MessageBox.Show("哈哈,你玩玩了");
return;
}
//下落完成,修改背景
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
bgGraoud[CurrentY + y, CurrentX + x] = CurrentTrick[y, x];
}
}
}
CheckSore();
BeginTricks();
}
Draw();
}
/// <summary>
/// 检测是否可以向下了
/// </summary>
/// <returns></returns>
private bool CheckIsDown()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
//超过了背景
if (y + CurrentY + 1 >= 20)
{
return false;
}
if (x + CurrentX >= 14)
{
CurrentX = 13 - x;
}
if (bgGraoud[y + CurrentY + 1, x + CurrentX] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以左移
/// </summary>
/// <returns></returns>
private bool CheckIsLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX - 1 < 0)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX - 1] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以右移
/// </summary>
/// <returns></returns>
private bool CheckIsRight()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX + 1 >= 14)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX+1] == 1)
{
return false;
}
}
}
}
return true;
}
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 timer1_Tick(object sender, EventArgs e)
{
DownTricks();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
{
ChangeTricks();
Draw();
}
else if (e.KeyCode == Keys.A)
{
if (CheckIsLeft())
{
CurrentX--;
}
Draw();
}
else if (e.KeyCode == Keys.D)
{
if (CheckIsRight())
{
CurrentX++;
}
Draw();
}
else if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 10;
timer1.Start();
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 1000;
timer1.Start();
}
}
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 button2_Click(object sender, EventArgs e)
{
if (button2.Text == "暂停游戏")
{
button2.Text = "开始游戏";
timer1.Stop();
}
else
{
button2.Text = "暂停游戏";
timer1.Start();
}
}
}
}
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;
namespace Tetris
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行
private int[, , ,] Tricks = {{
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
}};
#endregion
#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}
};
#endregion
private int[,] CurrentTrick = new int[4, 4]; //当前的砖块
//CurrentTrickNum当前砖块的数目, CurrentStatusNum当前状态, CurrentX当前x, CurrentY当前y, Sorce分数
private int CurrentTrickNum, CurrentStatusNum, CurrentX, CurrentY, Sorce;
private int TricksNum = 4;
private int StatusNum = 4;
private Image myImage;
private Random rand = new Random();
private void Form1_Load(object sender, EventArgs e)
{
//初始化
myImage = new Bitmap(panel1.Width, panel1.Height);
Sorce = 0;
}
protected override void OnPaint(PaintEventArgs e)
{
Draw();
base.OnPaint(e);
}
private void button1_Click(object sender, EventArgs e)
{
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 14; x++)
{
bgGraoud[y, x] = 0;
}
}
timer1.Interval = 1000;
BeginTricks();
this.Focus();
}
/// <summary>
/// 随机生成方块和状态
/// </summary>
private void BeginTricks()
{
//随机生成砖码和状态码
int i = rand.Next(0, TricksNum);
int j = rand.Next(0, StatusNum);
CurrentTrickNum = i;
CurrentStatusNum = j;
//分配数组
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y,x] = Tricks[i,j,y,x];
}
}
CurrentX = 0;
CurrentY = 0;
timer1.Start();
}
/// <summary>
/// 变化方块
/// </summary>
private void ChangeTricks()
{
if (CurrentStatusNum < 3)
{
CurrentStatusNum++;
}
else
{
CurrentStatusNum = 0;
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y, x] = Tricks[CurrentTrickNum, CurrentStatusNum, y, x];
}
}
}
/// <summary>
/// 下落方块
/// </summary>
private void DownTricks()
{
if (CheckIsDown())
{
CurrentY++;
}
else
{
if (CurrentY == 0)
{
timer1.Stop();
MessageBox.Show("哈哈,你玩玩了");
return;
}
//下落完成,修改背景
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
bgGraoud[CurrentY + y, CurrentX + x] = CurrentTrick[y, x];
}
}
}
CheckSore();
BeginTricks();
}
Draw();
}
/// <summary>
/// 检测是否可以向下了
/// </summary>
/// <returns></returns>
private bool CheckIsDown()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
//超过了背景
if (y + CurrentY + 1 >= 20)
{
return false;
}
if (x + CurrentX >= 14)
{
CurrentX = 13 - x;
}
if (bgGraoud[y + CurrentY + 1, x + CurrentX] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以左移
/// </summary>
/// <returns></returns>
private bool CheckIsLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX - 1 < 0)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX - 1] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以右移
/// </summary>
/// <returns></returns>
private bool CheckIsRight()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX + 1 >= 14)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX+1] == 1)
{
return false;
}
}
}
}
return true;
}
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 timer1_Tick(object sender, EventArgs e)
{
DownTricks();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
{
ChangeTricks();
Draw();
}
else if (e.KeyCode == Keys.A)
{
if (CheckIsLeft())
{
CurrentX--;
}
Draw();
}
else if (e.KeyCode == Keys.D)
{
if (CheckIsRight())
{
CurrentX++;
}
Draw();
}
else if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 10;
timer1.Start();
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 1000;
timer1.Start();
}
}
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 button2_Click(object sender, EventArgs e)
{
if (button2.Text == "暂停游戏")
{
button2.Text = "开始游戏";
timer1.Stop();
}
else
{
button2.Text = "暂停游戏";
timer1.Start();
}
}
}
}
本文章来自:/article/2605746.html
在接下来的内容中,我们把这个DEMO做成一个三维的俄罗斯方块。
详情请打开:http://blog.csdn.net/aofengdaxia/archive/2010/02/18/5310742.aspx
第一步、 思考俄罗斯方块的游戏规则:
任何时候我们去开发或者设计一个项目,首先需要思考的就是需求。
俄罗斯方块中,我们要做一个俄罗斯方块的游戏,那么俄罗斯方块游戏的游戏规则就是我们的需求。所以我们必须深入了解俄罗斯方块游戏的游戏规则。俄罗斯方块游戏可能产生下面五种形状的方块。这些方块有我们的方向键的控制可以产生旋转,左右移动和加速前进等,往下掉,只到遇到下面已经有方块挡住停下来。如果一行完全排列满,则会消掉,如果排列到了顶部,则会失败。
第二步、把我们的“需求”从计算机的角度去分析:
我们对任何一个项目的最初的需求是从使用者的角度去描述这个项目的,这种描述基本上涵盖了使用者可能用到的功能和要求。我们在做一个项目,特别是为一个非计算机专业做一个项目的时候,客户的描述,或者业务人员承接到项目的时候,他们和客户的沟通,基本上是基于这种初级的需求的,这种初级的需求的有点是:客户和业务人员比较容易理解,沟通起来非常的方便。但是他的缺点是非计算机专业用语,不够规范和严谨。不能拿这个文档和需求来直接要求开发人员。需要一个对市场(客户)比较了解,同时又是资深的程序员把这个需求编程一个专业开发人员相对比较容易理解的需求。甚至直接编程开发的具体思路。然后有开发人员去实现。我们的小游戏实在是太小了,不可能分出来业务人员、项目规划人员、项目架构、程序开发。。。。所以这一切也都有我们开发者一个人独揽了。不过麻雀虽小,五脏俱全哦。我们不是说了嘛,通过学习俄罗斯方块掌握项目开发的经验呢。所以希望各位看客认真的看这些个步骤,如果我哪里说错了,欢迎拍砖。
a、关于俄罗斯方块游戏中方块的产生。我们假设产生四种方块。实际上俄罗斯方块产生的方块要多余四个。但是咱们这节课是做一个Demo,所以先做四个,具体的四个请见图片1。(因为CSDN不能上传图片,我上传到下载中去了。大家可以下载使用,期待csdn可以正常的上传图片)。
b、俄罗斯方块当需要变化方块的时候,每个方块需要顺时针旋转90°,具体可能产生的形状也见图一。
从数学,或者计算机的角度来看:我们根据图1来看,我们可以把所有的方块看成一个4*4的二维数组。把有“砖”的地方表示为1,没有“砖”的地方表示为0,所以所有的的方块都可以表示为图二的样式。
c、我们也可以把背景看成是14*20的二维数组。
那么俄罗斯方块的需求,站在程序员的角度上就可以变成:我们随机从方块的4个4*4的矩阵中挑选出来一个,并且随机的挑选一个他的初始化状态(关于状态变化,我们同样可以把他们表示在一个4*4的矩阵中)。然后这个被挑选的矩阵,在一个14*20的矩阵中不断的按照一种速度进行往下运动。我们同时可以使用方向键,对这个举证进行控制,使得它可以左右运动,同时可以循环的变化他的状态。如果这个矩阵在运动的方向上遇到了数值为1的时候则停止运动,在左右运动上表现为不能移动,在往下运动的时候则表现为这个方块运动的结束。把这个矩阵的数值复制到背景矩阵中去。这个时候检查背景矩阵,如果背景矩阵中有一个行全部为1,那么在y轴上比该行小的所有行向下移动一行,用户得分增加100。同理,检查所有的行,并且做同样动作。检查完成后,进入下个方块的随机挑选,下落。当某个方块下落完成的时候。他的y坐标在背景中为0的时候。游戏结束。作为游戏的界面,我们需要在游戏的状态发生改变的时候,把背景矩阵和运动矩阵都绘制出来。数值为0的地方不绘图,数值为1的地方绘制图片。
---------------------------------------------------------------------------
到此为止。我们的游戏已经用人类语言。从计算机的角度来说分析完成了。剩下的就是使用计算机语言表达出来了,不管你是学习的C#,C语言,C++,Delphi,Java,python,Js,VB,……(汇编我不懂,暂时不包括吧)。只要你能理解了上述的“思路”。那么你可以用任何语言来写出来。我真希望用所有的语言都给大家写写,把IT老祖宗的那句:“编程靠的是思想(想法,思路),语言不重要。"的真理来验证下,可怜CSDN的blog写起来太麻烦了,而且我老婆催着我赶紧回家过年的,所以这次就暂时使用C#来给大家实现下。我们就从一个C#盲来开始看看需要如何学习,如何实现。
首先、确定我们要用的语言是C#,矩阵的运算需要多是多维数组,数组的运算多需要循环。另外对多种情况的判断需要if,switch等分支判断语句,我们的方块定时运动,需要用到timer控件。所以在开始咱们的项目前,请确保,你已经对C#的语法有了基本的了解,尤其对数组的操作、if语句,for循环语句,switch语句要会用。同时对基本的button、timer控件进行基本的了解。如果你在使用其他语言编程,找你所使用的语言中的类似的东西。其他的东西至少这个项目中不会经常用到。即时用到,查查即可。这个可能就是所谓的“语言没有思想重要吧”。如果你还不懂,去看看<C#入门经典吧>.
其次、俄罗斯方块需要绘制图形,这个需要你对C# GDI+有所了解。在其他语言中可能是GDI或者API了,这个你只需要google下即可。如果GDI+编程你还不懂,那么来下载个教程吧。我已经给大家上传到:http://download.csdn.net/source/2057311
上面的两个条件如果你已经具有了。那么开始我们的C#俄罗斯方块的代码之旅途吧。
不过在代码开始之前,还是先看看我们的界面吧。请看界面图;
下面我们来看代码。首先定义我们的砖块和背景吧。
[c-sharp] view plaincopyprint?
#region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行
private int[, , ,] Tricks = {{
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
}};
#endregion
#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}
};
#endregion
[c-sharp] view plaincopyprint? private int[,] CurrentTrick = new int[4, 4]; //当前的砖块 //CurrentTrickNum当前砖块的数目, CurrentStatusNum当前状态, CurrentX当前x, CurrentY当前y, Sorce分数 private int CurrentTrickNum, CurrentStatusNum, CurrentX, CurrentY, Sorce; private int TricksNum = 4; private int StatusNum = 4; private Image myImage; private Random rand = new Random(); private int[,] CurrentTrick = new int[4, 4]; //当前的砖块 //CurrentTrickNum当前砖块的数目, CurrentStatusNum当前状态, CurrentX当前x, CurrentY当前y, Sorce分数 private int CurrentTrickNum, CurrentStatusNum, CurrentX, CurrentY, Sorce; private int TricksNum = 4; private int StatusNum = 4; private Image myImage; private Random rand = new Random();
定义好了变量,我们来想想我们的几个函数吧。首先是变化砖块,变化砖块其实就是变化砖块的状态,把砖块数组中的状态位进行循环变化即可:
[c-sharp] view plaincopyprint?
/// <summary>
/// 变化方块
/// </summary>
private void ChangeTricks()
{
if (CurrentStatusNum < 3)
{
CurrentStatusNum++;
}
else
{
CurrentStatusNum = 0;
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y, x] = Tricks[CurrentTrickNum, CurrentStatusNum, y, x];
}
}
}
[c-sharp] view plaincopyprint? /// <summary> /// 检测是否可以向下了 /// </summary> /// <returns></returns> private bool CheckIsDown() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { //超过了背景 if (y + CurrentY + 1 >= 20) { return false; } if (x + CurrentX >= 14) { CurrentX = 13 - x; } if (bgGraoud[y + CurrentY + 1, x + CurrentX] == 1) { return false; } } } } return true; } /// <summary> /// 检测是否可以左移 /// </summary> /// <returns></returns> private bool CheckIsLeft() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { if (x + CurrentX - 1 < 0) { return false; } if (bgGraoud[y + CurrentY, x + CurrentX - 1] == 1) { return false; } } } } return true; } /// <summary> /// 检测是否可以右移 /// </summary> /// <returns></returns> private bool CheckIsRight() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { if (x + CurrentX + 1 >= 14) { return false; } if (bgGraoud[y + CurrentY, x + CurrentX+1] == 1) { return false; } } } } return true; } /// <summary> /// 检测是否可以向下了 /// </summary> /// <returns></returns> private bool CheckIsDown() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { //超过了背景 if (y + CurrentY + 1 >= 20) { return false; } if (x + CurrentX >= 14) { CurrentX = 13 - x; } if (bgGraoud[y + CurrentY + 1, x + CurrentX] == 1) { return false; } } } } return true; } /// <summary> /// 检测是否可以左移 /// </summary> /// <returns></returns> private bool CheckIsLeft() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { if (x + CurrentX - 1 < 0) { return false; } if (bgGraoud[y + CurrentY, x + CurrentX - 1] == 1) { return false; } } } } return true; } /// <summary> /// 检测是否可以右移 /// </summary> /// <returns></returns> private bool CheckIsRight() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { if (x + CurrentX + 1 >= 14) { return false; } if (bgGraoud[y + CurrentY, x + CurrentX+1] == 1) { return false; } } } } return true; }
下面是绘制函数:没啥思路,循环画出即可
[c-sharp] view plaincopyprint?
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);
}
[c-sharp] view plaincopyprint? /// <summary> /// 下落方块 /// </summary> private void DownTricks() { if (CheckIsDown()) { CurrentY++; } else { if (CurrentY == 0) { timer1.Stop(); MessageBox.Show("哈哈,你玩玩了"); return; } //下落完成,修改背景 for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { bgGraoud[CurrentY + y, CurrentX + x] = CurrentTrick[y, x]; } } } CheckSore(); BeginTricks(); } Draw(); } /// <summary> /// 下落方块 /// </summary> private void DownTricks() { if (CheckIsDown()) { CurrentY++; } else { if (CurrentY == 0) { timer1.Stop(); MessageBox.Show("哈哈,你玩玩了"); return; } //下落完成,修改背景 for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if (CurrentTrick[y, x] == 1) { bgGraoud[CurrentY + y, CurrentX + x] = CurrentTrick[y, x]; } } } CheckSore(); BeginTricks(); } Draw(); }
好像忘记了如何开始向下落的哦。看代码:太容易了,不解释了。
[c-sharp] view plaincopyprint?
private void BeginTricks()
{
//随机生成砖码和状态码
int i = rand.Next(0, TricksNum);
int j = rand.Next(0, StatusNum);
CurrentTrickNum = i;
CurrentStatusNum = j;
//分配数组
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y,x] = Tricks[i,j,y,x];
}
}
CurrentX = 0;
CurrentY = 0;
timer1.Start();
}
[c-sharp] view plaincopyprint? 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 > -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(); } } }
还有几个函数大家都可以看懂的,我就不讲解了。我把所有的代码都贴一遍。另外把所有的图片和源文件打包后上传到csdn,请大家下载。
代码下载地址:http://download.csdn.net/source/2057359
[c-sharp] view plaincopyprint?
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;
namespace Tetris
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行
private int[, , ,] Tricks = {{
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
}};
#endregion
#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}
};
#endregion
private int[,] CurrentTrick = new int[4, 4]; //当前的砖块
//CurrentTrickNum当前砖块的数目, CurrentStatusNum当前状态, CurrentX当前x, CurrentY当前y, Sorce分数
private int CurrentTrickNum, CurrentStatusNum, CurrentX, CurrentY, Sorce;
private int TricksNum = 4;
private int StatusNum = 4;
private Image myImage;
private Random rand = new Random();
private void Form1_Load(object sender, EventArgs e)
{
//初始化
myImage = new Bitmap(panel1.Width, panel1.Height);
Sorce = 0;
}
protected override void OnPaint(PaintEventArgs e)
{
Draw();
base.OnPaint(e);
}
private void button1_Click(object sender, EventArgs e)
{
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 14; x++)
{
bgGraoud[y, x] = 0;
}
}
timer1.Interval = 1000;
BeginTricks();
this.Focus();
}
/// <summary>
/// 随机生成方块和状态
/// </summary>
private void BeginTricks()
{
//随机生成砖码和状态码
int i = rand.Next(0, TricksNum);
int j = rand.Next(0, StatusNum);
CurrentTrickNum = i;
CurrentStatusNum = j;
//分配数组
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y,x] = Tricks[i,j,y,x];
}
}
CurrentX = 0;
CurrentY = 0;
timer1.Start();
}
/// <summary>
/// 变化方块
/// </summary>
private void ChangeTricks()
{
if (CurrentStatusNum < 3)
{
CurrentStatusNum++;
}
else
{
CurrentStatusNum = 0;
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y, x] = Tricks[CurrentTrickNum, CurrentStatusNum, y, x];
}
}
}
/// <summary>
/// 下落方块
/// </summary>
private void DownTricks()
{
if (CheckIsDown())
{
CurrentY++;
}
else
{
if (CurrentY == 0)
{
timer1.Stop();
MessageBox.Show("哈哈,你玩玩了");
return;
}
//下落完成,修改背景
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
bgGraoud[CurrentY + y, CurrentX + x] = CurrentTrick[y, x];
}
}
}
CheckSore();
BeginTricks();
}
Draw();
}
/// <summary>
/// 检测是否可以向下了
/// </summary>
/// <returns></returns>
private bool CheckIsDown()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
//超过了背景
if (y + CurrentY + 1 >= 20)
{
return false;
}
if (x + CurrentX >= 14)
{
CurrentX = 13 - x;
}
if (bgGraoud[y + CurrentY + 1, x + CurrentX] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以左移
/// </summary>
/// <returns></returns>
private bool CheckIsLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX - 1 < 0)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX - 1] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以右移
/// </summary>
/// <returns></returns>
private bool CheckIsRight()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX + 1 >= 14)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX+1] == 1)
{
return false;
}
}
}
}
return true;
}
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 timer1_Tick(object sender, EventArgs e)
{
DownTricks();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
{
ChangeTricks();
Draw();
}
else if (e.KeyCode == Keys.A)
{
if (CheckIsLeft())
{
CurrentX--;
}
Draw();
}
else if (e.KeyCode == Keys.D)
{
if (CheckIsRight())
{
CurrentX++;
}
Draw();
}
else if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 10;
timer1.Start();
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 1000;
timer1.Start();
}
}
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 button2_Click(object sender, EventArgs e)
{
if (button2.Text == "暂停游戏")
{
button2.Text = "开始游戏";
timer1.Stop();
}
else
{
button2.Text = "暂停游戏";
timer1.Start();
}
}
}
}
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;
namespace Tetris
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
#region 定义砖块int[i,j,y,x] Tricks:i为那块砖,j为状态,y为列,x为行
private int[, , ,] Tricks = {{
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,0,0,0},
{1,0,0,0}
},
{
{1,1,1,1},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,1,1,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0}
}
},
{
{
{1,1,0,0},
{0,1,0,0},
{0,1,0,0},
{0,0,0,0}
},
{
{0,0,1,0},
{1,1,1,0},
{0,0,0,0},
{0,0,0,0}
},
{
{1,0,0,0},
{1,0,0,0},
{1,1,0,0},
{0,0,0,0}
},
{
{1,1,1,0},
{1,0,0,0},
{0,0,0,0},
{0,0,0,0}
}
}};
#endregion
#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}
};
#endregion
private int[,] CurrentTrick = new int[4, 4]; //当前的砖块
//CurrentTrickNum当前砖块的数目, CurrentStatusNum当前状态, CurrentX当前x, CurrentY当前y, Sorce分数
private int CurrentTrickNum, CurrentStatusNum, CurrentX, CurrentY, Sorce;
private int TricksNum = 4;
private int StatusNum = 4;
private Image myImage;
private Random rand = new Random();
private void Form1_Load(object sender, EventArgs e)
{
//初始化
myImage = new Bitmap(panel1.Width, panel1.Height);
Sorce = 0;
}
protected override void OnPaint(PaintEventArgs e)
{
Draw();
base.OnPaint(e);
}
private void button1_Click(object sender, EventArgs e)
{
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 14; x++)
{
bgGraoud[y, x] = 0;
}
}
timer1.Interval = 1000;
BeginTricks();
this.Focus();
}
/// <summary>
/// 随机生成方块和状态
/// </summary>
private void BeginTricks()
{
//随机生成砖码和状态码
int i = rand.Next(0, TricksNum);
int j = rand.Next(0, StatusNum);
CurrentTrickNum = i;
CurrentStatusNum = j;
//分配数组
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y,x] = Tricks[i,j,y,x];
}
}
CurrentX = 0;
CurrentY = 0;
timer1.Start();
}
/// <summary>
/// 变化方块
/// </summary>
private void ChangeTricks()
{
if (CurrentStatusNum < 3)
{
CurrentStatusNum++;
}
else
{
CurrentStatusNum = 0;
}
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
CurrentTrick[y, x] = Tricks[CurrentTrickNum, CurrentStatusNum, y, x];
}
}
}
/// <summary>
/// 下落方块
/// </summary>
private void DownTricks()
{
if (CheckIsDown())
{
CurrentY++;
}
else
{
if (CurrentY == 0)
{
timer1.Stop();
MessageBox.Show("哈哈,你玩玩了");
return;
}
//下落完成,修改背景
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
bgGraoud[CurrentY + y, CurrentX + x] = CurrentTrick[y, x];
}
}
}
CheckSore();
BeginTricks();
}
Draw();
}
/// <summary>
/// 检测是否可以向下了
/// </summary>
/// <returns></returns>
private bool CheckIsDown()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
//超过了背景
if (y + CurrentY + 1 >= 20)
{
return false;
}
if (x + CurrentX >= 14)
{
CurrentX = 13 - x;
}
if (bgGraoud[y + CurrentY + 1, x + CurrentX] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以左移
/// </summary>
/// <returns></returns>
private bool CheckIsLeft()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX - 1 < 0)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX - 1] == 1)
{
return false;
}
}
}
}
return true;
}
/// <summary>
/// 检测是否可以右移
/// </summary>
/// <returns></returns>
private bool CheckIsRight()
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
if (CurrentTrick[y, x] == 1)
{
if (x + CurrentX + 1 >= 14)
{
return false;
}
if (bgGraoud[y + CurrentY, x + CurrentX+1] == 1)
{
return false;
}
}
}
}
return true;
}
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 timer1_Tick(object sender, EventArgs e)
{
DownTricks();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
{
ChangeTricks();
Draw();
}
else if (e.KeyCode == Keys.A)
{
if (CheckIsLeft())
{
CurrentX--;
}
Draw();
}
else if (e.KeyCode == Keys.D)
{
if (CheckIsRight())
{
CurrentX++;
}
Draw();
}
else if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 10;
timer1.Start();
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.S)
{
timer1.Stop();
timer1.Interval = 1000;
timer1.Start();
}
}
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 button2_Click(object sender, EventArgs e)
{
if (button2.Text == "暂停游戏")
{
button2.Text = "开始游戏";
timer1.Stop();
}
else
{
button2.Text = "暂停游戏";
timer1.Start();
}
}
}
}
本文章来自:/article/2605746.html
在接下来的内容中,我们把这个DEMO做成一个三维的俄罗斯方块。
详情请打开:http://blog.csdn.net/aofengdaxia/archive/2010/02/18/5310742.aspx
相关文章推荐
- 学习C#从俄罗斯方块开始(二)俄罗斯方块的规则和算法的简单实现
- 用C#实现的简单树型图生成算法!
- 小白学数据:教你用Python实现简单监督学习算法
- 1.1 KNN算法学习——KNN算法的原理及简单实现
- Windows Phone 8 学习志(探索问题一:如何简单利用Windows Phone Runtime Component项目类型实现C#和C++交互)
- 学习C#从俄罗斯方块开始(三)俄罗斯方块的优化和美化
- Hebbian学习规则 2神经元 简单实现
- 感知机学习算法的简单实现(Python)
- 算法研究学习一(用C和C#实现)
- C# 学习自定义控件,从一个简单实用的日期控件开始。
- Hebbian学习规则 2神经元 简单实现
- 学习:C#实现一个简单的爬虫
- 学习javascript的闭包特性用C#来实现一个简单的例子
- WPF学习——制作一个简单的录入界面(2):用C#编程实现所有控件的功能
- 深度学习笔记(二):简单神经网络,后向传播算法及实现
- 学习C#从俄罗斯方块开始(一)概述
- 设计模式学习(四): 1.简单工厂 (附C#实现)
- C#学习之逆波兰公式简单实现
- 算法学习,单链表 C# 泛型实现
- C# int to BCD encode(最简单的实现办法)BCD编码编程实现算法