俄罗斯方块游戏,使用C#和Windows Forms实现。
完整代码实现
csharp
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Diagnostics;
namespace TetrisGame
{
public partial class TetrisForm : Form
{
// 游戏常量
private const int BoardWidth = 10;
private const int BoardHeight = 20;
private const int CellSize = 30;
private const int PreviewSize = 5;
// 游戏状态
private int[,] gameBoard;
private Tetromino currentPiece;
private Tetromino nextPiece;
private Random random;
private bool isGameActive;
private int score;
private int level;
private int linesCleared;
private int fallSpeed;
private int fallCounter;
private Stopwatch gameTimer;
// 颜色定义
private readonly Color[] tetrominoColors =
{
Color.Cyan, // I
Color.Blue, // J
Color.Orange, // L
Color.Yellow, // O
Color.Green, // S
Color.Purple, // T
Color.Red // Z
};
// 方块形状定义
private readonly int[][,] tetrominoShapes =
{
// I
new int[,] { {1,1,1,1} },
// J
new int[,] { {1,0,0}, {1,1,1} },
// L
new int[,] { {0,0,1}, {1,1,1} },
// O
new int[,] { {1,1}, {1,1} },
// S
new int[,] { {0,1,1}, {1,1,0} },
// T
new int[,] { {0,1,0}, {1,1,1} },
// Z
new int[,] { {1,1,0}, {0,1,1} }
};
// UI组件
private Panel gamePanel;
private Panel previewPanel;
private Label scoreLabel;
private Label levelLabel;
private Label linesLabel;
private Button startButton;
private Button pauseButton;
private Label gameStatusLabel;
public TetrisForm()
{
InitializeGame();
InitializeComponents();
SetupGameLoop();
}
private void InitializeGame()
{
gameBoard = new int[BoardHeight, BoardWidth];
random = new Random();
isGameActive = false;
score = 0;
level = 1;
linesCleared = 0;
fallSpeed = 30; // 初始下落速度(值越小越快)
fallCounter = 0;
gameTimer = new Stopwatch();
}
private void InitializeComponents()
{
// 窗体设置
this.Text = "俄罗斯方块 - C# 实现";
this.ClientSize = new Size(800, 650);
this.BackColor = Color.FromArgb(30, 30, 50);
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.KeyPreview = true;
this.KeyDown += TetrisForm_KeyDown;
// 游戏主面板
gamePanel = new Panel
{
Location = new Point(20, 20),
Size = new Size(BoardWidth * CellSize, BoardHeight * CellSize),
BackColor = Color.Black,
BorderStyle = BorderStyle.Fixed3D
};
gamePanel.Paint += GamePanel_Paint;
this.Controls.Add(gamePanel);
// 预览面板
previewPanel = new Panel
{
Location = new Point(400, 20),
Size = new Size(PreviewSize * CellSize, PreviewSize * CellSize),
BackColor = Color.Black,
BorderStyle = BorderStyle.Fixed3D
};
previewPanel.Paint += PreviewPanel_Paint;
this.Controls.Add(previewPanel);
// 分数标签
scoreLabel = new Label
{
Location = new Point(400, 200),
Size = new Size(200, 30),
Text = "分数: 0",
Font = new Font("Arial", 14, FontStyle.Bold),
ForeColor = Color.White,
BackColor = Color.Transparent
};
this.Controls.Add(scoreLabel);
// 等级标签
levelLabel = new Label
{
Location = new Point(400, 240),
Size = new Size(200, 30),
Text = "等级: 1",
Font = new Font("Arial", 14, FontStyle.Bold),
ForeColor = Color.White,
BackColor = Color.Transparent
};
this.Controls.Add(levelLabel);
// 消除行数标签
linesLabel = new Label
{
Location = new Point(400, 280),
Size = new Size(200, 30),
Text = "消除行数: 0",
Font = new Font("Arial", 14, FontStyle.Bold),
ForeColor = Color.White,
BackColor = Color.Transparent
};
this.Controls.Add(linesLabel);
// 游戏状态标签
gameStatusLabel = new Label
{
Location = new Point(400, 120),
Size = new Size(200, 60),
Text = "按开始游戏",
Font = new Font("Arial", 16, FontStyle.Bold),
ForeColor = Color.Yellow,
BackColor = Color.Transparent,
TextAlign = ContentAlignment.MiddleCenter
};
this.Controls.Add(gameStatusLabel);
// 开始按钮
startButton = new Button
{
Location = new Point(400, 350),
Size = new Size(120, 40),
Text = "开始游戏",
Font = new Font("Arial", 12, FontStyle.Bold),
BackColor = Color.FromArgb(70, 130, 180),
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat
};
startButton.Click += StartButton_Click;
this.Controls.Add(startButton);
// 暂停按钮
pauseButton = new Button
{
Location = new Point(540, 350),
Size = new Size(120, 40),
Text = "暂停游戏",
Font = new Font("Arial", 12, FontStyle.Bold),
BackColor = Color.FromArgb(70, 130, 180),
ForeColor = Color.White,
FlatStyle = FlatStyle.Flat,
Enabled = false
};
pauseButton.Click += PauseButton_Click;
this.Controls.Add(pauseButton);
// 控制说明标签
Label controlsLabel = new Label
{
Location = new Point(400, 420),
Size = new Size(300, 200),
Text = "控制说明:\n" +
"← → : 左右移动\n" +
"↑ : 旋转方块\n" +
"↓ : 加速下落\n" +
"空格 : 直接落下\n" +
"P : 暂停/继续\n" +
"R : 重新开始",
Font = new Font("Arial", 11),
ForeColor = Color.LightGray,
BackColor = Color.Transparent
};
this.Controls.Add(controlsLabel);
}
private void SetupGameLoop()
{
// 设置游戏循环计时器
Timer gameTimer = new Timer
{
Interval = 50 // 50ms更新一次
};
gameTimer.Tick += GameTimer_Tick;
gameTimer.Start();
}
private void GameTimer_Tick(object sender, EventArgs e)
{
if (!isGameActive) return;
fallCounter++;
if (fallCounter >= fallSpeed)
{
MovePieceDown();
fallCounter = 0;
}
// 重绘游戏区域
gamePanel.Invalidate();
previewPanel.Invalidate();
}
private void StartNewGame()
{
// 重置游戏板
for (int y = 0; y < BoardHeight; y++)
for (int x = 0; x < BoardWidth; x++)
gameBoard[y, x] = 0;
// 重置游戏状态
score = 0;
level = 1;
linesCleared = 0;
fallSpeed = 30;
// 生成第一个和下一个方块
currentPiece = CreateRandomTetromino();
nextPiece = CreateRandomTetromino();
// 更新UI
UpdateLabels();
gameStatusLabel.Text = "游戏进行中";
gameStatusLabel.ForeColor = Color.LimeGreen;
// 激活游戏
isGameActive = true;
startButton.Enabled = false;
pauseButton.Enabled = true;
pauseButton.Text = "暂停游戏";
gameTimer = Stopwatch.StartNew();
}
private Tetromino CreateRandomTetromino()
{
int shapeIndex = random.Next(0, tetrominoShapes.Length);
int[,] shape = tetrominoShapes[shapeIndex];
Color color = tetrominoColors[shapeIndex];
// 计算初始位置(居中)
int startX = (BoardWidth - shape.GetLength(1)) / 2;
return new Tetromino(shape, color, startX, 0);
}
private void MovePieceDown()
{
if (CanMove(currentPiece, 0, 1))
{
currentPiece.Y++;
}
else
{
// 锁定方块到游戏板
LockPiece();
// 检查并清除完整的行
int lines = CheckAndClearLines();
if (lines > 0)
{
AddScore(lines);
UpdateLevel();
}
// 生成新的方块
currentPiece = nextPiece;
nextPiece = CreateRandomTetromino();
// 检查游戏是否结束
if (!CanMove(currentPiece, 0, 0))
{
GameOver();
}
}
}
private void MovePieceLeft()
{
if (CanMove(currentPiece, -1, 0))
currentPiece.X--;
}
private void MovePieceRight()
{
if (CanMove(currentPiece, 1, 0))
currentPiece.X++;
}
private void RotatePiece()
{
Tetromino rotatedPiece = currentPiece.Rotate();
// 检查旋转后是否有效
if (CanMove(rotatedPiece, 0, 0))
{
currentPiece = rotatedPiece;
}
else
{
// 尝试墙踢(wall kick) - 如果旋转后碰撞,尝试左右移动一格
if (CanMove(rotatedPiece, -1, 0))
{
rotatedPiece.X--;
currentPiece = rotatedPiece;
}
else if (CanMove(rotatedPiece, 1, 0))
{
rotatedPiece.X++;
currentPiece = rotatedPiece;
}
}
}
private void HardDrop()
{
while (CanMove(currentPiece, 0, 1))
{
currentPiece.Y++;
score += 1; // 硬降奖励分数
}
// 立即锁定方块
LockPiece();
// 检查并清除完整的行
int lines = CheckAndClearLines();
if (lines > 0)
{
AddScore(lines);
UpdateLevel();
}
// 生成新的方块
currentPiece = nextPiece;
nextPiece = CreateRandomTetromino();
// 检查游戏是否结束
if (!CanMove(currentPiece, 0, 0))
{
GameOver();
}
UpdateLabels();
}
private bool CanMove(Tetromino piece, int deltaX, int deltaY)
{
int newX = piece.X + deltaX;
int newY = piece.Y + deltaY;
for (int y = 0; y < piece.Height; y++)
{
for (int x = 0; x < piece.Width; x++)
{
if (piece.Shape[y, x] == 1)
{
int boardX = newX + x;
int boardY = newY + y;
// 检查边界
if (boardX < 0 || boardX >= BoardWidth || boardY >= BoardHeight)
return false;
// 检查是否与已有方块碰撞
if (boardY >= 0 && gameBoard[boardY, boardX] != 0)
return false;
}
}
}
return true;
}
private void LockPiece()
{
for (int y = 0; y < currentPiece.Height; y++)
{
for (int x = 0; x < currentPiece.Width; x++)
{
if (currentPiece.Shape[y, x] == 1)
{
int boardX = currentPiece.X + x;
int boardY = currentPiece.Y + y;
if (boardY >= 0) // 确保在游戏板内
{
// 存储颜色索引(从1开始,0表示空)
int colorIndex = Array.IndexOf(tetrominoColors, currentPiece.Color) + 1;
gameBoard[boardY, boardX] = colorIndex;
}
}
}
}
}
private int CheckAndClearLines()
{
int linesClearedCount = 0;
for (int y = BoardHeight - 1; y >= 0; y--)
{
bool lineComplete = true;
// 检查行是否完整
for (int x = 0; x < BoardWidth; x++)
{
if (gameBoard[y, x] == 0)
{
lineComplete = false;
break;
}
}
// 如果行完整,清除它并将上面的行下移
if (lineComplete)
{
linesClearedCount++;
// 将上面的所有行下移
for (int ny = y; ny > 0; ny--)
{
for (int x = 0; x < BoardWidth; x++)
{
gameBoard[ny, x] = gameBoard[ny - 1, x];
}
}
// 清空最顶部一行
for (int x = 0; x < BoardWidth; x++)
{
gameBoard[0, x] = 0;
}
// 重新检查当前行(因为已经下移了一行)
y++;
}
}
linesCleared += linesClearedCount;
return linesClearedCount;
}
private void AddScore(int lines)
{
// 根据一次消除的行数给予不同分数
int points = 0;
switch (lines)
{
case 1: points = 100 * level; break;
case 2: points = 300 * level; break;
case 3: points = 500 * level; break;
case 4: points = 800 * level; break;
}
score += points;
UpdateLabels();
}
private void UpdateLevel()
{
// 每消除10行升一级
int newLevel = (linesCleared / 10) + 1;
if (newLevel > level)
{
level = newLevel;
// 随着等级提高,下落速度加快
fallSpeed = Math.Max(5, 30 - (level - 1) * 2);
UpdateLabels();
}
}
private void GameOver()
{
isGameActive = false;
gameStatusLabel.Text = "游戏结束!";
gameStatusLabel.ForeColor = Color.Red;
startButton.Enabled = true;
pauseButton.Enabled = false;
// 显示最终分数
MessageBox.Show($"游戏结束!\n最终分数: {score}\n消除行数: {linesCleared}\n等级: {level}",
"游戏结束", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void UpdateLabels()
{
scoreLabel.Text = $"分数: {score}";
levelLabel.Text = $"等级: {level}";
linesLabel.Text = $"消除行数: {linesCleared}";
}
private void GamePanel_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
// 绘制网格背景
for (int y = 0; y < BoardHeight; y++)
{
for (int x = 0; x < BoardWidth; x++)
{
Rectangle rect = new Rectangle(
x * CellSize,
y * CellSize,
CellSize,
CellSize);
// 绘制游戏板上的方块
if (gameBoard[y, x] != 0)
{
int colorIndex = gameBoard[y, x] - 1;
Color color = tetrominoColors[colorIndex];
using (Brush brush = new SolidBrush(color))
{
g.FillRectangle(brush, rect);
}
// 绘制方块边框
using (Pen pen = new Pen(Color.White, 1))
{
g.DrawRectangle(pen, rect);
}
}
else
{
// 绘制空单元格
using (Brush brush = new SolidBrush(Color.FromArgb(30, 30, 30)))
{
g.FillRectangle(brush, rect);
}
// 绘制网格线
using (Pen pen = new Pen(Color.FromArgb(60, 60, 60), 1))
{
g.DrawRectangle(pen, rect);
}
}
}
}
// 绘制当前下落的方块
if (currentPiece != null && isGameActive)
{
DrawTetromino(g, currentPiece, currentPiece.X, currentPiece.Y);
}
}
private void PreviewPanel_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
// 清空预览面板
g.Clear(Color.Black);
if (nextPiece != null)
{
// 计算居中位置
int offsetX = (PreviewSize - nextPiece.Width) * CellSize / 2;
int offsetY = (PreviewSize - nextPiece.Height) * CellSize / 2;
DrawTetromino(g, nextPiece, offsetX / CellSize, offsetY / CellSize, true);
}
}
private void DrawTetromino(Graphics g, Tetromino piece, int boardX, int boardY, bool isPreview = false)
{
for (int y = 0; y < piece.Height; y++)
{
for (int x = 0; x < piece.Width; x++)
{
if (piece.Shape[y, x] == 1)
{
Rectangle rect = new Rectangle(
(boardX + x) * CellSize,
(boardY + y) * CellSize,
CellSize,
CellSize);
using (Brush brush = new SolidBrush(piece.Color))
{
g.FillRectangle(brush, rect);
}
// 绘制方块边框
using (Pen pen = new Pen(Color.White, 1))
{
g.DrawRectangle(pen, rect);
}
// 为预览方块添加半透明效果
if (isPreview)
{
using (Brush overlay = new SolidBrush(Color.FromArgb(100, 255, 255, 255)))
{
g.FillRectangle(overlay, rect);
}
}
}
}
}
}
private void TetrisForm_KeyDown(object sender, KeyEventArgs e)
{
if (!isGameActive && e.KeyCode != Keys.R && e.KeyCode != Keys.P)
return;
switch (e.KeyCode)
{
case Keys.Left:
MovePieceLeft();
break;
case Keys.Right:
MovePieceRight();
break;
case Keys.Down:
MovePieceDown();
score += 1; // 软降奖励分数
UpdateLabels();
break;
case Keys.Up:
RotatePiece();
break;
case Keys.Space:
HardDrop();
break;
case Keys.P:
TogglePause();
break;
case Keys.R:
StartNewGame();
break;
}
// 重绘游戏区域
gamePanel.Invalidate();
}
private void StartButton_Click(object sender, EventArgs e)
{
StartNewGame();
}
private void PauseButton_Click(object sender, EventArgs e)
{
TogglePause();
}
private void TogglePause()
{
if (!isGameActive && pauseButton.Text == "继续游戏")
{
// 继续游戏
isGameActive = true;
pauseButton.Text = "暂停游戏";
gameStatusLabel.Text = "游戏进行中";
gameStatusLabel.ForeColor = Color.LimeGreen;
gameTimer?.Start();
}
else if (isGameActive)
{
// 暂停游戏
isGameActive = false;
pauseButton.Text = "继续游戏";
gameStatusLabel.Text = "游戏暂停";
gameStatusLabel.ForeColor = Color.Yellow;
gameTimer?.Stop();
}
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new TetrisForm());
}
}
// 方块类
public class Tetromino
{
public int[,] Shape { get; set; }
public Color Color { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Width => Shape.GetLength(1);
public int Height => Shape.GetLength(0);
public Tetromino(int[,] shape, Color color, int x, int y)
{
Shape = shape;
Color = color;
X = x;
Y = y;
}
public Tetromino Rotate()
{
int rows = Shape.GetLength(0);
int cols = Shape.GetLength(1);
// 创建新的旋转后的形状
int[,] rotated = new int[cols, rows];
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
rotated[x, rows - 1 - y] = Shape[y, x];
}
}
// 返回新的Tetromino实例,保持其他属性不变
return new Tetromino(rotated, Color, X, Y);
}
}
}
项目设置说明
- 在Visual Studio中创建新的Windows Forms应用项目
- 将上述代码复制粘贴到Form1.cs文件中(或重命名为TetrisForm.cs)
- 确保项目中引用了System.Drawing命名空间
游戏功能特性
-
核心游戏机制:
- 标准俄罗斯方块玩法
- 7种不同形状的方块
- 方块旋转、移动和下落
- 行消除和分数计算
-
游戏控制:
- 左右箭头:移动方块
- 上箭头:旋转方块
- 下箭头:加速下落
- 空格键:直接落下(硬降)
- P键:暂停/继续游戏
- R键:重新开始游戏
-
游戏界面:
- 主游戏区域显示当前方块和已固定的方块
- 预览区域显示下一个方块
- 分数、等级和消除行数显示
- 开始/暂停按钮
-
游戏逻辑:
- 分数系统(消除行数越多得分越高)
- 等级系统(消除行数越多等级越高,下落速度越快)
- 碰撞检测
- 游戏结束判定
参考代码 C# 拼图游戏 www.youwenfan.com/csa/93149.html
扩展建议
如果您想进一步扩展这个游戏,可以考虑添加以下功能:
- 保存最高分记录
- 添加音效和背景音乐
- 实现更多方块旋转规则(如SRS旋转系统)
- 添加游戏难度选择
- 实现方块阴影(显示方块将落下的位置)
- 添加游戏暂停时的封面画面
- 实现网络排行榜功能