C# 俄罗斯方块源代码

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 俄罗斯方块源代码相关的知识,希望对你有一定的参考价值。

参考技术A using System;
using System.Drawing;
using Microsoft.Win32;

namespace AnotherBlock

/// <summary>
/// Represents a Tetris game engine.
/// </summary>
public class Game

/// <summary>
/// Constant with the image width of the block unit (in pixels).
/// </summary>
public const int BlockImageWidth = 21;
/// <summary>
/// Constant with the image height of the block unit (in pixels).
/// </summary>
public const int BlockImageHeight = 21;
/// <summary>
/// Constant with the playing field width (in block units).
/// </summary>
public const int PlayingFieldWidth = 10;
/// <summary>
/// Constant with the playing field height (in block units).
/// </summary>
public const int PlayingFieldHeight = 20;
/// <summary>
/// Constante with the number of lines for each level.
/// </summary>
public const int LevelEveryLines = 12;

/// <summary>
/// Private attribute that holds the current game score.
/// </summary>
private int score = 0;
/// <summary>
/// Private attribute that holds the current game level.
/// </summary>
private short level = 1;
/// <summary>
/// Private attribute that holds the current number of completed lines.
/// </summary>
private int lines = 0;
/// <summary>
/// Private attribute that holds the current game state.
/// </summary>
private GameState gameState;
/// <summary>
/// Private attribute that holds the level where the game started.
/// </summary>
private short startLevel = 1;
/// <summary>
/// Private attribute that holds the current game pile.
/// </summary>
private Brick[,] pile = new Brick[(PlayingFieldWidth + 1), (PlayingFieldHeight + 1)];
/// <summary>
/// Private attribute that holds the current block.
/// </summary>
private Block currentBlock = new Block();
/// <summary>
/// Private attribute that holds the next block.
/// </summary>
private Block nextBlock = new Block();

/// <summary>
/// Class constructor that creates a game.
/// </summary>
public Game()

// Clears the game pile.
ClearPile();


/// <summary>
/// Class constructor that creates a game in a given level.
/// </summary>
/// <param name="level">The level where the game should start.</param>
public Game(short level)

// Sets the level attribute to the game level where the game should start.
this.level = level;
// Sets the startLevel attribute to the game level where the game should start.
startLevel = level;
// Clears the game pile.
ClearPile();


/// <summary>
/// Readonly property that holds the score of the current game.
/// </summary>
public int Score

get

// Returns the value in the score attribute.
return score;



/// <summary>
/// Readonly property that holds the level of the current game.
/// </summary>
public short Level

get

// Returns the value in the level attribute.
return level;



/// <summary>
/// Readonly property that holds the number of complete lines in the current game.
/// </summary>
public int Lines

get

// Returns the value in the lines attribute.
return lines;



/// <summary>
/// Property that holds and sets the current game state.
/// </summary>
/// <remarks>
/// The game state can be "Running", "Paused" or "Over".
/// </remarks>
public GameState GameState

get

// Returns the value in the gameState attribute.
return gameState;

set

// Checks if the current game state is "Over", and if the value to change is not "Over".
if ((gameState == GameState.Over) && (value != GameState.Over))

// The current game state is "Over", and it's changing to something else than "Over".
// Resets the score, level and lines.
score = 0;
level = startLevel;
lines = 0;
// Creates a new current block, and a new next block.
currentBlock = new Block();
nextBlock = new Block();
// Clears the game pile.
ClearPile();


// Sets the gameState attribute to the value.
gameState = value;



/// <summary>
/// Method that moves the current block down one position.
/// </summary>
/// <returns>True if there was a hit on the ground or on the pile, false if there wasn't.</returns>
public bool MoveCurrentBlockDown()

// Creates a "hit" flag, to check if the block has hit the pile or the ground.
bool hit = false;

// Increases the Top of the current block.
currentBlock.Top++;

// Checks if the current block has hit the ground.
// COLLISION DETECTION
if ((currentBlock.Top + currentBlock.Height) > PlayingFieldHeight)

// Current block has hit the ground.
// Sets the "hit" flag to "true".
hit = true;

else

// Checks if the current block has hit the pile.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)

for(int j = 0; j < currentBlock.Height; j++)

int fx, fy;
fx = currentBlock.Left + i;
fy = currentBlock.Top + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[fx, (fy + 1)].Filled == true))

// Current block has hit the pile.
// Sets the "hit" flag to "true".
hit = true;





// Checks if there was a hit.
if (hit)

// There was a hit.
// Puts the current block in the pile.
MoveBlockToPile();
// Checks if the current game state is not "Over".
if (this.GameState != GameState.Over)

// Current game state is not "Over".
// Creates a new block.
CreateNewBlock();



// Returns if there was a hit or not.
return hit;


/// <summary>
/// Method that moves the current block down until there is a hit.
/// </summary>
public void MoveCurrentBlockCompletelyDown()

// Moves the current block down until it has a hit.
while(!MoveCurrentBlockDown());


/// <summary>
/// Method that rotates the current block.
/// </summary>
/// <param name="clockwise">True if the block will be rotated clockwise, false if counterclockwise.</param>
public void RotateCurrentBlock(bool clockwise)

// Creates a "canRotate" flag, to check if the block can be rotated.
bool canRotate = true;

// Rotates the current block.
// This should be different. There should be an easy way to check FIRST if the block could
// be rotated, and then rotate it. I'll study this later.
currentBlock.Rotate(clockwise);

// Checks if the current block could be rotated.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)

for(int j = 0; j < currentBlock.Height; j++)

int fx, fy;
fx = currentBlock.Left + i;
fy = (currentBlock.Top + 1) + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[fx, fy].Filled == true))

// Current block can't be rotated.
// Sets the "canRotate" flag to "false".
canRotate = false;




// Checks if the block can't be rotated.
if (!canRotate)

// Block can't be rotated.
// Rotates the block back to its first position.
currentBlock.Rotate(!clockwise);



/// <summary>
/// Method that moves the current block to the right or to the left.
/// </summary>
/// <param name="left">True if the block will be moved to the left, false if to the right.</param>
public void MoveCurrentBlockSide(bool left)

// Creates a "canMove" flag, to check if the block can be moved to the sides.
bool canMove = true;

// Checks if the block is to be moved to the left.
if (left)

// The block is to be moved to the left.
// Checks if the block is not already at the most left of the playing field.
if (currentBlock.Left > 0)

// Block is not at the most left of the playing field.
// Checks if the current block can move to the left.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)

for(int j = 0; j < currentBlock.Height; j++)

int fx, fy;
fx = currentBlock.Left + i;
fy = (currentBlock.Top + 1) + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[(fx - 1), fy].Filled == true))

// Current block can't move to the left.
// Sets the "canMove" flag to "false".
canMove = false;




// Checks if the block can be moved to the left.
if (canMove)

// Block can be moved to the left.
// Moves the block to the left.
currentBlock.Left--;



else

// The block is not to be moved to the left (it is to be moved to the right).
// Checks if the block is not already at the most right of the playing field.
if ((currentBlock.Left + currentBlock.Width) < PlayingFieldWidth)

// Block is not at the most right of the playing field.
// Checks if the current block can move to the right.
// COLLISION DETECTION
for(int i = 0; i < currentBlock.Width; i++)

for(int j = 0; j < currentBlock.Height; j++)

int fx, fy;
fx = currentBlock.Left + i;
fy = (currentBlock.Top + 1) + j;
if ((currentBlock.Shape[i, j].Filled == true) && (pile[(fx + 1), fy].Filled == true))

// Current block can't move to the right.
// Sets the "canMove" flag to "false".
canMove = false;




// Checks if the block can be moved to the right.
if (canMove)

// Block can be moved to the right.
// Moves the block to the right.
currentBlock.Left++;





/// <summary>
/// Method that draws the pile in a surface.
/// </summary>
/// <param name="drawingSurface">The graphics surface where the pile will be drawn.</param>
public void DrawPile(Graphics drawingSurface)

// Runs through the playing field Width.
for (int i = 0; i < (PlayingFieldWidth + 1); i++)

// Runs through the playing field Height.
for (int j = 0; j < (PlayingFieldHeight + 1); j++)

// Checks if the current brick of the pile is set to be solid.
if (pile[i, j].Filled == true)

// Current brick of the pile is set to be solid.
// Creates a rectangle in the right position of this brick.
Rectangle rect = new Rectangle(i * BlockImageWidth, (j - 1) * BlockImageHeight, BlockImageWidth, BlockImageHeight);
// Draws the block image in the just created rectangle.
drawingSurface.DrawImage(pile[i, j].BrickImage, rect);





/// <summary>
/// Method that draws the current block in a surface.
/// </summary>
/// <param name="drawingSurface">The graphics surface where the current block will be drawn.</param>
public void DrawCurrentBlock(Graphics drawingSurface)

// Checks if there is a current block.
if (currentBlock != null)

// There is a current block.
// Draws the current block in the drawing surface.
currentBlock.Draw(drawingSurface);



/// <summary>
/// Method that draws the next block in a surface.
/// </summary>
/// <param name="drawingSurface">The graphics surface where the current block will be drawn.</param>
public void DrawNextBlock(Graphics drawingSurface)

// Checks if there is a next block.
if (nextBlock != null)

// There is a next block.
// Saves the current Left and Top properties of the next block.
short currentLeft = nextBlock.Left;
short currentTop = nextBlock.Top;

// Changes the current Left and Top properties of the next block, so they can be shown
// in the center of a drawing surface that has a size of 6x6 blocks.
nextBlock.Left = (short)((6 - nextBlock.Width) / 2);
nextBlock.Top = (short)((6 - nextBlock.Height) / 2);

// Draws the next block in the drawing surface.
nextBlock.Draw(drawingSurface);

// Retrieves the previously saved Left and Top properties, and put them back in the next block.
nextBlock.Left = currentLeft;
nextBlock.Top = currentTop;



/// <summary>
/// Private method that clears the current game pile.
/// </summary>
private void ClearPile()

// Runs through the playing field Width.
for(int i = 0; i < (PlayingFieldWidth + 1); i++)

// Runs through the playing field Height.
for(int j = 0; j < (PlayingFieldHeight + 1); j++)

// Clears the current brick of the pile.
pile[i, j].Filled = false;




/// <summary>
/// Private method that creates a new current block by getting it from the next block,
/// and creates a new random next block.
/// </summary>
private void CreateNewBlock()

// Checks if there is a next block.
if (this.nextBlock != null)

// There is a next block.
// Sets the current block to the next block.
currentBlock = nextBlock;

else

// There isn't a next block.
// Sets the current block as a new random block.
currentBlock = new Block();


// Sets the next block as a new random block.
nextBlock = new Block();


/// <summary>
/// Private method that moves the current block to the game pile.
/// While moving the block to the pile, it checks if there are complete lines, and count them, in
/// order to update the score, the lines and the level. It also checks for game over.
/// </summary>
private void MoveBlockToPile()

// Runs through the current block Width.
for(int i = 0; i < currentBlock.Width; i++)

// Runs through the current block Height.
for(int j = 0; j < currentBlock.Height; j++)

// Converts the current brick position the a playing field position.
int fx, fy;
fx = currentBlock.Left + i;
fy = currentBlock.Top + j;
// Checks if the current brick is solid.
if (currentBlock.Shape[i, j].Filled == true)

// The current brick is solid.
// Moves the current brick to the pile.
pile[fx, fy].Filled = true;
pile[fx, fy].BrickImage = currentBlock.Shape[i, j].BrickImage;




// Checks for complete lines.
CheckForLines();

// Checks for game over.
CheckForGameOver();


/// <summary>
/// Private method that checks the pile for complete lines.
/// </summary>
/// <returns>The number of found lines.</returns>
private int CheckForLines()

// Creates a variable that will hold the number of lines found.
int numLines = 0;
// Creates a variable that will hold the number of the complete lines found.
int[] completeLines = new int[PlayingFieldHeight];

// Runs through the playing field lines.
for (int j = PlayingFieldHeight; j > 0; j--)

// Checks if there is a complete line.
bool fullLine = true;

for (int i = 0; i < PlayingFieldWidth; i++)

if (pile[i, j].Filled == false)

fullLine = false;
break;



// Checks if there was a complete line.
if (fullLine)

// There was a complete line.
// Increases the number of complete lines found.
numLines++;
// Pauses the game so no block will come down while clearing the complete line.
this.GameState = GameState.Paused;
// Holds the number of the complete line found.
completeLines[numLines] = j;
// Sets the game state to "Running" again, to release the game.
this.GameState = GameState.Running;



// Checks if there were any complete lines.
if (numLines > 0)

// There were complete lines.
// Runs through all the complete lines, and clears them.
for(int i = 1; i <= numLines; i++)

// Clear a complete line.
ClearLine((completeLines[i] + (i - 1)));

// Updates the game score, lines and level.
score += 5 * (numLines * (numLines + 1));
lines += numLines;
level = (short)((lines / LevelEveryLines) + startLevel);


// Returns the number of complete lines.
return numLines;


/// <summary>
/// Private method that checks the pile for game over.
/// </summary>
private void CheckForGameOver()

// Checks if the top of the current block is on the top of the pile.
if (currentBlock.Top == 1)

// Current block is on the top the the pile.
// Sets the game state to "Over".
this.GameState = GameState.Over;



/// <summary>
/// Private method that clears a line from the pile.
/// </summary>
/// <param name="lineNumber">The number of the line to be cleared.</param>
private void ClearLine(int lineNumber)

// Runs through all the lines, from the line to be cleared up.
for (int j = lineNumber; j > 0; j--)

// Runs through all the bricks in one line.
for (int i = 0; i < PlayingFieldWidth; i++)

// Move the current brick down.
pile[i, j] = pile[i, (j - 1)];



// Runs through the top line bricks.
for (int i = 0; i < PlayingFieldWidth; i++)

// Sets the current brick to empty.
pile[i, 0].Filled = false;





这是其中之一最重要的部分,要全部代码给我发邮件
forstrongest@163.com本回答被提问者采纳

python写俄罗斯方块

python写俄罗斯方块

✨博主介绍

💂 个人主页:苏州程序大白

💂 个人社区:CSDN全国各地程序猿

🤟作者介绍:中国DBA联盟(ACDU)成员,CSDN全国各地程序猿(媛)聚集地管理员。目前从事工业自动化软件开发工作。擅长C#、Java、机器视觉、底层算法等语言。2019年成立柒月软件工作室,2021年注册苏州凯捷智能科技有限公司

💅 有任何问题欢迎私信,看到会及时回复

👤 微信号:stbsl6,微信公众号:苏州程序大白

💬如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)

🎯 想加入技术交流群的可以加我好友,群里会分享学习资料

# coding : utf-8

#: pip install pygame
import random
import sys
import pygame

#: 颜色定义
COLOR_WHITE = (255, 255, 255)
COLOR_BLACK = (0, 0, 0)

class Block:
    """小块"""
    width = 24
    height = 24

    @staticmethod
    def draw(s, left, top, color, bg_color):
        pygame.draw.rect(s, bg_color, pygame.Rect(left, top, Block.width, Block.height))
        pygame.draw.rect(s, color, pygame.Rect(left, top, Block.width - 1, Block.height - 1))


class Building:
    """积木"""

    def __init__(self):
        """
        方块的7种基本形状
        每次初始化随机选择一个形状
        @:return True / False
        """
        self.form = random.choice(
            [
                [
                    [0, 0, 0, 0, 0],
                    [0, 0, 1, 0, 0],
                    [0, 1, 1, 1, 0],
                    [0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0]
                ],
                [
                    [0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0],
                    [1, 1, 1, 1, 0],
                    [0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0]
                ],
                [
                    [0, 0, 0, 0, 0],
                    [0, 1, 1, 0, 0],
                    [0, 0, 1, 1, 0],
                    [0, 0, 0, 0, 0],
                    [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, 0, 0]
                ],
                [
                    [0, 0, 0, 0, 0],
                    [0, 1, 1, 0, 0],
                    [0, 0, 1, 0, 0],
                    [0, 0, 1, 0, 0],
                    [0, 0, 0, 0, 0]
                ],
                [
                    [0, 0, 0, 0, 0],
                    [0, 0, 1, 1, 0],
                    [0, 0, 1, 0, 0],
                    [0, 0, 1, 0, 0],
                    [0, 0, 0, 0, 0]
                ],
                [
                    [0, 0, 0, 0, 0],
                    [0, 1, 1, 0, 0],
                    [0, 1, 1, 0, 0],
                    [0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0]
                ]
            ])

    def __getitem__(self, pos):
        return self.form[pos]

    def __setitem__(self, key, value):
        self.form[key] = value


class Layout:
    """棋盘"""

    def __init__(self):
        self.block_x_count = 16;
        self.block_y_count = 22;
        self.layout = [[0 if 1 < i < self.block_x_count - 2 and j < self.block_y_count - 2 else 1
                        for i in range(self.block_x_count)] for j in range(self.block_y_count)]

    @property
    def size(self):
        """返回棋盘屏幕大小(width,height)"""
        return (self.block_x_count * Block.width, self.block_y_count * Block.height)

    def create_new_building(self):
        """
        创建新的积木,初始化位置为第5,0格, 速度为4
        :return: 返回是否无空间创建了
        """
        self.building = Building()
        self.building_left, self.building_top = 5, 0  #
        self.drop_speed = 3
        print(self.test_building_touch_wall())
        return self.test_building_touch_wall()
    
    @property
    def speed(self):
        return self.drop_speed

    def test_building_touch_wall(self, x_offset=0, y_offset=0):
        """
        积木是否已经触底/墙壁
        具体操作:
        判断积木最后一排的1,是否在当前棋牌对应的位置是也是1
        @:param x_offset: x的偏移量  移动时可以传入1/-1来判断
        @:param y_offset: y的偏移量  正常下落时可以传入1来判断
        """
        for i in range(4, -1, -1):
            for j in range(5):
                if self.building[i][j]:
                    if self.layout[i + self.building_top + y_offset][j + self.building_left + x_offset]:
                        return True
        return False

    def move_left_right(self, x):
        """
        左右移动
        @:param x:  移动量 x_offset
        """
        #: 移动时不能撞墙
        if not self.test_building_touch_wall(x_offset=x):
            self.building_left += x

    def down_build(self):
        """ 盒子的自动下移 """
        self.building_top += 1

    def direct_down(self):
        """ 手动快速降落 """
        self.drop_speed = 50

    def convert_building(self):
        """
        * 扭转盒子的总方位 (右转)
        具体操作:
        把第一竖排的倒序给第一横排的
        把第二竖排的倒序给第二横排的
        后面同理.
        """
        new_box = [[0 for i in range(5)] for j in range(5)]
        for i in range(5):
            for j in range(4, -1, -1):
                new_box[i][j] = self.building[4 - j][i]
        self.building = new_box

    def clear_full_lines(self):
        """消除满行的所有行"""
        new_layout = [[0 if 1 < i < self.block_x_count - 2 and j < self.block_y_count - 2 else 1
                       for i in range(self.block_x_count)] for j in range(self.block_y_count)]

        row_len = self.block_x_count - 4
        new_row = self.block_y_count - 2 - 1
        for cur_row in range(self.block_y_count - 2 - 1, 0, -1):
            if sum(self.layout[cur_row][2:self.block_x_count - 2]) < row_len:
                new_layout[new_row] = self.layout[cur_row]
                new_row -= 1
        self.layout = new_layout

    def put_building_to_layout(self):
        """将积木放到棋盘里"""
        for i in range(4, -1, -1):
            for j in range(5):
                if self.building[i][j]:
                    self.layout[i + self.building_top][j + self.building_left] = 1
        #: 这里会调用消除函数
        self.clear_full_lines()

    def draw_building(self, s):
        """
        显示积木
        @:param s : pygame = screen 
        """
        cur_left, cur_top = self.building_left * Block.width, self.building_top * Block.height
        for i in range(5):
            for j in range(5):
                # 只画积木实体,不管盒子本身
                if self.building[j][i]:
                    Block.draw(s, cur_left + i * Block.width, cur_top + j * Block.height, COLOR_BLACK, COLOR_WHITE)

    def draw(self, s):
        """
        显示棋盘
        @:param s : pygame = screen 
        """
        for i in range(self.block_x_count):
            for j in range(self.block_y_count):
                if self.layout[j][i] == 0:
                    Block.draw(s, i * Block.width, j * Block.height, COLOR_WHITE, COLOR_BLACK)
                else:
                    Block.draw(s, i * Block.width, j * Block.height, COLOR_BLACK, COLOR_WHITE)


# -------------------------------------------------------------------
# Main
# -------------------------------------------------------------------
def main():
    #: 初始化
    while True:
        layout = Layout()
        layout.create_new_building()
        pygame.init()
        pygame.display.set_caption('俄罗斯方块')
        screen = pygame.display.set_mode((layout.size), 0, 32)
        is_over = False
        #: 单局游戏循环开始 [结束后直接重新开始]
        while not is_over:
            #: 处理游戏消息
            for e in pygame.event.get():
                if e.type == pygame.QUIT:
                    sys.exit()
                #: 处理按键
                if e.type == pygame.KEYDOWN:
                    if e.key == pygame.K_UP:
                        layout.convert_building()
                    if e.key == pygame.K_DOWN:
                        layout.direct_down()
                    if e.key == pygame.K_LEFT:
                        layout.move_left_right(-1)
                    if e.key == pygame.K_RIGHT:
                        layout.move_left_right(1)
            #: 是否碰触底部地面了,是 -> 融合背景   否 -> 继续下落
            if layout.test_building_touch_wall(y_offset=1):
                layout.put_building_to_layout()
                is_over = layout.create_new_building()
            else:
                layout.down_build()
            #: 绘制
            layout.draw(screen)
            layout.draw_building(screen)
            pygame.display.update()
            #: 速度
            pygame.time.Clock().tick(layout.speed)


if __name__ == '__main__':
    main()

以上是关于C# 俄罗斯方块源代码的主要内容,如果未能解决你的问题,请参考以下文章

使用C#和MonoGame开发俄罗斯方块游戏

win10 uwp 俄罗斯方块

C#之四十八 俄罗斯方块设计

C#语言实例源码系列-游戏-实现俄罗斯方块

java的俄罗斯方块代码

求用JAVA编写俄罗斯方块游戏的源代码