让编程变得更有趣:用Python实现经典俄罗斯方块

_哈喽,大家好,我是强哥。_今天我要和大家分享的不仅仅是一段代码,而是一段时光的旅行。回想起那些无忧无虑的儿时岁月,我们或许都曾在游戏厅的角落里,或是家中那台旧电视机前,痴迷于一款简单却引人入胜的游戏 —— 俄罗斯方块。那些由彩色方块组成的下落画面,不仅考验着我们的反应能力和策略思维,还无声地陪伴着我们成长。

而今,当我们步入编程的世界,是否可以用代码的魔力,重塑这一经典呢?我想说的是,不仅可以,而且我们可以通过这个过程,让那些美好的记忆重现眼前,同时锻炼我们的编程技能。

我将要分享的,是一个用Python编写的俄罗斯方块游戏。它简洁而不失精巧,对于刚入门的编程新手来说,是理解编程逻辑的绝佳示例;对于有一定基础的编程爱好者,它又提供了无限的扩展可能,等待你用自己的想象力和创造力去探索和改进。

让我们通过这段代码,不仅重温经典,更在编程的道路上迈出坚实的一步。从最基础的图形绘制到复杂的逻辑处理,从代码的编写到游戏的体验,每一步都充满了乐趣和挑战。准备好了吗?让我们开始这段激动人心的编程之旅,一起探索代码背后的无限可能吧!

接下来的部分:我们将深入游戏规则的细节,探讨使用的Python库,逐行解读代码,并讨论如何进一步改进和创新。无论你是编程初学者,还是希望找到新的编程灵感,都不要错过!

游戏规则

俄罗斯方块,这款源自上世纪80年代的经典游戏,相信大家都不陌生。玩家需要移动、旋转下落的方块,使它们在底部排列紧密,一旦填满一行就会消除并得分。听起来简单,但想要高分,就需要策略和前瞻性。

使用的Python库

  • turtle:一个简单的图形绘制库,用于绘制游戏界面和方块。

  • random:生成随机数,用于随机选择方块形状和颜色。

代码示例

接下来是我们的主角,详细的代码实现。代码首先定义了方块的各种形状和颜色,然后通过 Block 类来管理方块的行为,如移动、旋转和下落。游戏的主循环通过 run 函数控制,处理方块下落和行消除的逻辑。完整代码可看文末!


from turtle import * # 导入turtle库,用于创建图形界面
from random import randint, choice # 导入randint和choice函数,用于生成随机数和随机选择

# SHAPES列表包含了所有可能的方块形状,每个形状用二维数组表示,1代表方块的一部分,0代表空白
SHAPES = [
    # 长条形
    [[1, 1, 1, 1]],

    # 长条形的另一种方向
    [[1],
     [1],
     [1],
     [1]],

    # T形
    [[0, 0, 1],
     [1, 1, 1]],

    # L形
    [[1, 0, 0],
     [1, 1, 1]],

    # 反Z形
    [[0, 1, 1],
     [1, 1, 0]],

    # Z形
    [[1, 1, 0],
     [0, 1, 1]],

    # 正方形
    [[1, 1],
     [1, 1]],

    # 反T形
    [[0, 1, 0],
     [1, 1, 1]]
]


class Block():
    def __init__(self, grid):
        """
        初始化方块对象
        :param grid: 游戏的网格,方块会被放置在这个网格中
        """
        self.grid = grid  # 游戏网格
        self.color = randint(1, 7)  # 随机选择颜色
        self.shape = choice(SHAPES)  # 随机选择一个形状
        self.i = 0  # 方块的初始行位置
        self.j = 5  # 方块的初始列位置
        self.width = len(self.shape[0])  # 计算方块的宽度
        self.height = len(self.shape)  # 计算方块的高度

    def fill(self):
        """
        将方块的形状填充到游戏网格中
        """
        for i in range(self.height):
            for j in range(self.width):
                if self.shape[i][j] == 1:  # 检查形状数组中的每个元素
                    self.grid[self.i + i][self.j + j] = self.color  # 在相应的位置填充颜色

    def erase(self):
        """
        从游戏网格中擦除方块,用于移动或旋转方块前的清理
        """
        for i in range(self.height):
            for j in range(self.width):
                if self.shape[i][j] == 1:  # 检查形状数组中的每个元素
                    self.grid[self.i + i][self.j + j] = 0  # 在相应的位置擦除方块

    # 后续的方法(move_left, move_right, move_down, check_down, can_fall, rotate)
    # 提供方块移动和旋转的功能,以及检查方块是否可以下移
    def move_left(self):
        """
        向左移动方块一格
        """
        if self.j > 0:
            for row in range(self.height):
                for col in range(self.width):
                    if self.shape[row][col] == 1:
                        if self.grid[self.i + row][self.j + col - 1] != 0:
                            return False
                        break

            self.erase()
            self.j -= 1
            self.fill()

    def move_right(self):
        """
        向右移动方块一格
        """
        if self.j + self.width < len(self.grid[0]):
            for row in range(self.height):
                for col in range(self.width - 1, -1, -1):
                    if self.shape[row][col] == 1:
                        if self.grid[self.i + row][self.j + col + 1] != 0:
                            return False
                        break

            self.erase()
            self.j += 1
            self.fill()

    def move_down(self):
        """
        快速向下移动方块
        """
        i = self.i
        while self.check_down(i):
            i += 1
        self.erase()
        self.i = i
        self.fill()

    def check_down(self, i):
        """
        检查方块是否可以向下移动
        :param i: 当前行位置
        :return: 如果可以移动返回True,否则返回False
        """
        if i + self.height >= len(self.grid):
            return False
        for col in range(self.width):
            for row in range(self.height - 1, -1, -1):
                if self.shape[row][col] == 1:
                    if self.grid[i + row + 1][self.j + col] != 0:
                        return False
                    break
        return True

    def can_fall(self):
        """
        检查方块是否可以继续下落
        :return: 如果可以继续下落返回True,否则返回False
        """
        return self.check_down(self.i)

    def rotate(self):
        """
        旋转方块
        """
        rotated = []
        for j in range(len(self.shape[0])):
            new_row = []
            for i in range(len(self.shape) - 1, -1, -1):
                new_row.append(self.shape[i][j])
            rotated.append(new_row)

        for i in range(len(rotated)):
            for j in range(len(rotated[0])):
                if rotated[i][j] == 1:
                    # 如果旋转后,有任何位置超过边界,则不能旋转
                    if self.i + i >= len(self.grid) or self.j + j >= len(self.grid[0]):
                        return
                    # 如果旋转后的位置有方块了,则不能旋转
                    if self.grid[self.i + i][self.j + j] != 0 and (i not in range(len(self.shape)) or j not in range(
                            len(self.shape[0]))):
                        return
        self.erase()
        self.shape = rotated
        self.height = len(self.shape)
        self.width = len(self.shape[0])
        self.fill()

# 游戏的基本设置
gz = 32  # 方格大小
WIDTH = 12  # 游戏网格的宽度
HEIGHT = 24  # 游戏网格的高度
COLORS = ("black", "red", "orange", "yellow", "green", "cyan", "blue", "purple")  # 方块颜色

# 创建游戏网格,初始时所有格子均为空(0表示)
grid = [[0 for col in range(WIDTH)] for row in range(HEIGHT)]

# 设置turtle画布的基本属性
title("海水加糖的俄罗斯方块")  # 设置窗口标题
bgcolor("lightgreen")  # 设置背景颜色
shapesize(1.5)  # 设置形状大小
tracer(False)  # 关闭自动刷新,用于手动刷新画面
speed(0)  # 设置绘图速度
shape("square")  # 设置绘图形状为方形
up()  # 抬起画笔,移动时不绘图

# 初始化分数和分数显示
score = 0  # 初始化分数
score_pen = Turtle()  # 创建用于显示分数的turtle对象
score_pen.ht()  # 隐藏turtle对象
score_pen.up()  # 抬起画笔
score_pen.goto(0, HEIGHT / 2 * gz)  # 移动到指定位置
score_pen.down()  # 放下画笔
score_pen.write("分数:{}".format(score), font=("", 20, ""), align="center")  # 显示分数

# 创建一个用于显示下一个方块的turtle对象
block_pen = Turtle()
block_pen.speed(0)
block_pen.shapesize(1.5)
block_pen.shape("square")
block_pen.up()
block_pen.ht()

def draw_next_block(block):
    """
    绘制下一个方块
    :param block: 下一个要显示的方块对象
    """
    block_pen.clear()  # 清除之前的绘图
    block_pen.color(COLORS[block.color])  # 设置绘图颜色
    for i in range(len(block.shape)):
        for j in range(len(block.shape[0])):
            if block.shape[i][j] == 1:
                block_pen.goto(WIDTH / 2 * gz + 50 + j * gz, HEIGHT / 2 * gz - 50 - i * gz)  # 移动到指定位置
                block_pen.stamp()  # 绘制方块

def draw_grid():
    """
    绘制游戏网格和方块
    """
    clear()  # 清除当前画面
    for row in range(len(grid)):
        for col in range(len(grid[row])):
            goto(-WIDTH / 2 * gz + col * gz, HEIGHT / 2 * gz - row * gz - 20)  # 移动到指定位置
            color(COLORS[grid[row][col]])  # 设置方块颜色
            stamp()  # 绘制方块

......

代码解析

  • 初始化和方块形状:代码开始就定义了方块的形状,这是游戏的核心。每个形状都用一个二维数组表示,其中 1 和 0 分别代表方块的一部分和空白。

  • 方块类(Block):这个类是代码的核心,处理方块的创建、移动、旋转和渲染。例如,move_down 方法检查方块是否可以继续下移,如果可以,就更新其位置。

  • 图形界面:使用 turtle 库绘制游戏界面和方块。每个方块的颜色和位置都由这个库来管理。

  • 游戏逻辑:run 函数控制着游戏的进程,检测方块是否触底,是否需要消除行,以及游戏是否结束。

效果展示

探索与改进

  • 代码优化:代码中有很多可以优化的地方,比如减少全局变量的使用,提高代码的模块化和可读性。

  • 功能扩展:可以增加更多功能,如下一个方块的预览、不同级别的难度、计分板和音效等,让游戏更加丰富和有趣。

  • 图形界面美化:虽然 turtle 库足够简单,但对于更复杂的图形效果,可能需要考虑其他图形库,如 pygame。

结语

编写一个游戏是学习编程的绝佳途径。它不仅可以加深你对编程语言的理解,还可以让你在实际应用中锻炼逻辑思维和解决问题的能力。这个俄罗斯方块项目是一个很好的开始,不论你是为了提升编程技能,还是仅仅想找点乐子,都可以尝试一下。

感兴趣的小伙伴,完整代码和全套Python学习资料免费赠送,具体看这里。

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img
img

二、Python必备开发工具

工具都帮大家整理好了,安装就可直接上手!img

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、Python视频合集

观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

五、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

六、面试宝典

在这里插入图片描述

在这里插入图片描述

简历模板在这里插入图片描述
若有侵权,请联系删除
  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值