2020-11-08 Windows应用程序设计作业(Python版实现)(三)模仿应用程序界面 - 俄罗斯方块游戏

Windows应用程序设计作业(Python版实现)

作业3-模仿应用程序界面 - 俄罗斯方块游戏
设计一个俄罗斯方块的游戏界面,要求有菜单,选项设置对话框,操控界面,能控制方块的左右和向下移动。
先来个测试视频:
https://www.bilibili.com/video/BV1Vt4y1e7ej/

代码参考教程:
https://www.bilibili.com/video/BV1eJ411h7ZV?from=search&seid=6903931124819368025

代码封装设计结构如下:
在这里插入图片描述
(一)main.py

from tetris_bg_show import Background_show
from tetris_initialize import Tetris_init
import tkinter as tk

win = tk.Tk()
tetris = Tetris_init(win, 20, 12, 30, 400)   # R,C,cell_size,FPS
bk_canvas = Background_show(win, tetris)
bk_canvas.BK_canvas()
win.mainloop()

(二)tetris_bg_show.py

import tkinter as tk
from tetris_initialize import Status
from tetris_initialize import Tetris_init
from tetris_shape import Tetris_shape
from tetris_fg_show import Tetrominoe
from PIL import ImageTk,Image
import tkinter.font as tkFont

class Background_show:

    def __init__(self, win, tetris):
        self.win = win
        self.tetris = tetris
        self.R, self.C, self.cell_size = tetris.R, tetris.C, tetris.cell_size
        self.height, self.width = tetris.height, tetris.width
        self.bk_canvas = tk.Canvas(self.win, width = self.width, height = self.height)

    def on_click(self):
        self.value = self.iv_style.get()   
        if self.value != 0:
            if self.value == 1:         
                Status.FPS = 800           
            elif self.value == 2:          
                Status.FPS = 500
            else:                          
                Status.FPS = 200          
            self.bk_canvas.delete("all") 
            root = self.win  
            self.tetris.__init__(root, self.R, self.C, self.cell_size, Status.FPS, True) 
            self.bk_canvas.pack_forget()
            tetrominoe = Tetrominoe(root, self.tetris)   
            tetrominoe.NW_canvas(root)        
            
    def BK_canvas(self):
        self.im = ImageTk.PhotoImage(Image.open(r'F:\2020_C#_assignments\background.gif'))
        self.bk_canvas.create_image(0, 0, anchor='nw', image = self.im)
        self.iv_style = tk.IntVar()                                          
        ft1 = tkFont.Font(family='微软雅黑', size=15, weight=tkFont.BOLD)      
        self.bk_canvas.create_window(180, 260, width = 100, height = 40, window = tk.Radiobutton(self.win, text = '初级难度', font = ft1, foreground = "FireBrick", relief = "raised", value = 1, variable = self.iv_style, indicatoron = 0))
        self.bk_canvas.create_window(180, 310, width = 100, height = 40, window = tk.Radiobutton(self.win, text = '中级难度', font = ft1, foreground = "FireBrick", relief = "raised", value = 2, variable = self.iv_style, indicatoron = 0))
        self.bk_canvas.create_window(180, 360, width = 100, height = 40, window = tk.Radiobutton(self.win, text = '高级难度', font = ft1, foreground = "FireBrick", relief = "raised", value = 3, variable = self.iv_style, indicatoron = 0))
        self.bk_canvas.create_window(180, 450, width=140, height=60, window=tk.Button(self.win, text = "开启游戏之旅", font = ft1, command = self.on_click))
        self.bk_canvas.pack()    

(三)tetris_fg_show.py

import tkinter as tk
from tetris_initialize import Status
from tetris_initialize import Tetris_init
from tetris_shape import Tetris_shape
from tetris_operation import Tetris_op

class Text:
    NEXT = 'NEXT SHAPE'
    SCOR = 'SCORES'
    ZERO = '0'
    FST1 = ('Helvetica', 20, 'bold')
    FST2 = ('Helvetica', 80, 'bold')

    SCOLOR = {
        'D':'DarkCyan',
        'P':'pink',
        'T':'tan',
        'G':'gold',
        'R':'RosyBrown'
    }

class Tetrominoe:

    def __init__(self, win, tetris):
        self.win = win
        self.tetris = tetris
        self.R, self.C, self.cs = tetris.R, tetris.C, tetris.cell_size
        self.h, self.w = tetris.height, tetris.width
        self.nw_canvas = tk.Canvas(win, width = self.w, height = self.h)
        self.tetris_op = Tetris_op(self.tetris, self.nw_canvas)
        Status.mouse_click = 1 
        for i in range(self.R):
            i_row = ['' for j in range(self.C)]
            Status.block_list.append(i_row)
    
    def NW_canvas(self, win):
        self.tetris_op.draw_board(self.nw_canvas)                    
        self.nw_canvas.focus_set()                
        self.nw_canvas.bind_all('<KeyPress>', self.event_move)
        ca, cb = 0, 45
        cc, cd, ce = self.cs * 3, self.cs * 9, self.cs * 11
        cf, cg, cw, ch = self.cs * 12 + 3, self.cs * 15, self.w, self.h 
        self.nw_canvas.create_rectangle((cf, ca, cw, cc), width = 4, fill = Text.SCOLOR['P'], outline = Text.SCOLOR['T'], stipple = 'gray25')
        self.nw_canvas.create_rectangle((cf, cd, cw, ch), width = 4, fill = Text.SCOLOR['P'], outline = Text.SCOLOR['T'], stipple = 'gray25')
        self.nw_canvas.create_rectangle((cf, cc + 4, cw , cd - 4), width = 4, outline = Text.SCOLOR['G'], dash = (1,1))  
        self.nw_canvas.create_text((cg, cg), text = Text.ZERO, font = Text.FST2, fill = Text.SCOLOR['D'], tag = 'SCORE')  
        self.nw_canvas.create_text((cg, cb), text = Text.NEXT, font = Text.FST1, fill = Text.SCOLOR['R'])   
        self.nw_canvas.create_text((cg, ce), text = Text.SCOR, font = Text.FST1, fill = Text.SCOLOR['R']) 
        win.after(Status.FPS, self.tetris_op.game_loop)       
        self.nw_canvas.pack()  
        
    def event_move(self, event):
        direction = [0, 0]
        if event.keysym == 'Left':
            direction = [-1, 0]              
        elif event.keysym == 'Right':
            direction = [1, 0]  
        elif event.keysym == 'Up':
            self.event_rotata('Up')   
        elif event.keysym == 'Down':
            if Status.current_block is None:
                return 
            cell_list = Status.current_block['cell_list']
            cc, cr = Status.current_block['cr']
            min_height = self.R
            for cell in cell_list:
                height = 0 
                cell_c, cell_r = cell 
                c, r = cell_c + cc, cell_r + cr
                if r >= 0 and Status.block_list[r][c]:  
                    return     
                for ri in range(r + 1, self.R):
                    if Status.block_list[ri][c]:  
                        break
                    else:  
                        height += 1
                if height < min_height:  
                    min_height = height
            direction = [0, min_height]
        if Status.current_block is not None and self.tetris_op.check_move(Status.current_block, direction):
            self.tetris_op.draw_block_move(self.nw_canvas, Status.current_block, direction)

    def event_rotata(self, event):
        if Status.current_block is None:
            return 
        cell_list = Status.current_block['cell_list']
        rorate_list = []
        for cell in cell_list:
            cell_c, cell_r = cell
            rorate_cell = [cell_r, -cell_c]
            rorate_list.append(rorate_cell)
        block_after_rotate = {
            'kind': Status.current_block['kind'],
            'cell_list': rorate_list,
            'cr': Status.current_block['cr']
        }
        if self.tetris_op.check_move(block_after_rotate):
            cc, cr =  Status.current_block['cr']
            self.tetris_op.draw_cells(self.nw_canvas, cc, cr, Status.current_block['cell_list'])
            self.tetris_op.draw_cells(self.nw_canvas, cc, cr, rorate_list, Tetris_shape.SHAPESCOLOR[Status.current_block['kind']])
            Status.current_block = block_after_rotate

(四)tetris_initialize.py

from tetris_shape import Tetris_shape

class Status:
    current_block = None  
    next_block = None
    next_block_pre = None  
    block_list = []
    mouse_click = 1
    flag_clear = False
    score = 0
    FPS = 0

class Tetris_init:

    def __init__(self, win, R, C, cell_size, FPS, show = False):
        self.win = win
        Status.FPS = FPS
        self.R, self.C = R, C
        self.cell_size = cell_size
        self.height, self.width = self.R * self.cell_size, self.C * self.cell_size
        self.screenwidth, self.screenheight = self.win.winfo_screenwidth(), self.win.winfo_screenheight() 
        if show is True:
            self.width = self.width + self.cell_size * 6 
        self.win.geometry("%dx%d+%d+%d" % (self.width, self.height, (self.screenwidth - self.width) / 2, (self.screenheight - self.height) / 2))    
        self.win.title("Welcom to Tetris~")

(五)tetris_operation.py

import tkinter as tk
import tkinter.messagebox
from tetris_initialize import Status
from tetris_initialize import Tetris_init
from tetris_shape import Tetris_shape
import pyautogui 
import random

class Tetris_op:

    def __init__(self, tetris, nw_canvas):
        self.tetris = tetris
        self.nw_canvas = nw_canvas
        self.R, self.C, self.cell_size = tetris.R, tetris.C, tetris.cell_size
        self.height, self.width = tetris.R * tetris.cell_size, tetris.C * tetris.cell_size
        self.screenwidth, self.screenheight = tetris.win.winfo_screenwidth(), tetris.win.winfo_screenheight() 

    def draw_cell_by_cr(self, canvas, c, r, color="lightgray"):
        x0 = c * self.cell_size                   
        y0 = r * self.cell_size  
        x1 = c * self.cell_size  + self.cell_size 
        y1 = r * self.cell_size + self.cell_size
        canvas.create_rectangle(x0, y0, x1, y1, fill = color, outline = "white", width = 2)     

    def draw_board(self, canvas):
        for ri in range(self.R):
            for ci in range(self.C):
                cell_type = Status.block_list[ri][ci]
                if cell_type:
                    self.draw_cell_by_cr(canvas, ci, ri, Tetris_shape.SHAPESCOLOR[cell_type])
                else:
                    self.draw_cell_by_cr(canvas, ci, ri)  
        for ri in range(3, 9):
            for ci in range(12, 18):
                self.draw_cell_by_cr(canvas, ci, ri, color = "white")     

    def draw_cells(self, canvas, c, r, cell_list, color = "lightgray", show = False):
        for cell in cell_list:
            cell_c, cell_r = cell
            ci = cell_c + c
            ri = cell_r + r
            if 0 <= c < self.C and 0 <= r < self.R :              
                self.draw_cell_by_cr(canvas, ci, ri, color)
            if show is True:
                self.draw_cell_by_cr(canvas, ci, ri, color) 

    def draw_block_move(self, canvas, block, direction = [0, 0]):
        shape_type = block['kind']              
        cell_list = block['cell_list']            
        c, r = block['cr']                         
        self.draw_cells(canvas, c, r, cell_list)   
        dc, dr = direction  
        new_c, new_r = c + dc, r + dr
        block['cr'] = [new_c, new_r]          
        self.draw_cells(canvas, new_c, new_r, cell_list, Tetris_shape.SHAPESCOLOR[shape_type])    

    def generate_new_block(self):        
        cr = [self.C//2, 0]     
        new_block = {
            'kind': Status.next_block['kind'],                        
            'cell_list': Status.next_block['cell_list'],        
            'cr': cr                               
        }
        if Status.flag_clear is True:
            pre_shape_type = Status.next_block['kind']
            pre_cell_list = Status.next_block['cell_list']
            pre_c, pre_r = Status.next_block['cr']
            for cell in pre_cell_list:
                cell_c, cell_r = cell
                ci = cell_c + pre_c
                ri = cell_r + pre_r
                x0 = ci * self.cell_size                   
                y0 = ri * self.cell_size  
                x1 = ci * self.cell_size  + self.cell_size 
                y1 = ri * self.cell_size + self.cell_size
                self.nw_canvas.create_rectangle(x0, y0, x1, y1, fill = "white", outline = "white", width = 2) 
            Status.flag_clear = False
        Status.next_block = self.generate_next_block()
        self.draw_next_block(self.nw_canvas, Status.next_block, Status.next_block_pre)
        return new_block
        
    def generate_next_block(self):
        kind = random.choice(list(Tetris_shape.SHAPES.keys()))
        next_cr = [15, 6]
        next_tetris_block = {
            'kind': kind,
            'cell_list': Tetris_shape.SHAPES[kind],
            'cr': next_cr
        }
        return next_tetris_block

    def draw_next_block(self, canvas, block, block_pre):
        shape_type = block['kind']                
        cell_list = block['cell_list']            
        c, r = block['cr']    
        for cell in cell_list:
            cell_c, cell_r = cell
            ci = cell_c + c
            ri = cell_r + r
            x0 = ci * self.cell_size                  
            y0 = ri * self.cell_size  
            x1 = ci * self.cell_size  + self.cell_size 
            y1 = ri * self.cell_size + self.cell_size
            canvas.create_rectangle(x0, y0, x1, y1, fill = Tetris_shape.SHAPESCOLOR[shape_type], outline = "white", width = 2) 

    def check_move(self, 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 >= self.C or r >= self.R:
                return False
            if r >= 0 and Status.block_list[r][c]:
                return False
        return True

    def save_block_to_list(self, block):
        shape_type = block['kind']
        cell_list = block['cell_list']
        cc, cr = block['cr']
        for cell in cell_list:
            cell_c, cell_r = cell
            c = cell_c + cc
            r = cell_r + cr
            Status.block_list[r][c] = shape_type
    
    def check_row_complete(self, row):
        for cell in row:
            if cell == '':
                return False
        return True

    def check_and_clear(self):
        has_complete_row = False
        for ri in range(len(Status.block_list)):
            if self.check_row_complete(Status.block_list[ri]):
                has_complete_row = True
                if ri > 0:
                    for cur_ri in range(ri, 0, -1):
                        Status.block_list[cur_ri] = Status.block_list[cur_ri - 1][:]
                    Status.block_list[0] = ['' for j in range(self.C)]
                else: 
                    Status.block_list[ri] = ['' for j in range(self.C)]
                Status.score += 10   
        if has_complete_row:
            self.draw_board(self.nw_canvas)
            self.nw_canvas.delete('SCORE')
            score_str = str(Status.score)
            self.nw_canvas.create_text((15 * self.cell_size, 3 * (self.height / 4) ), text = score_str, font = ('Helvetica', 80, 'bold'), fill = 'DarkCyan', tag = 'SCORE')  

    def game_loop(self):
        if Status.mouse_click == 1:
            x, y = (self.screenwidth - self.width)/2 + 100 , (self.screenheight - self.height)/2 + 100
            pyautogui.moveTo(x, y)        
            pyautogui.click()             
            Status.mouse_click += 1
            Status.next_block_pre = self.generate_next_block()   
            Status.next_block = Status.next_block_pre
        if Status.current_block is None:
            Status.new_block = self.generate_new_block()
            self.draw_block_move(self.nw_canvas, Status.new_block)      
            Status.current_block = Status.new_block
            if not self.check_move(Status.current_block, [0, 0]):
                tk.messagebox.showinfo("Game Over!","Your Score is %s " % Status.score)
                self.tetris.win.destroy()                         
                return                       
        else:
            if self.check_move(Status.current_block, [0, 1]):              
                self.draw_block_move(self.nw_canvas, Status.current_block, [0, 1]) 
            else:     
                self.save_block_to_list(Status.current_block)            
                Status.flag_clear = True                                   
                Status.current_block = None                               
        self.check_and_clear()                                         
        self.tetris.win.after(Status.FPS, self.game_loop)

(六)tetris_shape.py

class Tetris_shape:

    SHAPES = {
        "I": [(0, 1), (0, 0), (0, -1), (0, -2)],
        "J": [(-1, 0), (0, 0), (0, -1), (0, -2)],
        "L": [(-1, 0), (0, 0), (-1, -1), (-1, -2)],
        "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)],
        "Z": [(-1, -1), (0, -1), (0, 0), (1, 0)],
    }
    SHAPESCOLOR = {
        "I": "darksalmon",
        "J": "sandybrown",
        "L": "darkkhaki",
        "O": "darkseagreen",
        "S": "mediumpurple",
        "T": "cornflowerblue",
        "Z": "palevioletred",
    }

那写看似毫无波澜的日复一日,会在某一天 让你突然发现努力的意义。
无悔昨天 & 感谢今天 & 喜欢明天~

一以贯之的努力,不得懈怠的人生。每天的微小积累,会决定最终的结果,这 就是答案!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值