python,基于tkinter模块编写的完整俄罗斯方块游戏代码

使用python编写小游戏挺容易的,常用的模块是pygame, 本文用tkinter,实现了俄罗斯方块小游戏,感觉还是比较容易的。

import tkinter as tk
import time
import random
from tkinter import messagebox
import pygame
pygame.mixer.pre_init(44100, -16, 2, 512)
pygame.mixer.init()  # 初始化混音器

# 读取最高纪录
with open('record.txt', 'r') as f:
    record = int(f.read())

# 定义游戏中的常量
R = 20  # 20行
C = 12 # 30列
cell_size = 30 #方块边长
with open('speed.txt', 'r') as f:
    FPS = int(f.readline()) # 读取刷新时间
height = R * cell_size #画布高度
width = C * cell_size #画布宽度

#定义形状的座标矩阵
SHAPES = {
    'O': [(-1, -1), (0, -1), (-1, 0), (0, 0)],
    'S': [(-1, 0), (0, 0), (0, -1), (1, -1)],
    'T': [(-1, 0), (0, 0), (0, -1), (1, 0)],
    'I': [(0, 1), (0, 0), (0, -1), (0, -2)],
    'L': [(-1, 0), (0, 0), (-1, -1), (-1, -2)],
    'J': [(-1, 0), (0, 0), (0, -1), (0, -2)],
    'Z': [(-1, -1), (0, -1), (0, 0), (1, 0)]
}
# 定义每个形状的颜色
SHAPECOLOR = {
    'O': 'blue',
    'S': 'red',
    'T': 'yellow',
    'I': 'green',
    'L': 'purple',
    'J': 'orange',
    'Z': 'Cyan'
}

# 定义函数,在画板指定的行列上画指定颜色的方格
def draw_cell_by_cr(canvas, c, r, color = '#CCCCCC'):
    #定义左上角和右下角座标
    x0 = c * cell_size
    y0 = r * cell_size
    x1 = c * cell_size + cell_size
    y1 = r * cell_size + cell_size
    canvas.create_rectangle(x0, y0, x1, y1, fill = color, outline = 'white', width = 2)

# 定义函数,画背景画布
def draw_board(canvas, block_list):
    for ri in range(R):
        for ci in range(C):
            cell_type = block_list[ri][ci]
            if cell_type:
                draw_cell_by_cr(canvas, ci, ri, SHAPECOLOR[cell_type])
            else:
                draw_cell_by_cr(canvas, ci, ri)

# 定义在指定的行列,绘制指定颜色的图形
def draw_cell(canvas, c, r, cell_list, color = '#cccccc'):
    for cell in cell_list:
        cell_c, cell_r = cell
        ci = cell_c + c # 实际列座标
        ri = cell_r + r # 实际行座标
        if 0 <= c < C and 0 <= r < R:
            draw_cell_by_cr(canvas, ci, ri, color) # 画出一个方格






win = tk.Tk()
canvas = tk.Canvas(win, width = width, height = height) #定义画布控件
win.geometry('+800+10')
canvas.pack()
# draw_blank_board(canvas)



# draw_cell(canvas, 3, 3, SHAPES['O'], SHAPECOLOR['O'])
# draw_cell(canvas, 3, 8, SHAPES['S'], SHAPECOLOR['S'])
# draw_cell(canvas, 3, 13, SHAPES['T'], SHAPECOLOR['T'])
# draw_cell(canvas, 8, 3, SHAPES['I'], SHAPECOLOR['I'])
# draw_cell(canvas, 8, 8, SHAPES['L'], SHAPECOLOR['L'])
# draw_cell(canvas, 8, 13, SHAPES['J'], SHAPECOLOR['J'])
# draw_cell(canvas, 5, 18, SHAPES['Z'], SHAPECOLOR['Z'])


block_list = [] # 定义记录已经生成的方块的列表
for i in range(R):
    i_row = ['' for i in range(C)]
    block_list.append(i_row) # 生成由空字符串组成的R行C列的列表

draw_board(canvas, block_list)
# 定义移动方块函数
def draw_block_move(canvas, block, direction = [0, 0]):
    '''
    :param:
    :param canvas: 画布
    :param block:  方块对象
    :param direction: 移动方向
    :return:
    '''
    shape_type = block['kind']
    c, r = block['cr']
    cell_list = block['cell_list']
    draw_cell(canvas, c, r, cell_list) # 擦除旧位置的形状
    dc, dr = direction
    new_c, new_r = c + dc, r + dr
    block['cr'] = [new_c, new_r]
    draw_cell(canvas, new_c, new_r, cell_list, SHAPECOLOR[shape_type]) # 绘制新位置的形状

# draw_block_move(canvas, a_block)
# 定义一个随机生成形状的函数
def generate_new_block():
    kind = random.choice(list(SHAPES.keys()))
    cr = [C // 2, 0]
    new_block = {
        'kind': kind,
        'cell_list': SHAPES[kind],
        'cr': cr
    }
    return(new_block)

# 定义检测方块是否移动到最底部的函数
def check_move(block, direction = [0, 0]):
    cc, cr = block['cr'] # 定义当前的行列座标
    cell_list = block['cell_list']
    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc + direction[0]
        r = cell_r + cr + direction[1]
        if c < 0 or c >= C or r >= R:
            return False
        if r >= 0 and block_list[r][c]:
            return False
    return True

# 定义一个存储已生成方块列表的函数
def save_to_block_list(block):
    shape_type = block['kind']
    cc, cr = block['cr']
    cell_list = block['cell_list']
    for cell in cell_list:
        cell_c, cell_r = cell
        c = cell_c + cc
        r = cell_r + cr
        block_list[r][c] = shape_type

def horizontal_move_block(event):
    '''
    :左右移动方块
    :param event: 键鼠标事件
    :return:
    '''
    direction = [0, 0] #默认方向为不动
    if event.keysym == 'Left':
        direction = [-1, 0]
    elif event.keysym == 'Right':
        direction = [1, 0]
    else:
        return
    global current_block
    if current_block is not None and check_move(current_block, direction):
        draw_block_move(canvas, current_block, direction)

# 定义旋转方块函数
def rotate_block(event):
    global current_block
    if current_block is None:
        return
    cell_list = current_block['cell_list']
    rotate_list = []
    for cell in cell_list:
        cell_c, cell_r = cell
        rotate_cell = [cell_r, -cell_c]
        rotate_list.append(rotate_cell)

    block_after_rotate = {
        'kind': current_block['kind'],
        'cell_list': rotate_list,
        'cr': current_block['cr']
    }
    if check_move(block_after_rotate):
        cc, cr = current_block['cr']
        draw_cell(canvas, cc, cr, current_block['cell_list'])
        draw_cell(canvas, cc, cr, rotate_list, SHAPECOLOR[current_block['kind']])
        current_block = block_after_rotate

# 定义一个按向下键直接着陆的函数
def land(event):
    global current_block
    if current_block is None:
        return
    cell_list = current_block['cell_list']
    cc, cr = current_block['cr']
    min_height = R
    for cell in cell_list:
        cell_c, cell_r = cell
        c, r = cell_c + cc, cell_r + cr
        if block_list[r][c]:
            return
        h = 0
        for ri in range(r + 1, R):
            if block_list[ri][c]:
                break
            else:
                h += 1
        if h < min_height:
            min_height = h
    down = [0, min_height]
    if check_move(current_block, down):
        draw_block_move(canvas, current_block, down)
        # wave_down.play()

    # 定义保存得分的变量
score = 0
win.title('To lotus! Scores:%s  The record is %s' % (score, record))

# 定义函数判断指定行是否已经满了
def check_row_complete(row):
    for cell in row:
        if cell == '':
            return False
    return True

# 定义函数检查是否满了,同时清除满行方块
def check_and_clear():
    has_complete_row = False
    for ri in range(len(block_list)):
        if check_row_complete(block_list[ri]):
            has_complete_row = True
            if ri > 0:
                for cur_ri in range(ri, 0, -1):
                    block_list[cur_ri] = block_list[cur_ri -1][:]
                block_list[0] = ['' for i in range(C)]
            else:
                block_list[ri] = ['' for i in range(C)]
            global score
            score += 10
    if has_complete_row:
        remove.play()
        draw_board(canvas, block_list)
        win.title('To lotus! Scores:%s  The record is %s' % (score, record))


# 定义定时刷新函数
def game_loop():
    win.update()
    global current_block
    if current_block == None:
        new_block = generate_new_block()
        draw_block_move(canvas, new_block) # 绘制形状(未输入direction,在new_block点绘制,不移动)
        current_block = new_block
        if not check_move(current_block):
            game_over.play()
            if score >= record:
                messagebox.showinfo('Game Over!', '宝贝,我爱你!Your score is %s! Congratulations on setting a new record!' % score)
                with open('record.txt', 'w') as f:
                    f.write(str(score))
            else:
                messagebox.showinfo('Game Over!', 'Your score is %s!' % score)
            win.destroy()
            return
    else:
        if check_move(current_block, [0, 1]):
            draw_block_move(canvas, current_block, [0, 1])
        else:
            save_to_block_list(current_block)
            current_block = None
            wave_down.play()


    check_and_clear()
    win.after(FPS, game_loop)

current_block = None
canvas.focus_set() # 聚焦到画板对象
canvas.bind('<KeyPress-Left>', horizontal_move_block)
canvas.bind('<KeyPress-Right>', horizontal_move_block)
canvas.bind('<KeyPress-Up>', rotate_block)
canvas.bind('<KeyPress-Down>', land)


game_loop()
pygame.mixer.pre_init(44100, -16, 2, 512)
pygame.mixer.init()  # 初始化混音器
#加载音乐文件
# mp3_backGround = pygame.mixer.music.load("background.mp3")
background = pygame.mixer.Sound('background.wav')
#加载wave文件
wave_down =   pygame.mixer.Sound("down.wav")
remove =   pygame.mixer.Sound("remove.wav")
game_over =   pygame.mixer.Sound("gameover.wav")
#设置背景音乐的音量
# pygame.mixer.music.set_volume(Config.bgMusicVolume)
#播放背景音乐,参数-1表示循环播放
background.play(-1)

win.mainloop()

  

 

posted @ 2020-06-11 17:06  Iceberg_710815  阅读(1932)  评论(0编辑  收藏  举报