Python俄罗斯方块

news2024/12/28 19:44:38

文章目录

    • 游戏实现思路
      • 1. 游戏元素的定义
      • 2. 游戏区域和状态的定义
      • 3. 游戏逻辑的实现
      • 4. 游戏界面的绘制
      • 5. 游戏事件的处理
      • 6. 游戏循环
      • 7. 完整实现代码

在这里插入图片描述

游戏实现思路

这个游戏的实现思路主要分为以下几个步骤:

1. 游戏元素的定义

  • Brick类:表示游戏中的砖块,包括其位置、颜色以及图像。
  • Block类:表示游戏中的方块,包括其布局、方向、位置、砖块列表等。

2. 游戏区域和状态的定义

  • 游戏区域大小:定义游戏区域的宽度和高度。
  • 方块的初始位置:定义每个新方块在游戏区域中的初始位置。
  • 信息面板宽度:定义显示游戏信息和下一个方块的面板宽度。
  • 下一个方块的初始位置:定义下一个方块在信息面板中的初始位置。
  • 游戏区域地图:使用二维数组表示游戏区域,其中0表示无砖块,1表示有砖块。
  • 游戏状态:包括游戏是否在运行、当前分数、上次移动时间等。

3. 游戏逻辑的实现

  • 随机生成方块:使用随机数生成不同类型和颜色的方块。
  • 方块的移动和旋转:根据用户的键盘输入,实现方块的左右移动、下落和旋转。
  • 方块的停止和消除:当方块无法继续下落时,将其砖块添加到游戏区域地图中,并判断是否可以消除行。
  • 分数的计算:根据消除的行数增加分数。
  • 游戏结束判断:当新生成的方块无法放置在游戏区域中时,游戏结束。

4. 游戏界面的绘制

  • 绘制游戏区域:包括绘制游戏区域的砖块和边框。
  • 绘制信息面板:包括绘制当前分数和下一个方块。
  • 更新屏幕:使用pygame库的函数更新游戏界面。

5. 游戏事件的处理

  • 处理键盘事件:根据用户的键盘输入,控制方块的移动和旋转。
  • 处理退出事件:当用户点击关闭按钮时,退出游戏。

6. 游戏循环

  • 主游戏循环:不断生成新方块,并更新和绘制游戏界面,直到游戏结束。
  • 游戏结束界面:在游戏结束后,显示游戏结束图像,并等待用户退出游戏。

7. 完整实现代码

import pygame
from pygame.locals import *
import random


# 定义砖块类
class Brick:
    def __init__(self, position, color):
        # 初始化砖块的位置和颜色
        self.position = position
        self.color = color
        # 创建一个与砖块大小相同的图像
        self.image = pygame.Surface([brick_width, brick_height])
        # 用砖块的颜色填充图像
        self.image.fill(self.color)

    # 绘制砖块
    def draw(self):
        # 将砖块图像绘制到屏幕上
        screen.blit(self.image, (self.position[0] * brick_width, self.position[1] * brick_height))


# 定义方块类
class Block:
    def __init__(self, bricks_layout, direction, color):
        # 初始化方块的布局、方向和颜色
        self.bricks_layout = bricks_layout
        self.direction = direction
        self.current_layout = self.bricks_layout[self.direction]
        self.position = current_block_init_position
        self.stopped = False
        self.move_interval = 800
        self.bricks = []
        # 根据当前布局和颜色创建方块的砖块
        for (x, y) in self.current_layout:
            self.bricks.append(Brick(
                (self.position[0] + x, self.position[1] + y),
                color))

    # 设置方块的位置
    def set_position(self, position):
        self.position = position
        self.refresh_bricks()

    # 绘制方块
    def draw(self):
        # 绘制方块的所有砖块
        for brick in self.bricks:
            brick.draw()

    # 检查新位置是否合法
    @staticmethod
    def is_legal(layout, position):
        (x0, y0) = position
        for (x, y) in layout:
            # 如果新位置超出游戏区域或与已有砖块重叠,则不合法
            if x + x0 < 0 or y + y0 < 0 or x + x0 >= field_width or y + y0 >= field_height:
                return False
            if field_map[y + y0][x + x0] != 0:
                return False
        return True

    # 向左移动方块
    def move_left(self):
        new_position = (self.position[0] - 1, self.position[1])
        if self.is_legal(self.current_layout, new_position):
            self.position = new_position
            self.refresh_bricks()

    # 向右移动方块
    def move_right(self):
        new_position = (self.position[0] + 1, self.position[1])
        if self.is_legal(self.current_layout, new_position):
            self.position = new_position
            self.refresh_bricks()

    # 向下移动方块
    def move_down(self):
        (x, y) = (self.position[0], self.position[1] + 1)
        while self.is_legal(self.current_layout, (x, y)):
            self.position = (x, y)
            self.refresh_bricks()
            y += 1

    # 更新方块的砖块位置
    def refresh_bricks(self):
        for (brick, (x, y)) in zip(self.bricks, self.current_layout):
            brick.position = (self.position[0] + x, self.position[1] + y)

    # 停止方块并添加到游戏区域
    def stop(self):
        global field_bricks
        global score
        self.stopped = True
        ys = []
        for brick in self.bricks:
            field_bricks.append(brick)
            (x, y) = brick.position
            if y not in ys:
                ys.append(y)
            # 将砖块添加到游戏区域地图中
            field_map[y][x] = 1

        eliminate_count = 0
        ys.sort()
        for y in ys:
            if 0 in field_map[y]:
                continue
            eliminate_count += 1
            # 消除一行,将上面的行向下移动
            for fy in range(y, 0, -1):
                field_map[fy] = field_map[fy - 1][:]
            field_map[0] = [0 for _ in range(field_width)]

            # 更新消除行上方的砖块位置
            tmp_field_bricks = []
            for fb in field_bricks:
                (fx, fy) = fb.position
                if fy < y:
                    fb.position = (fx, fy + 1)
                    tmp_field_bricks.append(fb)
                elif fy > y:
                    tmp_field_bricks.append(fb)
            field_bricks = tmp_field_bricks
        # 根据消除的行数增加分数
        if eliminate_count == 1:
            score += 1
        elif eliminate_count == 2:
            score += 2
        elif eliminate_count == 3:
            score += 4
        elif eliminate_count == 4:
            score += 6

    # 更新方块的状态
    def update(self, c_time):
        global last_move
        self.draw()
        # 如果达到下落时间间隔,则尝试向下移动方块
        if last_move == -1 or c_time - last_move >= self.move_interval:
            new_position = (self.position[0], self.position[1] + 1)
            if self.is_legal(self.current_layout, new_position):
                self.position = new_position
                self.refresh_bricks()
                last_move = c_time
            else:
                self.stop()

    # 旋转方块
    def rotate(self):
        new_direction = (self.direction + 1) % len(self.bricks_layout)
        new_layout = self.bricks_layout[new_direction]
        if not self.is_legal(new_layout, self.position):
            return
        self.direction = new_direction
        self.current_layout = new_layout
        for (brick, (x, y)) in zip(self.bricks, self.current_layout):
            brick.position = (self.position[0] + x, self.position[1] + y)
        self.refresh_bricks()
        self.draw()


# 绘制游戏区域的砖块
def draw_field():
    for brick in field_bricks:
        brick.draw()


# 绘制信息面板
def draw_info_panel():
    font = pygame.font.Font("resources/fonts/MONACO.TTF", 18)
    survived_text = font.render('Score: ' + str(score), True, (255, 255, 255))
    text_rect = survived_text.get_rect()
    # noinspection SpellCheckingInspection
    text_rect.topleft = ((field_width + 2) * brick_width, 10)
    screen.blit(survived_text, text_rect)

    next_block.draw()


# 绘制游戏区域的边框
def draw_frame():
    frame_color = pygame.Color(200, 200, 200)
    pygame.draw.line(screen, frame_color, (field_width * brick_width, field_height * brick_height),
                     (field_width * brick_width, 0), 3)


# 随机生成一个方块
def get_block():
    block_type = random.randint(0, 6)
    if block_type == 0:
        return Block(bricks_layout_0, random.randint(0, len(bricks_layout_0) - 1), colors_for_bricks[0])
    elif block_type == 1:
        return Block(bricks_layout_1, random.randint(0, len(bricks_layout_1) - 1), colors_for_bricks[1])
    elif block_type == 2:
        return Block(bricks_layout_2, random.randint(0, len(bricks_layout_2) - 1), colors_for_bricks[2])
    elif block_type == 3:
        return Block(bricks_layout_3, random.randint(0, len(bricks_layout_3) - 1), colors_for_bricks[3])
    elif block_type == 4:
        return Block(bricks_layout_4, random.randint(0, len(bricks_layout_4) - 1), colors_for_bricks[4])
    elif block_type == 5:
        return Block(bricks_layout_5, random.randint(0, len(bricks_layout_5) - 1), colors_for_bricks[5])
    elif block_type == 6:
        return Block(bricks_layout_6, random.randint(0, len(bricks_layout_6) - 1), colors_for_bricks[6])


# 方块布局定义
# 0: oooo
# 1: oo
#    oo
# 2: o
#   ooo
# 3: o
#    oo
#     o
# 4:  o
#    oo
#    o
# 5: ooo
#    o
# 6: ooo
#      o
bricks_layout_0 = (
    ((0, 0), (0, 1), (0, 2), (0, 3)),
    ((0, 1), (1, 1), (2, 1), (3, 1)))
bricks_layout_1 = (
    ((1, 0), (2, 0), (1, 1), (2, 1)),
)
bricks_layout_2 = (
    ((1, 0), (0, 1), (1, 1), (2, 1)),
    ((0, 1), (1, 0), (1, 1), (1, 2)),
    ((1, 2), (0, 1), (1, 1), (2, 1)),
    ((2, 1), (1, 0), (1, 1), (1, 2)),
)
bricks_layout_3 = (
    ((0, 1), (1, 1), (1, 0), (2, 0)),
    ((0, 0), (0, 1), (1, 1), (1, 2)),
)
bricks_layout_4 = (
    ((0, 0), (1, 0), (1, 1), (2, 1)),
    ((1, 0), (1, 1), (0, 1), (0, 2)),
)
bricks_layout_5 = (
    ((0, 0), (1, 0), (1, 1), (1, 2)),
    ((0, 2), (0, 1), (1, 1), (2, 1)),
    ((1, 0), (1, 1), (1, 2), (2, 2)),
    ((2, 0), (2, 1), (1, 1), (0, 1)),
)
bricks_layout_6 = (
    ((2, 0), (1, 0), (1, 1), (1, 2)),
    ((0, 0), (0, 1), (1, 1), (2, 1)),
    ((0, 2), (1, 2), (1, 1), (1, 0)),
    ((2, 2), (2, 1), (1, 1), (0, 1)),
)

# 方块颜色定义
colors_for_bricks = (
    pygame.Color(255, 0, 0), pygame.Color(0, 255, 0), pygame.Color(0, 0, 255),
    pygame.Color(100, 100, 100), pygame.Color(120, 200, 0), pygame.Color(100, 0, 200),
    pygame.Color(10, 100, 30))

# 游戏区域大小
field_width, field_height = 12, 17
# 当前方块的初始位置
current_block_init_position = (4, 0)
# 信息面板宽度
info_panel_width = 8
# 下一个方块的初始位置
next_block_init_position = (field_width + 3, 5)
# 游戏区域地图,0表示无砖块,1表示有砖块
field_map = [[0 for i in range(field_width)] for j in range(field_height)]

# 游戏结束图像
game_over_img = pygame.image.load("resources/images/game_over.gif")

# 游戏是否在运行
running = True
# 当前分数
score = 0
# 砖块大小
brick_width, brick_height = 30, 30
# 游戏区域的砖块列表
field_bricks = []

# 下一个方块
next_block = None
# 上次移动时间
last_move = -1

# 初始化pygame
pygame.init()
# 创建屏幕
screen = pygame.display.set_mode(((field_width + info_panel_width) * brick_width, field_height * brick_height), 0, 32)
# 设置游戏标题
pygame.display.set_caption('Tetris')

# 主游戏循环
while running:
    # 如果下一个方块不存在,则生成一个新方块
    if next_block is None:
        current_block = get_block()
    else:
        current_block = next_block
        current_block.set_position(current_block_init_position)
    # 生成下一个方块
    next_block = get_block()
    next_block.set_position(next_block_init_position)

    # 如果新方块的位置不合法,则游戏结束
    if not current_block.is_legal(current_block.current_layout, current_block.position):
        current_block.draw()
        running = False
        continue
    # 当前方块没有停止时,不断更新其状态
    while not current_block.stopped:
        # 清空屏幕
        screen.fill(0)
        # 绘制游戏区域边框
        draw_frame()
        # 获取当前时间
        time = pygame.time.get_ticks()
        # 更新当前方块的状态
        current_block.update(time)
        # 绘制游戏区域的砖块
        draw_field()
        # 绘制信息面板
        draw_info_panel()

        # 更新屏幕
        pygame.display.flip()
        pygame.display.update()
        # 处理事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # 退出游戏
                pygame.quit()
                exit(0)
            if event.type == pygame.KEYDOWN:
                if event.key == K_w or event.key == K_UP:
                    # 旋转方块
                    current_block.rotate()
                    last_move = time
                elif event.key == K_a or event.key == K_LEFT:
                    # 向左移动方块
                    current_block.move_left()
                elif event.key == K_d or event.key == K_RIGHT:
                    # 向右移动方块
                    current_block.move_right()
                elif event.key == K_s or event.key == K_DOWN:
                    # 向下移动方块
                    current_block.move_down()
                    last_move = time - 500

# 游戏结束后,显示游戏结束图像
screen.blit(game_over_img, (field_width / 2 * brick_width, (field_height / 2 - 2) * brick_height))

# 等待玩家退出游戏
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)
    # 更新屏幕
    pygame.display.flip()
    pygame.display.update()

源码仓库地址:https://gitcode.com/stormsha1/games.git
代码需要的字体和结束动画都在仓库中,资源目录:tetris/resources

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1634869.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Tortoise 创建远程分支

1。首先创建本地分支branch1&#xff0c;右键tortoise git->创建分支&#xff0c;输入分支名称branch1&#xff0c;确定。 2。右键tortoise git->推送&#xff0c;按下图设置&#xff0c;确定&#xff0c;git会判断远程有没有分支branch1&#xff0c;如果没有会自动创建…

QT类之间主窗口子窗口传递*指针对象

1.新建CFile_Operation 类文件 2.主窗口头文件声明&#xff1a; CFile_Operation *cfile_operation; 按钮点击事件函数里面调用子窗口 dialog_debug new Dialog_Debug(this);connect(this,&MainWindow_oq::SendCfile_operation_Obj,dialog_debug,&Dialog_Debug::R…

【redis】初始redis和分布式系统的基本知识

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

Linux中ssh登录协议

目录 一.ssh基础 1.ssh协议介绍 2.ssh协议的优点 3.ssh文件位置 二.ssh原理 1.公钥传输原理&#xff08;首次连接&#xff09; 2.ssh加密通讯原理 &#xff08;1&#xff09;对称加密 &#xff08;2&#xff09;非对称加密 3.远程登录 三.服务端的配置 常用的配置项…

C++信息学奥赛 数据结构认识

数据结构 1.1数据结构分类 1.2基本数据类型 1.3数字编码 1.4字符编码 1.1数据结构分类 数据结构如同一副稳固而多样的框架。为数据的有序组织提供了蓝图&#xff0c;算法得以在此基础上生动起来。 常用的数据结构包括哪些 &#xff0c; &#xff0c; &…

QA测试开发工程师面试题满分问答21: 单元测试、集成测试、系统测试的侧重点是什么?

单元测试、集成测试和系统测试是软件测试中的不同层次和阶段&#xff0c;每个阶段侧重于不同的测试目标和范围。以下是它们的侧重点的简要说明&#xff1a; 单元测试&#xff1a; 单元测试是针对软件中最小的可测试单元&#xff08;通常是函数、方法或模块&#xff09;进行的测…

版本控制系统-Git

目录 1. Git简介 2. 下载及安装 3.命令行操做 3.1全局设置 3.2初始化仓库 3.3提交代码 3.4查看提交历史 3.5推送代码 3.6拉取合并代码 3.7克隆仓库 3.8. 配置忽略文件 3.9. 凭据管理 4. GUI工具操作 4.1. 全局设置 4.2. 初始化仓库 4.3. 提交代码 输入提交日志…

Gone框架介绍3 - 使用gone命令,自动生成Priest函数

文章目录 1. 安装辅助工具: gone2. 创建一个名为gen-code的新项目3. 创建Goner4. 使用辅助工具5. 添加main函数 我在两年前实现了一个Golang的依赖注入框架&#xff0c;并且集成了gin、xorm、redis、cron、消息中间件等功能&#xff0c;自己觉得还挺好用的&#xff1b;之前一直…

Jenkins首次Build,配置Git,Maven,JDK,凭证管理

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudso…

有哪些好用电脑端时间定时软件?桌面日程安排软件推荐 桌面备忘录

随着现代生活节奏的加快&#xff0c;人们对于时间管理和任务提醒的需求越来越大。为了满足这一需求&#xff0c;市场上涌现出了众多桌面便签备忘录软件&#xff0c;它们不仅可以帮助我们记录待办事项&#xff0c;还能定时提醒我们完成任务。在这篇文章中&#xff0c;我将为大家…

宝子们,到我选Offer了

A. 腾讯IEG光子 游戏客户端 Base 深圳 优点&#xff1a; 1. Title可以&#xff0c;是IEG正经游戏工作室 2. 这可是鹅啊&#xff0c;可以吟唱《作废》歌 缺点&#xff1a; 1. 离得远 要租房 2. 5000HC 转正率懂得都懂 3. 可能会参与预研的东西 不会很快参与…

HaLo-NeRF:利用视觉和语言模型对场景的精准定位和细粒度语义理解

包含大量摄影师拍摄的照片的互联网图像集有望实现对大型旅游地标的数字探索。然而&#xff0c;先前的工作主要集中在几何重建和可视化上&#xff0c;忽略了语言在为导航和细粒度理解提供语义界面方面的关键作用。 项目&#xff1a;HaLo-NeRF: Learning Geometry-Guided Semant…

Ansible自动化运维工具主机清单配置

作者主页&#xff1a;点击&#xff01; Ansible专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月24日12点21分 Ansible主机清单文件用于定义要管理的主机及其相关信息。它是Ansible的核心配置文件之一&#xff0c;用于Ansible识别目标主机并与其建立连接。 …

win10安装DHCP服务--用于2台机器之间搭建简易网络来进入目标机器修改配置

前言&#xff1a; 客户多了&#xff0c;往往会出现各种突发情况。 比如一个客户现场没有DHCP&#xff0c;没有显示器&#xff0c;键盘。 你只有一台笔记本的情况下要配置目标机器的网络。要如何配置&#xff1f;&#xff1f; 这时候就可以使用这篇博客提供的方式了。 Windows…

分布式与一致性协议之CAP和Paxos算法(一)

CAP 理论 如何使用BASE理论 以InfluxDB系统中DATA节点的集群实现为例。DATA节点的核心功能是读和写&#xff0c;所以基本可用是指读和写的基本可用。我们可以通过分片和多副本实现读和写的基本可用。也就是说&#xff0c;将同一业务的数据先分片&#xff0c;再以多份副本的形…

STM32驱动SYN6288语音合成模块

STM32驱动SYN6288语音合成模块 简介功能特点通讯方式接线代码结果总结 简介 SYN6288通过异步串口(UART) 通讯方式&#xff0c;接收待合成的文本数据&#xff0c;从而实现文本到语音的转换SYN06188 语音芯片的优秀特点:最小SS0P28L 贴片封装、硬件接口简单、低功耗、音色清亮圆…

C++中auto关键字的用法详解

1.简介 auto作为一个C语言就存在的关键字&#xff0c;在C语言和C之间却有很大区别。 在C语言中auto修饰的变量&#xff0c;是具有自动存储器的局部变量&#xff0c;但因为局部变量默认类别默认是auto修饰导致一直没有人去使用它。 C11中&#xff0c;标准委员会赋予了auto全新…

Linux学习笔记:进程间的通信.共享内存shm

共享内存shm 什么是共享内存shm共享内存的特点关键函数ftokshmgetshmatshmdtshmctl 代码示例 什么是共享内存shm 进程间通信的前提:必须让不同的进程看到同一份资源,并且这个资源是OS提供的 而共享内存(Share memory)就是在内核共享内存区找一块物理内存空间,并允许多个进程共…

西瓜书学习——决策树形状、熵和决策树的本质

文章目录 决策树形状监督学习算法分类与回归 熵信息熵香农熵 (Shannon Entropy) - H(X)联合熵 (Joint Entropy) - H(X, Y)条件熵 (Conditional Entropy) - H(Y|X)互信息 (Mutual Information) - I(X; Y)相对熵 (Relative Entropy) / KL散度 (Kullback-Leibler Divergence) - DK…

学习CSS3,实现红色心形loading特效

试想一下&#xff0c;如果你的网站在加载过程中&#xff0c;loading图由一个老旧的菊花转动图片&#xff0c;变为一个红色的心形loading特效&#xff0c;那该有多炫酷啊。 目录 实现思路 初始化HTML部分 延迟动画是重点 设定动画效果 完整源代码 最后 实现思路 每个…