俄罗斯方块

news/2024/12/2 19:51:49/

1. 案例介绍

俄罗斯方块是由 4 个小方块组成不同形状的板块,随机从屏幕上方落下,按方向键调整板块的位置和方向,在底部拼出完整的一行或几行。这些完整的横条会消失,给新落下来的板块腾出空间,并获得分数奖励。没有被消除掉的方块不断堆积,一旦堆到顶端,便告输,游戏结束。本例难度为高级,适合具有 Python 进阶和 Pygame 编程技巧的用户学习。

2. 设计要点

边框――由 15*25 个空格组成,方块就落在这里面。盒子――组成方块的其中小方块,是组成方块的基本单元。方块――从边框顶掉下的东西,游戏者可以翻转和改变位置。每个方块由 4 个盒子组成。形状――不同类型的方块。这里形状的名字被叫做 T, S, Z ,J, L, I , O。如下图所示:

图片

图片

模版――用一个列表存放形状被翻转后的所有可能样式。全部存放在变量里,变量名字如 S or J。着陆――当一个方块到达边框的底部或接触到在其他的盒子话,就说这个方块着陆了。那样的话,另一个方块就会开始下落。

3. 示例效果

图片

4. 示例源码


 

import pygame
import random
import ospygame.init()GRID_WIDTH = 20
GRID_NUM_WIDTH = 15
GRID_NUM_HEIGHT = 25
WIDTH, HEIGHT = GRID_WIDTH * GRID_NUM_WIDTH, GRID_WIDTH * GRID_NUM_HEIGHT
SIDE_WIDTH = 200
SCREEN_WIDTH = WIDTH + SIDE_WIDTH
WHITE = (0xff, 0xff, 0xff)
BLACK = (0, 0, 0)
LINE_COLOR = (0x33, 0x33, 0x33)CUBE_COLORS = [(0xcc, 0x99, 0x99), (0xff, 0xff, 0x99), (0x66, 0x66, 0x99),(0x99, 0x00, 0x66), (0xff, 0xcc, 0x00), (0xcc, 0x00, 0x33),(0xff, 0x00, 0x33), (0x00, 0x66, 0x99), (0xff, 0xff, 0x33),(0x99, 0x00, 0x33), (0xcc, 0xff, 0x66), (0xff, 0x99, 0x00)
]screen = pygame.display.set_mode((SCREEN_WIDTH, HEIGHT))
pygame.display.set_caption("俄罗斯方块")
clock = pygame.time.Clock()
FPS = 30score = 0
level = 1screen_color_matrix = [[None] * GRID_NUM_WIDTH for i in range(GRID_NUM_HEIGHT)]# 设置游戏的根目录为当前文件夹
base_folder = os.path.dirname(__file__)def show_text(surf, text, size, x, y, color=WHITE):font_name = os.path.join(base_folder, 'font/font.ttc')font = pygame.font.Font(font_name, size)text_surface = font.render(text, True, color)text_rect = text_surface.get_rect()text_rect.midtop = (x, y)surf.blit(text_surface, text_rect)class CubeShape(object):SHAPES = ['I', 'J', 'L', 'O', 'S', 'T', 'Z']I = [[(0, -1), (0, 0), (0, 1), (0, 2)],[(-1, 0), (0, 0), (1, 0), (2, 0)]]J = [[(-2, 0), (-1, 0), (0, 0), (0, -1)],[(-1, 0), (0, 0), (0, 1), (0, 2)],[(0, 1), (0, 0), (1, 0), (2, 0)],[(0, -2), (0, -1), (0, 0), (1, 0)]]L = [[(-2, 0), (-1, 0), (0, 0), (0, 1)],[(1, 0), (0, 0), (0, 1), (0, 2)],[(0, -1), (0, 0), (1, 0), (2, 0)],[(0, -2), (0, -1), (0, 0), (-1, 0)]]O = [[(0, 0), (0, 1), (1, 0), (1, 1)]]S = [[(-1, 0), (0, 0), (0, 1), (1, 1)],[(1, -1), (1, 0), (0, 0), (0, 1)]]T = [[(0, -1), (0, 0), (0, 1), (-1, 0)],[(-1, 0), (0, 0), (1, 0), (0, 1)],[(0, -1), (0, 0), (0, 1), (1, 0)],[(-1, 0), (0, 0), (1, 0), (0, -1)]]Z = [[(0, -1), (0, 0), (1, 0), (1, 1)],[(-1, 0), (0, 0), (0, -1), (1, -1)]]SHAPES_WITH_DIR = {'I': I, 'J': J, 'L': L, 'O': O, 'S': S, 'T': T, 'Z': Z}def __init__(self):self.shape = self.SHAPES[random.randint(0, len(self.SHAPES) - 1)]# 骨牌所在的行列self.center = (2, GRID_NUM_WIDTH // 2)self.dir = random.randint(0, len(self.SHAPES_WITH_DIR[self.shape]) - 1)self.color = CUBE_COLORS[random.randint(0, len(CUBE_COLORS) - 1)]def get_all_gridpos(self, center=None):curr_shape = self.SHAPES_WITH_DIR[self.shape][self.dir]if center is None:center = [self.center[0], self.center[1]]return [(cube[0] + center[0], cube[1] + center[1])for cube in curr_shape]def conflict(self, center):for cube in self.get_all_gridpos(center):# 超出屏幕之外,说明不合法if cube[0] < 0 or cube[1] < 0 or cube[0] >= GRID_NUM_HEIGHT or \cube[1] >= GRID_NUM_WIDTH:return True# 不为None,说明之前已经有小方块存在了,也不合法if screen_color_matrix[cube[0]][cube[1]] is not None:return Truereturn Falsedef rotate(self):new_dir = self.dir + 1new_dir %= len(self.SHAPES_WITH_DIR[self.shape])old_dir = self.dirself.dir = new_dirif self.conflict(self.center):self.dir = old_dirreturn Falsedef down(self):# import pdb; pdb.set_trace()center = (self.center[0] + 1, self.center[1])if self.conflict(center):return Falseself.center = centerreturn Truedef left(self):center = (self.center[0], self.center[1] - 1)if self.conflict(center):return Falseself.center = centerreturn Truedef right(self):center = (self.center[0], self.center[1] + 1)if self.conflict(center):return Falseself.center = centerreturn Truedef draw(self):for cube in self.get_all_gridpos():pygame.draw.rect(screen, self.color,(cube[1] * GRID_WIDTH, cube[0] * GRID_WIDTH,GRID_WIDTH, GRID_WIDTH))pygame.draw.rect(screen, WHITE,(cube[1] * GRID_WIDTH, cube[0] * GRID_WIDTH,GRID_WIDTH, GRID_WIDTH),1)def draw_grids():for i in range(GRID_NUM_WIDTH):pygame.draw.line(screen, LINE_COLOR,(i * GRID_WIDTH, 0), (i * GRID_WIDTH, HEIGHT))for i in range(GRID_NUM_HEIGHT):pygame.draw.line(screen, LINE_COLOR,(0, i * GRID_WIDTH), (WIDTH, i * GRID_WIDTH))pygame.draw.line(screen, WHITE,(GRID_WIDTH * GRID_NUM_WIDTH, 0),(GRID_WIDTH * GRID_NUM_WIDTH, GRID_WIDTH * GRID_NUM_HEIGHT))def draw_matrix():for i, row in zip(range(GRID_NUM_HEIGHT), screen_color_matrix):for j, color in zip(range(GRID_NUM_WIDTH), row):if color is not None:pygame.draw.rect(screen, color,(j * GRID_WIDTH, i * GRID_WIDTH,GRID_WIDTH, GRID_WIDTH))pygame.draw.rect(screen, WHITE,(j * GRID_WIDTH, i * GRID_WIDTH,GRID_WIDTH, GRID_WIDTH), 2)def draw_score():show_text(screen, u'得分:{}'.format(score), 20, WIDTH + SIDE_WIDTH // 2, 100)def remove_full_line():global screen_color_matrixglobal scoreglobal levelnew_matrix = [[None] * GRID_NUM_WIDTH for i in range(GRID_NUM_HEIGHT)]index = GRID_NUM_HEIGHT - 1n_full_line = 0for i in range(GRID_NUM_HEIGHT - 1, -1, -1):is_full = Truefor j in range(GRID_NUM_WIDTH):if screen_color_matrix[i][j] is None:is_full = Falsecontinueif not is_full:new_matrix[index] = screen_color_matrix[i]index -= 1else:n_full_line += 1score += n_full_linelevel = score // 20 + 1screen_color_matrix = new_matrixdef show_welcome(screen):show_text(screen, u'俄罗斯方块', 30, WIDTH / 2, HEIGHT / 2)show_text(screen, u'按任意键开始游戏', 20, WIDTH / 2, HEIGHT / 2 + 50)running = True
gameover = True
counter = 0
live_cube = None
while running:clock.tick(FPS)for event in pygame.event.get():if event.type == pygame.QUIT:running = Falseelif event.type == pygame.KEYDOWN:if gameover:gameover = Falselive_cube = CubeShape()breakif event.key == pygame.K_LEFT:live_cube.left()elif event.key == pygame.K_RIGHT:live_cube.right()elif event.key == pygame.K_DOWN:live_cube.down()elif event.key == pygame.K_UP:live_cube.rotate()elif event.key == pygame.K_SPACE:while live_cube.down() == True:passremove_full_line()# level 是为了方便游戏的难度,level 越高 FPS // level 的值越小# 这样屏幕刷新的就越快,难度就越大if gameover is False and counter % (FPS // level) == 0:# down 表示下移骨牌,返回False表示下移不成功,可能超过了屏幕或者和之前固定的# 小方块冲突了if live_cube.down() == False:for cube in live_cube.get_all_gridpos():screen_color_matrix[cube[0]][cube[1]] = live_cube.colorlive_cube = CubeShape()if live_cube.conflict(live_cube.center):gameover = Truescore = 0live_cube = Nonescreen_color_matrix = [[None] * GRID_NUM_WIDTH for i in range(GRID_NUM_HEIGHT)]# 消除满行remove_full_line()counter += 1# 更新屏幕screen.fill(BLACK)draw_grids()draw_matrix()draw_score()if live_cube is not None:live_cube.draw()if gameover:show_welcome(screen)pygame.display.update()


http://www.ppmy.cn/news/165160.html

相关文章

客服都要下岗了? 当ChatGPT遇见私有数据,秒变AI智能客服!

用ChatGPT搭建基于私有数据的WorkPlus AI客服机器人这个想法&#xff0c;源于WorkPlus售前工作需求。在ChatGPT之前&#xff0c;其实对话式AI一直在被广泛使用在客服场景&#xff0c;只不过不大智能而已。比如你应该看到不少电商客服产品&#xff0c;就有类似的功能&#xff0c…

数据库笔记01-数据库的创建

第一步&#xff0c;右键点击新建数据库 第二步 初始大小为10MB&#xff0c;最大为50MB&#xff0c;数据库自动增长&#xff0c;增长方式按10%增长&#xff0c;日志文件初始大小为2MB&#xff0c;最大大小不受限制&#xff0c;按1MB增长。 sql语句 create database testdb01…

Android进程保活

Android中的进程保活应该分为两个方面&#xff1a; 提高进程的优先级&#xff0c;减少被系统杀死的可能性在进程已经被杀死的情况下&#xff0c;通过一些手段来重新启动应用进程 本文针对这两方面来进程阐述&#xff0c;并给出相应的示例。其实主要也是在前人的基础上做了一个…

六、创建一个基于Python的代理采集项目(04)通过代理采集

代理拿到了&#xff0c;要应用到采集上面&#xff0c;需要在requests.get()中增加一个proxies参数 为了方便以后的代码编写&#xff0c;先梳理一下代码 因为做采集&#xff0c;header要变换&#xff0c;ip要变换&#xff0c;因此这两块要独立出来&#xff0c;方便维护 有关采…

保护计算机系统与数据有什么方法,计算机系统开机和硬盘数据保护方法,与其数据保护模块...

技术领域 本发明涉及一种数据保护技术&#xff0c;且特别是涉及一种计算机系统的开机和硬盘数据保护方法&#xff0c;与其数据保护模块。 背景技术 图1示出了一种已知的具有密码保护的计算机系统的开机方法步骤流程图。请参照图1&#xff0c;已知的计算机系统开机方法&#xff…

基于移动位置服务器,基于移动位置的服务系统及方法

本申请是申请号为03148343.7、申请日为2003年6月30日、发明名称为“基于移动位置的服务系统及方法”的发明专利申请的分案申请。 技术领域 本发明涉及一种基于位置的移动台服务&#xff0c;更具体地说&#xff0c;本发明涉及一种基于移动位置的服务系统&#xff0c;该系统能根据…

计算机不等长编码有哪些,第9讲最佳不等长编码_W

《第9讲最佳不等长编码_W》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《第9讲最佳不等长编码_W(38页珍藏版)》请在人人文库网上搜索。 1、第九讲最佳不等长编码Review不等长编码定理H (U ) d n 1k ikk 1P1 0Shannon编码例1&#xff1a; 设离散无记忆信源 S s1s2s…

520 miix 小兵 黑苹果,Hackintosh黑苹果长期维护机型整理清单

## 黑苹果长期维护机型整理 引言 by @我意 整理这份清单的目的:在于给想体验黑苹果的人一个方向,也想减少大家重复造轮子,节约大家的时间。 所有文件均归属于原作者,本清单只列出链接。如果您不希望你的链接被这份清单收录,请发送邮件到 [email protected],我将移除链接 清…