C# 實(shí)現(xiàn)俄羅斯方塊(附源碼)
概述
俄羅斯方塊(Tetris)是一款由俄羅斯人阿列克謝·帕基特諾夫發(fā)明的休閑游戲,帕基特諾夫愛(ài)玩拼圖,從拼圖游戲里得到靈感,設(shè)計(jì)出了俄羅斯方塊。由于上手簡(jiǎn)單、老少皆宜,從而家喻戶曉,風(fēng)靡世界。本文簡(jiǎn)述如何通過(guò)C#來(lái)實(shí)現(xiàn)俄羅斯方塊,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正。
涉及知識(shí)點(diǎn)
BackgroundWorker 在單獨(dú)的線程上執(zhí)行操作(主要執(zhí)行比較耗時(shí)的操作)。
Action .NetFramework自帶的一個(gè)委托方法。
TableLayoutPanel 表示一個(gè)面板,它可以在一個(gè)由行和列組成的網(wǎng)格中對(duì)其內(nèi)容進(jìn)行動(dòng)態(tài)布局,本文主要用作俄羅斯方塊的容器。
方塊流程圖
如下圖所示,描述了俄羅斯方塊的設(shè)計(jì)流程圖

俄羅斯方塊效果圖
如下圖所示:主要包括狀態(tài),得分,開(kāi)始按鈕,停止按鈕,按鍵盤(pán)左右箭頭移動(dòng)等功能

核心代碼
1. 定義方塊的形狀
如下所示:共7中形狀
/// <summary>
/// 俄羅斯方塊的形狀
/// </summary>
public enum TetrisStyle
{
S = 0,
Z = 1,
L = 2,
J = 3,
I = 4,
O = 5,
T = 6
}
2. 定義移動(dòng)的方向
如下所示:默認(rèn)向下移動(dòng),同時(shí)可以左右移動(dòng)
/// <summary>
/// 俄羅斯方塊移動(dòng)方向
/// </summary>
public enum TetrisDirection
{
UP = 0,//上,表示順時(shí)針旋轉(zhuǎn)
DOWN = 1,//下,表示向下移動(dòng)
LEFT = 2,//左,表示往左移動(dòng)
RIGHT = 3, //表示向右移動(dòng)
DEFAULT=4 //默認(rèn)動(dòng)作
}
3. 俄羅斯方塊元素
如下所示,每一種形狀都由四個(gè)方塊組成,根據(jù)不同形狀設(shè)置不同的位置
/// <summary>
/// 俄羅斯方塊元素
/// </summary>
public class TetrisElement
{
/// <summary>
/// 構(gòu)造函數(shù)
/// </summary>
/// <param name="style"></param>
public TetrisElement(TetrisStyle style) {
this.style = style;
}
/// <summary>
/// 構(gòu)造函數(shù)
/// </summary>
/// <param name="style">形狀</param>
/// <param name="content">內(nèi)容</param>
/// <param name="location">位置</param>
public TetrisElement(TetrisStyle style, Point[] content, Point location)
{
this.style = style;
this.content = content;
this.location = location;
}
/// <summary>
/// 元素字母類(lèi)型
/// </summary>
public TetrisStyle style { get; set; }
/// <summary>
/// 內(nèi)容
/// </summary>
public Point[] content { get; set; }
/// <summary>
/// 元素位置
/// </summary>
public Point location { get; set; }
/// <summary>
/// 位置改變
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public void move(int x, int y)
{
this.location = new Point(x, y);
}
public Point[] getContent(TetrisStyle style)
{
//內(nèi)容由四個(gè)點(diǎn)組成,順序:先上后下,先左后右
Point[] content = new Point[4];
switch (style)
{
case TetrisStyle.I:
//I形狀
content[0] = new Point(0, 0);
content[1] = new Point(0, 1);
content[2] = new Point(0, 2);
content[3] = new Point(0, 3);
break;
case TetrisStyle.J:
//J形狀
content[0] = new Point(1, 0);
content[1] = new Point(1, 1);
content[2] = new Point(1, 2);
content[3] = new Point(0, 2);
break;
case TetrisStyle.L:
//L形狀
content[0] = new Point(0, 0);
content[1] = new Point(0, 1);
content[2] = new Point(0, 2);
content[3] = new Point(1, 2);
break;
case TetrisStyle.O:
//O形狀
content[0] = new Point(0, 0);
content[1] = new Point(1, 0);
content[2] = new Point(0, 1);
content[3] = new Point(1, 1);
break;
case TetrisStyle.S:
//S形狀
content[0] = new Point(2, 0);
content[1] = new Point(1, 0);
content[2] = new Point(1, 1);
content[3] = new Point(0, 1);
break;
case TetrisStyle.T:
//T形狀
content[0] = new Point(0, 0);
content[1] = new Point(1, 0);
content[2] = new Point(2, 0);
content[3] = new Point(1, 1);
break;
case TetrisStyle.Z:
//Z形狀
content[0] = new Point(0, 0);
content[1] = new Point(1, 0);
content[2] = new Point(1, 1);
content[3] = new Point(2, 1);
break;
default:
//默認(rèn)I
content[0] = new Point(0, 0);
content[1] = new Point(0, 1);
content[2] = new Point(0, 2);
content[3] = new Point(0, 3);
break;
}
return content;
}
}
4. 容器類(lèi)
如下所示:容器類(lèi)主要是移動(dòng)方塊元素,并更新頁(yè)面上的值
/// <summary>
/// 俄羅斯方塊容器
/// </summary>
public class TetrisContainer
{
private int[,] tetris = new int[10, 20];//定義二維數(shù)組,表示坐標(biāo)信息,默認(rèn)值為0
public Action<Point,Point[],TetrisDirection> onPartialChanged;//局部變更事件
public Action<int[,]> onFullChanged;//元素全變更事件,即有整行被清除事件
public Action onCompleted; //結(jié)束事件
public int scorce = 0;
/// <summary>
/// 狀態(tài)發(fā)生改變
/// </summary>
/// <param name="element"></param>
/// <param name="direction"></param>
/// <returns></returns>
public TetrisElement change(TetrisElement element, TetrisDirection direction)
{
TetrisElement tmp=null;
//判斷不同的方向
switch (direction) {
case TetrisDirection.DEFAULT:
//如果可以向下移動(dòng)
if (checkDefault(element))
{
//向下移動(dòng)一個(gè)元素
element.move(element.location.X, element.location.Y + 1);
tmp = element;
}
else {
//如果不可以向下移動(dòng),則更新容器
updateTetris(element);
tmp = null;
}
break;
case TetrisDirection.DOWN:
break;
case TetrisDirection.UP:
break;
case TetrisDirection.LEFT:
if (checkLeft(element)){
//判斷是否可以向左移動(dòng)
//向下移動(dòng)一個(gè)元素
element.move(element.location.X-1, element.location.Y);
tmp = element;
}
break;
case TetrisDirection.RIGHT:
if (checkRight(element))
{
//判斷是否可以右左移動(dòng)
//向下移動(dòng)一個(gè)元素
element.move(element.location.X+1, element.location.Y);
tmp = element;
}
break;
}
//局部變更
if (onPartialChanged != null)
{
Point location = element.location;
Point[] content = new Point[4];
element.content.CopyTo(content, 0);
for (int i = 0; i < content.Length; i++)
{
content[i].X = location.X + content[i].X;
content[i].Y = location.Y + content[i].Y;
}
onPartialChanged(location,content,direction);
}
//判斷游戲是否結(jié)束
if (onCompleted != null) {
if (checkComplete()) {
onCompleted();
}
}
//全部變更
if (onFullChanged != null)
{
//判斷是是否有權(quán)為1的行,如果有則消掉
int[] rows = checkAllTetris();
if (rows.Length>0)
{
updateAllTetris(rows);//消掉行
onFullChanged(tetris);
}
}
return tmp;
}
/// <summary>
/// 更新tetris
/// </summary>
/// <param name="element"></param>
private void updateTetris(TetrisElement element)
{
Point location = element.location;
Point[] content = element.content;
int minX = element.getMinX(element.style);
int maxX = element.getMaxX(element.style);
int minY = element.getMinY(element.style);
int maxY = element.getMaxY(element.style);
foreach (Point p in content)
{
if (location.Y + p.Y < 20 && location.Y + p.Y >= 0 && location.X + p.X >= 0 && location.X + p.X < 10)
{
this.tetris[location.X + p.X, location.Y + p.Y] = 1;
}
}
}
/// <summary>
/// 檢查全部列
/// </summary>
private int[] checkAllTetris()
{
List<int> lst = new List<int>();
//20行
for (int y = 0; y < 20; y++)
{
int col = 0;
//10列
for (int x = 0; x < 10; x++)
{
if (tetris[x, y] == 0)
{
break;
}
else
{
col += 1;
}
}
if (col == 10)
{
col = 0;
lst.Add(y);
}
}
return lst.ToArray();
}
/// <summary>
/// 更新
/// </summary>
private void updateAllTetris(int[] rows) {
foreach (int row in rows) {
//當(dāng)前行清掉
for (int x = 0; x < 10; x++) {
tetris[x, row] = 0;
}
//row行之上的往下移動(dòng)一行
for (int y = row-1; y >=0; y--) {
for (int x = 0; x < 10; x++) {
if (tetris[x, y] == 1) {
tetris[x, y + 1] = 1;
tetris[x, y] = 0;
}
}
}
}
}
/// <summary>
/// 判斷游戲是否結(jié)束
/// </summary>
/// <returns></returns>
private bool checkComplete() {
bool isComplete = false;
for (int i = 0; i < 10; i++) {
if (tetris[i, 0] == 1) {
isComplete = true;
break;
}
}
return isComplete;
}
/// <summary>
/// 更新得分
/// </summary>
/// <param name="s"></param>
public void updateScore(int s) {
this.scorce = this.scorce + s;
}
/// <summary>
/// 重置信息
/// </summary>
public void Reset() {
this.tetris = new int[10, 20];
this.scorce = 0;
}
}
5. 隨機(jī)生成方塊元素和起始位置
/// <summary>
/// 靜態(tài)函數(shù),生成Tetris元素對(duì)象
/// </summary>
/// <returns></returns>
public static TetrisElement generate()
{
Random r = new Random(0);
//隨機(jī)生成形狀
int tstyle = getRandom();
tstyle = tstyle % 7;
TetrisStyle style = TetrisStyle.I;
style = (TetrisStyle)Enum.Parse(typeof(TetrisStyle), tstyle.ToString());
//隨機(jī)生成起始坐標(biāo)
int x = getRandom();
x = x % 10;
int y = 0;
//根據(jù)形狀生成位置信息
TetrisElement element = new TetrisElement(style);
//內(nèi)容由四個(gè)點(diǎn)組成,順序:先上后下,先左后右
Point[] content = element.getContent(style);
//獲取最小坐標(biāo)和最大坐標(biāo),防止越界
int minX = element.getMinX(style);
int minY = element.getMinY(style);
int maxX = element.getMaxX(style);
int maxY = element.getMaxY(style);
//修正起始坐標(biāo)
x = (x <= minX) ? minX : x;
x = (x >= maxX) ? maxX : x;
y = minY;
Point location = new Point(x, y);
element.location = location;
element.content = content;
return element;
}
備注
以上就是C# 實(shí)現(xiàn)俄羅斯方塊(附源碼)的詳細(xì)內(nèi)容,更多關(guān)于C# 實(shí)現(xiàn)俄羅斯方塊的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#實(shí)現(xiàn)觀察者模式(Observer?Pattern)的兩種方式
這篇文章介紹了C#實(shí)現(xiàn)觀察者模式(Observer?Pattern)的兩種方式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08
C#創(chuàng)建Windows服務(wù)的圖文教程
本文主要介紹了C#創(chuàng)建Windows服務(wù)的圖文教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
關(guān)于C#版Nebula客戶端編譯的問(wèn)題
這篇文章主要介紹了C#版Nebula客戶端編譯的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
C# PictureBox圖片控件實(shí)現(xiàn)圖片交換
在c#中可以使用PictureBox控件來(lái)呈現(xiàn)圖像,本文主要介紹了C# PictureBox實(shí)現(xiàn)圖片交換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06

