【Python】用Python写一个俄罗斯方块玩玩

【Python】用Python写一个俄罗斯方块玩玩

  • 一、引言
    • 1.成品效果展示
  • 二、思考准备
    • 1.思考设计
    • 2.代码设计
      • 2.1 游戏页面
      • 2.2 控件设计
        • 2.2.1 方块生成
        • 2.2.2 方块碰撞
        • 2.2.3 方块消融
        • 2.2.4 游戏主循环
        • 2.2.5 游戏窗口
  • 三、游戏完整版

一、引言

  • 今日看到侄子在玩游戏,凑近一看,原来是俄罗斯方块。熟悉又怀念,童年的记忆瞬间涌上心头。小时候觉得这游戏老厉害了,现在想想,好像就是数组的组合和消融,便想着自己写一个试试。说干就干,冲!

1.成品效果展示

俄罗斯方块实现过程

二、思考准备

1.思考设计

在这里插入图片描述

  • 俄罗斯方块作为风靡一时的游戏,由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的休闲游戏,主要是通过方块的组合、消融完成的;
  • 所以得先设计有哪些方块、方块如何组合、完成一行时方块消融并下降一行、方块组合还得回旋转,单次90°等等,考虑中ing…

2.代码设计

2.1 游戏页面

  • 游戏首先得有个操控页面,所以得设计一个
# 设计游戏窗口尺寸
SCREEN_WIDTH, SCREEN_HEIGHT = 300, 600  
# 方块大小
GRID_SIZE = 30     
# 各种图形颜色 可自定义调整                    
COLORS = [            # 颜色配置(含背景色+7种方块色)(0, 0, 0),        # 0: 黑色背景(255, 0, 0),      # 1: 红色-I型(0, 255, 0),      # 2: 绿色-T型(0, 0, 255),      # 3: 蓝色-J型(255, 165, 0),    # 4: 橙色-L型(255, 255, 0),    # 5: 黄色-O型(128, 0, 128),    # 6: 紫色-S型(0, 255, 255)     # 7: 青色-Z型
]

2.2 控件设计

2.2.1 方块生成
  • 游戏开始最上方会有方块掉落,随机形状和颜色

def new_piece(self):"""生成新方块,随机形状和颜色"""shape = random.choice(SHAPES)return {'shape': shape,                                        # 方块形状矩阵'x': (SCREEN_WIDTH//GRID_SIZE - len(shape[0])) // 2,   # 初始水平居中'y': 0,                                                # 初始垂直位置'color': random.randint(1, len(COLORS)-1)              # 随机颜色(排除背景色)}
2.2.2 方块碰撞
  • 方块会一直下降,碰撞,下降时还要符合可以多次旋转

def check_collision(self, dx=0, dy=0, rotate=False):"""碰撞检测函数:param dx: 水平移动偏移量:param dy: 垂直移动偏移量:param rotate: 是否正在旋转:return: 是否发生碰撞"""shape = self.current_piece['shape']# 旋转时生成临时形状if rotate:         shape = [list(row[::-1]) for row in zip(*shape)]  # 矩阵旋转算法:先转置再反转每行(顺时针90度)for y, row in enumerate(shape):for x, cell in enumerate(row):if cell:                        # 仅检测实体方块new_x = self.current_piece['x'] + x + dxnew_y = self.current_piece['y'] + y + dy# 边界检测(左右越界/触底/与其他方块重叠)if not (0 <= new_x < len(self.grid[0])) or new_y >= len(self.grid):return Trueif new_y >=0 and self.grid[new_y][new_x]:return Truereturn False
2.2.3 方块消融
  • 方块接触时,合适的会消融、不合适的会叠加,消融了计算分数,消融的还要剔除
def merge_piece(self):"""将当前方块合并到游戏网格,并触发消行检测"""for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:# 将方块颜色写入网格对应位置self.grid[self.current_piece['y']+y][self.current_piece['x']+x] = self.current_piece['color']# 消行并更新分数lines = self.clear_lines()self.score += lines * 100def clear_lines(self):"""消除满行并返回消除行数"""lines = 0# 从底部向上扫描for i, row in enumerate(self.grid):if all(cell !=0 for cell in row):       # 检测整行填满del self.grid[i]                    # 删除该行self.grid.insert(0, [0]*len(row))   # 在顶部插入新空行lines +=1return lines
2.2.4 游戏主循环
  • 游戏主体逻辑写入,方块的处理时间、操作事项和刷新等

def run(self):"""游戏主循环"""fall_time = 0       # 下落时间累计器while True:self.screen.fill(COLORS[0])            # 用背景色清屏# 计时系统(控制自动下落速度)fall_time += self.clock.get_rawtime()self.clock.tick()        # 保持帧率稳定# 自动下落逻辑(每800ms下落一格)if fall_time >= 800:if not self.check_collision(dy=1):self.current_piece['y'] +=1                 # 正常下落else:self.merge_piece()                          # 触底合并self.current_piece = self.new_piece()       # 生成新方块# 游戏结束检测(新方块无法放置)if self.check_collision():print("Game Over 你完蛋啦! Score:", self.score)returnfall_time =0   # 重置计时器# 事件处理(适配Mac键盘布局)for event in pygame.event.get():if event.type == QUIT:pygame.quit()returnif event.type == KEYDOWN:# 左右移动(带碰撞检测)if event.key == K_LEFT and not self.check_collision(dx=-1):self.current_piece['x'] -=1elif event.key == K_RIGHT and not self.check_collision(dx=1):self.current_piece['x'] +=1# 软下落(手动加速)elif event.key == K_DOWN:if not self.check_collision(dy=1):self.current_piece['y'] +=1# 旋转方块(带碰撞检测)elif event.key == K_UP and not self.check_collision(rotate=True):self.current_piece['shape'] = [list(row[::-1]) for row in zip(*self.current_piece['shape'])]# 硬下落(空格键一键到底)    elif event.key == K_SPACE:  while not self.check_collision(dy=1):self.current_piece['y'] +=1# 绘制逻辑,游戏网格for y, row in enumerate(self.grid):for x, color in enumerate(row):if color:# 绘制已落下方块(留1像素间隙)pygame.draw.rect(self.screen, COLORS[color], (x*GRID_SIZE, y*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))# 绘制当前操作方块for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:pygame.draw.rect(self.screen, COLORS[self.current_piece['color']],((self.current_piece['x']+x)*GRID_SIZE, (self.current_piece['y']+y)*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))# 刷新画面pygame.display.flip()  
2.2.5 游戏窗口
  • 最后,游戏设计好了,必须有个游戏窗口来展示

def __init__(self):# 初始化游戏窗口self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("Mac M1俄罗斯方块")self.clock = pygame.time.Clock()   # 游戏时钟控制帧率# 游戏状态初始化self.grid = [[0]*(SCREEN_WIDTH//GRID_SIZE) for _ in range(SCREEN_HEIGHT//GRID_SIZE)]              # 20x10游戏网格self.current_piece = self.new_piece()     # 当前操作方块self.score = 0                           

三、游戏完整版


# 俄罗斯方块设计
# -*- coding: utf-8 -*-  
"""
功能:俄罗斯方块,童年的回忆
作者:看海的四叔
最后更新:2025-04-16
"""import pygame
import random
from pygame.locals import *# 初始化配置
pygame.init()                           
SCREEN_WIDTH, SCREEN_HEIGHT = 300, 600  
GRID_SIZE = 30                          
COLORS = [            (0, 0, 0),        (255, 0, 0),      (0, 255, 0),      (0, 0, 255),      (255, 165, 0),    (255, 255, 0),    (128, 0, 128),    (0, 255, 255)     
]SHAPES = [[[1,1,1,1]],                [[1,1],[1,1]],              [[0,1,0], [1,1,1]],         [[1,1,1], [1,0,0]],         [[1,1,1], [0,0,1]],         [[0,1,1], [1,1,0]],         [[1,1,0], [0,1,1]]          
]class Tetris:"""游戏主控制类,处理游戏逻辑与渲染"""def __init__(self):self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))pygame.display.set_caption("Mac M1俄罗斯方块")self.clock = pygame.time.Clock()  self.grid = [[0]*(SCREEN_WIDTH//GRID_SIZE) for _ in range(SCREEN_HEIGHT//GRID_SIZE)] self.current_piece = self.new_piece()    self.score = 0                           def new_piece(self):"""生成新方块(随机形状和颜色)"""shape = random.choice(SHAPES)return {'shape': shape,                                        'x': (SCREEN_WIDTH//GRID_SIZE - len(shape[0])) // 2,   'y': 0,                                                'color': random.randint(1, len(COLORS)-1)              }def check_collision(self, dx=0, dy=0, rotate=False):"""碰撞检测函数:param dx: 水平移动偏移量:param dy: 垂直移动偏移量:param rotate: 是否正在旋转:return: 是否发生碰撞"""shape = self.current_piece['shape']if rotate:         shape = [list(row[::-1]) for row in zip(*shape)]  for y, row in enumerate(shape):for x, cell in enumerate(row):if cell:                       new_x = self.current_piece['x'] + x + dxnew_y = self.current_piece['y'] + y + dyif not (0 <= new_x < len(self.grid[0])) or new_y >= len(self.grid):return Trueif new_y >=0 and self.grid[new_y][new_x]:return Truereturn Falsedef merge_piece(self):"""将当前方块合并到游戏网格,并触发消行检测"""for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:self.grid[self.current_piece['y']+y][self.current_piece['x']+x] = self.current_piece['color']lines = self.clear_lines()self.score += lines * 100def clear_lines(self):"""消除满行并返回消除行数"""lines = 0for i, row in enumerate(self.grid):if all(cell !=0 for cell in row):       del self.grid[i]                    self.grid.insert(0, [0]*len(row))   lines +=1return linesdef run(self):"""游戏主循环"""fall_time = 0      while True:self.screen.fill(COLORS[0])           fall_time += self.clock.get_rawtime()self.clock.tick()       if fall_time >= 800:if not self.check_collision(dy=1):self.current_piece['y'] +=1                 # 正常下落else:self.merge_piece()                          self.current_piece = self.new_piece()       # 游戏结束检测(新方块无法放置)if self.check_collision():print("Game Over 你完蛋啦! Score:", self.score)returnfall_time =0   # 重置计时器for event in pygame.event.get():if event.type == QUIT:pygame.quit()returnif event.type == KEYDOWN:if event.key == K_LEFT and not self.check_collision(dx=-1):self.current_piece['x'] -=1elif event.key == K_RIGHT and not self.check_collision(dx=1):self.current_piece['x'] +=1elif event.key == K_DOWN:if not self.check_collision(dy=1):self.current_piece['y'] +=1elif event.key == K_UP and not self.check_collision(rotate=True):self.current_piece['shape'] = [list(row[::-1]) for row in zip(*self.current_piece['shape'])]elif event.key == K_SPACE:  while not self.check_collision(dy=1):self.current_piece['y'] +=1for y, row in enumerate(self.grid):for x, color in enumerate(row):if color:pygame.draw.rect(self.screen, COLORS[color], (x*GRID_SIZE, y*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))for y, row in enumerate(self.current_piece['shape']):for x, cell in enumerate(row):if cell:pygame.draw.rect(self.screen, COLORS[self.current_piece['color']],((self.current_piece['x']+x)*GRID_SIZE, (self.current_piece['y']+y)*GRID_SIZE, GRID_SIZE-1, GRID_SIZE-1))pygame.display.flip()  if __name__ == "__main__":game = Tetris()game.run()

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

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

相关文章

维港首秀!沃飞长空AE200亮相香港特别行政区

4月13日-16日&#xff0c;第三届香港国际创科展在香港会议展览中心盛大举办。 作为国内领先、国际一流的eVTOL主机厂&#xff0c;沃飞长空携旗下AE200批产构型登陆国际舞台&#xff0c;以前瞻性的创新技术与商业化应用潜力&#xff0c;吸引了来自全球17个国家及地区的行业领袖…

Openfein实现远程调用的方法(实操)

文章目录 环境准备一、URL中接收参数二、接收一个参数三、接收多个参数四、传递对象五、传递JSON格式数据 环境准备 下面的配置&#xff0c;服务调用方加入即可。 依赖导入&#xff1a; <!-- openfeign依赖--><dependency><groupId>org.springframe…

Bright+Data网页解锁器:旅游行业数据革命的“隐形引擎”

在数字经济浪潮中&#xff0c;旅游行业正经历前所未有的变革。当消费者指尖滑动间完成跨国酒店预订&#xff0c;当航空公司每秒调整万次舱位价格&#xff0c;背后是一场无声的数据战争。而在这场战争中&#xff0c;BrightData网页解锁器正成为旅游企业破局的关键武器——它像一…

OpenCV 图形API(38)图像滤波-----Sobel 算子操作函数Sobel()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::gapi::Sobel 函数是 OpenCV 的 G-API 模块中用于执行 Sobel 算子操作的一个函数&#xff0c;主要用于图像的边缘检测。Sobel 算子通过计算图…

CS5346 - Interactivity in Visualization 可视化中的交互

文章目录 Visualization representation interactionInteraction &#xff08;交互&#xff09;Benefits (好处)Typical Interaction Techniques&#xff08;交互技术&#xff09;SelectFilteringAbstract / Elaborate几何放缩&#xff08;Geometric zoom)语义放缩&#xff0…

第十六届蓝桥杯大赛软件赛省赛 C++ 大学 B 组 部分题解

赛时参加的是Python组&#xff0c;这是赛后写的题解&#xff0c;还有两题暂时还不会&#xff0c;待更新 题目链接题目列表 - 洛谷 | 计算机科学教育新生态 A 移动距离 答案&#xff1a;1576 C 可分解的正整数 Python3 import itertools from functools import cmp_to_ke…

Vue 解决 Error: please transfer a valid prop path to form item!

在 Vue.js 中使用表单验证库&#xff08;如 VeeValidate 或 Element UI 的表单组件时&#xff09;&#xff0c;遇到错误信息 "please transfer a valid prop path to form item!" 通常指的是在表单项的属性绑定中&#xff0c;路径&#xff08;prop path&#xff09;不…

在 Visual Studio Code 中安装通义灵码 - 智能编码助手

高效的编码工具对于提升开发效率和代码质量至关重要。 通义灵码作为一款智能编码助手&#xff0c;为开发者提供了全方位的支持。 本文将详细介绍如何在 Visual Studio Code&#xff08;简称 VSCode&#xff09;中安装通义灵码&#xff0c;以及如何进行相关配置以开启智能编码…

SQL 解析 with as dual sysdate level

目录 sql的运行顺序 with as EXTRACT ​编辑 dual sysdate level ​编辑 ​编辑 Oracle中的日期存储 核心部分 拆解字符串并计算最小值 关联子查询 NVL 函数 REGEXP_SUBSTR() sql的运行顺序 <select id="getTrendList" parameterType="java.uti…

快手OneRec 重构推荐系统:从检索排序到生成统一的跃迁

文章目录 1. 背景2. 方法2.1 OneRec框架2.2 Preliminary2.3 生成会话列表2.4 利用奖励模型进行迭代偏好对齐2.4.1 训练奖励模型2.4.2 迭代偏好对齐 3. 总结 昨天面试的时候聊到了OneRec&#xff0c;但是由于上次看这篇文章已经是一个月之前&#xff0c;忘得差不多了&#xff0c…

软考高级系统架构设计师-第11章 系统架构设计

【本章学习建议】 根据考试大纲&#xff0c;本章不仅考查系统架构设计师单选题&#xff0c;预计考12分左右&#xff0c;而且案例分析和论文写作也是必考&#xff0c;对应第二版教材第7章&#xff0c;属于重点学习的章节。 软考高级系统架构设计师VIP课程https://edu.csdn.net/…

selenium之文件下载

Selenium 自动化测试&#xff1a;轻松搞定文件下载 在 Web 自动化测试中&#xff0c;经常会遇到需要验证文件下载功能的场景。例如&#xff0c;测试报告的导出、用户上传文件的下载、PDF 文档的生成与下载等等。Selenium 本身并没有直接处理文件下载的内置方法&#xff0c;但我…

基于迁移学习实现肺炎X光片诊断分类

大家好&#xff0c;我是带我去滑雪&#xff01; 肺炎是全球范围内致死率较高的疾病之一&#xff0c;尤其是在老年人、免疫系统较弱的患者群体中&#xff0c;更容易引发严重并发症。传统上&#xff0c;肺炎的诊断依赖于医生的临床经验以及影像学检查&#xff0c;尤其是X光片&…

工业数据治理范式革新:时序数据库 TDengine虚拟表技术解析

小T导读&#xff1a;在工业数字化过程中&#xff0c;数据如何从设备采集顺利“爬坡”到上层应用&#xff0c;一直是个难题。传统“单列模型”虽贴合设备协议&#xff0c;却让上层分析举步维艰。TDengine 用一种更聪明的方法打通了这条数据通路&#xff1a;不强求建模、不手动转…

Redis面试——日志

一、RDB&#xff08;Redis DataBase&#xff09; RDB 全程是 Redis DataBase&#xff0c;它是一种将 Redis 在某一时刻内存中的数据以快照形式保存到磁盘的机制 &#xff0c;相当于给执行save/bgsave命令时刻的内存数据库数据拍了一张快照我们如果通过save命令来执行快照&…

【Android】常用参数实践 用户界面UI 布局文件XML

本文将系统总结 Android XML 布局的通用参数和常用布局类型的专属规则 一、通用布局参数 这些参数适用于所有 View 和 ViewGroup&#xff0c;是布局设计的基石。 1. 尺寸控制 android:layout_width 与 android:layout_height 定义视图的宽度和高度&#xff0c;可选值&#xf…

解决 VSCode 中 NVM 配置后无法识别 Node 和 NPM 的问题

在开发中&#xff0c;我们经常需要使用 Node.js 和 NPM 来管理 JavaScript 项目依赖&#xff0c;而 NVM&#xff08;Node Version Manager&#xff09;是开发者在本地环境中管理多个 Node.js 版本的得力工具。不过&#xff0c;有时候在 VSCode 中配置完 NVM 后&#xff0c;可能…

BGP分解实验·23——BGP选路原则之路由器标识

在选路原则需要用到Router-ID做选路决策时&#xff0c;其对等体Router-ID较小的路由将被优选&#xff1b;其中&#xff0c;当路由被反射时&#xff0c;包含起源器ID属性时&#xff0c;该属性将代替router-id做比较。 实验拓扑如下&#xff1a; 实验通过调整路由器R1和R2的rout…

Linux: 线程同步

目录 一 前言 二 线程饥饿 三 线程同步 四 条件变量 1. cond &#xff08; condition&#xff09; 2. pthread_cond_wait() &#xff1a; 3. pthread_cond_signal() 五 条件变量的使用 一 前言 在上篇文章Linux : 多线程互斥-CSDN博客我们讲解了线程互斥的概念&#xff…

MyBatisPlus-QueryWrapper的exists方法拼接SQL中的EXISTS子句

在 MyBatis-Plus 中,QueryWrapper 的 exists 方法用于拼接 SQL 中的 EXISTS 子句,通常用于构 建子查询条件。以下是具体用法和示例: ​​1. 基本语法​​ // 判断是否存在符合条件的记录 queryWrapper.exists(String existsSql); queryWrapper.notExists(String existsSq…