猫史档案馆


【Python作品分享】tetris

用户:何星雨666何星雨666查看:0 回复:1 评论:0 创建时间:2023-01-31T21:40:27


【作品展示】

center_image

 

【作品介绍】

简单的俄罗斯方块

 

【作品源代码】

import pygame  # 导入游戏开发库
from copy import deepcopy  # 导入深复制 默认对象复制是浅复制 只是复制了引用 并不是复制对象的所有属性和方法
from random import choice, randrange  # 导入随机选择 和 随机范围函数

W, H = 10, 20  # 把游戏窗口划分成20行 10列的区域fast
TILE = 30  # 每个正方形小方块都是30个像素 ,那么横向10X30=300 纵向就是20*30=600
GAME_RES = W * TILE, H * TILE  # 300, 600 左边的积木游戏窗口大小
RES = 600, 喵0  # 整个游戏的窗口大小 包括右边 得分显示  下一个积木显示等
FPS = 60  # 每秒窗口刷新率 也叫为帧率

pygame.init()  # 初始化游戏库函数
sc = pygame.display.set_mode(RES)  # 创建主游戏窗口
pygame.display.set_caption("俄罗斯方块")  # 窗口标题
game_sc = pygame.Surface(GAME_RES)  # 创建左边的游戏窗口
clock = pygame.time.Clock()  # 创建时钟chen
# 准备背景上的格子,每格30*30大小 共20行X10列 个块  [20个列表元素[10个RECT元素]] 列表嵌套  远的是内循环 近的是外循环
grid = [pygame.Rect(x * TILE, y * TILE, TILE, TILE)
        for x in range(W) for y in range(H)]


figures_pos = [[(-1, 0), (-2, 0), (0, 0), (1, 0)],
               [(0, -1), (-1, -1), (-1, 0), (0, 0)],
               [(-1, 0), (-1, 1), (0, 0), (0, -1)],
               [(0, 0), (-1, 0), (0, 1), (-1, -1)],
               [(0, 0), (0, -1), (0, 1), (-1, -1)],
               [(0, 0), (0, -1), (0, 1), (1, -1)],
               [(0, 0), (0, -1), (0, 1), (-1, 0)]]
#把方块初始化放到 10X20划分的屏幕中去  w//2  10整除以2 就是游戏窗口正中间位置
figures = [[pygame.Rect(x + W // 2, y + 1, 1, 1)
            for x, y in fig_pos] for fig_pos in figures_pos]

# 生成一个小方格 缩小两个像素 Rect对象可以理解为有位置有大小的矩形
figure_rect = pygame.Rect(0, 0, TILE - 2, TILE - 2)
# 生成一个20个元素的列表,每个元素列表有10个子元素 初始为0,用于指示此区域有没有方块
field = [[0 for i in range(W)] for j in range(H)]

anim_count, anim_speed, anim_limit = 0, 60, 2000
bg = pygame.image.load('img/bg.jpg').convert()  # 加载背景图片
game_bg = pygame.image.load('img/bg2.jpg').convert()  # 加载背景图片2
main_font = pygame.font.Font('font/font.ttf', 45)  # 加载字体
font = pygame.font.SysFont('SimHei', 30)  # 设置系统字体黑体
title_tetris = main_font.render('TETRIS', True, pygame.Color('darkorange'))
title_score = font.render('得分:', True, pygame.Color('green'))
title_record = font.render('记录:', True, pygame.Color('purple'))


def get_color():  # 产生一个随机的颜色
    return randrange(30, 256), randrange(30, 256), randrange(30, 256)


figure, next_figure = deepcopy(choice(figures)), deepcopy(
    choice(figures))  # 随机抽取两种积木 一个是当前的,一个是下一次要显示的
color, next_color = get_color(), get_color()
score, lines = 0, 0
# 消一行 100分 2行 300分 3 行700分 4行1500分
scores = {0: 0, 1: 100, 2: 300, 3: 700, 4: 1500}


def check_borders():  # 碰撞测试 False就是碰到 True就是没有碰到
    if figure[i].x < 0 or figure[i].x > W - 1:
        return False
    elif figure[i].y > H - 1 or field[figure[i].y][figure[i].x]:
        return False
    return True


def get_record():  # 读取记录文件,如果没有记录文件record新建一个 并把记录更新成0
    try:
        with open('record') as f:
            return f.readline()
    except FileNotFoundError:
        with open('record', 'w') as f:
            f.write('0')


def set_record(record, score):
    rec = max(int(record), score)
    with open('record', 'w') as f:
        f.write(str(rec))


"""
主循环 
"""
while True:
    record = get_record()
    dx, rotate = 0, False  # rotate 按下键盘的上键 表示需要旋转积木
    sc.blit(bg, (0, 0))
    sc.blit(game_sc, (20, 20))
    game_sc.blit(game_bg, (0, 0))
    # 消除时画面停顿300毫秒
    for i in range(lines):
        pygame.time.wait(300)
    # 读取事件 并处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()
        #按键事件处理
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                dx = -1
            elif event.key == pygame.K_RIGHT:
                dx = 1
            elif event.key == pygame.K_DOWN:
                anim_limit = 100
            elif event.key == pygame.K_UP:
                rotate = True
    # 横向移动
    figure_old = deepcopy(figure)
    for i in range(4):  # 每个积木有四个小方格 横向移动就是操作每个小方格的横坐标
        figure[i].x += dx
        if not check_borders():  # 如果移动后碰壁 就还原
            figure = deepcopy(figure_old)
            break
    # 纵向移动
    anim_count += anim_speed
    if anim_count > anim_limit:
        anim_count = 0
        figure_old = deepcopy(figure)
        for i in range(4):
            figure[i].y += 1  # 把这个积木的所有方格向下移动一格
            if not check_borders():
                for s in range(4):
                    field[figure_old[s].y][figure_old[s].x] = color
                figure, color = next_figure, next_color
                next_figure, next_color = deepcopy(
                    choice(figures)), get_color()
                anim_limit = 2000
                break
    # 顺时针旋转积木  以中心块为基准,把要处理的方块坐标减去中心块坐标 得到相对位移,并把横向位移 转成上下位移,通过左边转上边 右边转下边 上边转右边 下边转左边 来实现顺时针旋转
    center = figure[0]
    figure_old = deepcopy(figure)
    if rotate:
        # 以中心块为中心实现顺时针旋转
        for i in range(4):
            x = figure[i].y - center.y  # 纵坐标相减 负数在中心块的上面 正数在中心块的下面
            y = figure[i].x - center.x  # 横坐标相减 负数在中心块的左 正数在中块的右
            figure[i].x = center.x - x   # 中心块的横坐标 减掉 纵坐标相对值 作为旋转后的横坐标
            figure[i].y = center.y + y   # 中心块的纵坐标 加上 横坐标的相对值 作为旋转后的纵坐标
            if not check_borders():
                figure = deepcopy(figure_old)
                break
    # check lines 检测是否有消掉一行
    line, lines = H - 1, 0
    for row in range(H - 1, -1, -1):  # 从最下面一行开始循环
        count = 0
        for i in range(W):  # 循环每一列 如果此列有积木了 累加1  如果count小于10列 就判断上一行 否则 消掉行数加1
            if field[row][i]:
                count += 1
            field[line][i] = field[row][i]  # 如果有一行消掉 上面一行就复制给下面一行
        if count < W:  # 如果这一行没有满 不能消
            line -= 1
        else:
            anim_speed += 3  # 每消掉一行 速度加3
            lines += 1
    # 累加得分 消掉不同的行数 得分不一样
    score += scores[lines]
    # 画格子线
    [pygame.draw.rect(game_sc, (40, 40, 40), i_rect, 1) for i_rect in grid]
    # draw figure 画积木
    for i in range(4):
        figure_rect.x = figure[i].x * TILE
        figure_rect.y = figure[i].y * TILE
        pygame.draw.rect(game_sc, color, figure_rect)
    # draw field 绘制已经落底的积木,枚举每个10X20的格子 取出相应的方块 重绘,为了区分已经落底 颜色 改成(200,200,200)
    for y, raw in enumerate(field):
        for x, col in enumerate(raw):
            if col:
                figure_rect.x, figure_rect.y = x * TILE, y * TILE
                pygame.draw.rect(game_sc, (200, 200, 200), figure_rect)
    # 画下一个积木
    for i in range(4):
        figure_rect.x = next_figure[i].x * TILE + 300
        figure_rect.y = next_figure[i].y * TILE + 185
        pygame.draw.rect(sc, next_color, figure_rect)
    # draw titles
    sc.blit(title_tetris, (380, -10))
    sc.blit(title_score, (425, 400))
    sc.blit(font.render(str(score), True, pygame.Color('white')), (450, 450))
    sc.blit(title_record, (425, 500))
    sc.blit(font.render(record, True, pygame.Color('gold')), (450, 550))
    # 游戏结束处理
    for i in range(W):  # 循环每一列
        if field[0][i]:  # 如果第一行的出现方块 就判定游戏结束
            set_record(record, score)  # 保存当前得分
            field = [[0 for i in range(W)]
                     for i in range(H)]  # 重新初始化10X20的方格为0 清空
            anim_count, anim_speed, anim_limit = 0, 60, 2000
            score = 0
            for i_rect in grid:
                pygame.draw.rect(game_sc, get_color(), i_rect)
                sc.blit(game_sc, (20, 20))
                pygame.display.flip()
                clock.tick(200)

    pygame.display.flip()  # 更新整个游戏窗口
    clock.tick(FPS)

 

【提示】

部分含有Python第三方库相关内容的作品,在海龟编辑器网页端无法运行哦!如遇到这种情况,可以打开下面的链接,下载海龟编辑器客户端:

https://python.codemao.cn


回复

上一页1 页 / 共 1下一页
暗藏玄鸡暗藏玄鸡

这个程序所涉及到的图片,别人的电脑没有‘img/bg.jpg’等这些图片,所以除了自己的电脑,其他的就运行不了了。emotion_编程猫_翻白眼

点赞0


评论