俄罗斯方块之一——构建游戏区域

我们知道俄罗斯方块是由四个小格组成,结合动画的原理,其实就是将小格子按照需求一副静态图片一副静态图片的展示。那么,四格拼板的游戏区域可以定制成由小格子组成的网格图,然后控制小格子的显示就能达到需求。
构建四格拼版游戏区域是俄罗斯方块中及其重要的一步,只有理解了这一步,才能理解俄罗斯方块游戏的真谛。

1、绘制窗体

if __name__ == "__main__":
    pygame.init()  # 使用 pygame 之前先进行初始化
    screen = pygame.display.set_mode((800, 600), 0, 32)
    # 上面一行代码的功能为设置屏幕大小,此实例为 800*600,
    # 第二个参数是 0,表示打开一个不可改变大小的窗口,
    # 第三个参数是 32 位真彩色。
    pygame.display.set_caption("俄罗斯方块") # 设置窗体名称

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: # 检测退出动作
                exit()

        pygame.display.update()

利用以上代码,可以创建一个 800*600 的窗体,如果觉得默认的背景颜色不符合自己的期望,可以在 while True: 代码的下一行添加 screen.fill(( 30, 25, 25))

2、绘制小方格

俄罗斯游戏中的四格拼板是有四个小方格组成,那么我首先要做的就是在窗体中绘制小方格。小方格该如何绘制呢?我们可以利用 pygame.Rect 类,Rect 是用于存储矩形坐标的 Pygame 对象。语法如下:

Rect(left, top, width, height) -> Rect

Rect((left, top), (width, height)) -> Rect

Rect(object) -> Rect

其中,参数 left 代表的是窗体左上角横向距离到小方格左上角的像素单位,top 代表的是窗体左上角竖向距离到小方格左上角的像素单位,width 代表的是矩形的宽度,height 代表的是矩形的高度。

我们利用函数来定义一个小方格:

def box(x:"x表示在窗体内的横坐标", y:"y表示在窗体内的纵坐标"):
    ''' 功能:画出用于组成图形的单个正方形
    '''
    rect = pygame.Rect(x, y, 20, 20)
    pygame.Surface.fill(screen, (255, 245,  40), rect) # 填充方格内的颜色
    pygame.draw.rect(screen, (255, 245, 245), rect, 1)  # 画出方格的线条
    return rect

然后在窗体的代码的 while True: 循环结构体内部添加 box(50, 50) 函数即可呈现出小方格。如下图:

小方格

3、绘制游戏区域

还是利用 pygame.Rect 类来绘制一个矩形的活动区域,活动区域的大小是宽度为 360,高度为 540。

def area():
    ''' 功能:画出游戏区域
    '''
    rect = pygame.Rect(((800-360)//4, 600-540), (360, 540))
    pygame.draw.rect(screen, ( 20,  20, 175), rect, 5)          # 画出游戏区域

然后在窗体的代码的 while True: 循环结构体内部添加 area 函数即可呈现出小方格。如下图:

活动区域

4、绘制游戏区域网格

小方格是在游戏区域内移动,那么为了确定小方格的呈现位置,可以将游戏区域分解成 N 个小方格。结合 pygame.Rect 类的使用方法,我们需要知道每个小方格的左上角的坐标。而将游戏区域分解就是要将每个小方格的坐标组合成一个二维数组

        ------------------------------------------------------------>
        |
        |    **********************************************
        |    *(0, 0) (0, 1) (0, 2) ............... (0, y) *
        |    *(1, 0) (1, 1) (1, 2) ............... (1, y) *
        |    *(2, 0) (2, 1) (2, 2) ............... (2, y) *
        |    * .......................................... *
        |    * .......................................... *
        |    * .......................................... *
        |    * .......................................... *
        |    * .......................................... *
        |    * .......................................... *
        |    * .......................................... *
        |    * .......................................... *
        |    *(x, 0) (x, 1) (x, 2) ............... (x, y) *
        |
        |

可以利用 Python 列表推导的特性,来对代码进行优化,代码如下:

def matrix():
    ''' 功能:以游戏区域为基础,画出用于呈现方块图形左上角坐标的矩阵。
    '''
    # 下面一行列表推导的代码用于构造小方格左上角坐标的二维列表
    box_coordinate_list = [[((coordinate[0] + x*edge + 2),
                            (coordinate[1] + y*edge + 2))
                            for x in range(box_col)] for y in range(box_row)]

    # 以下代码是画出游戏区域的网格,网格线是白色,网格内填充灰色。
    for i in range(len(box_coordinate_list)):
        for j in box_coordinate_list[i]:
            rect = pygame.Rect(j[0], j[1], edge, edge)
            pygame.Surface.fill(screen, gray, rect)
            pygame.draw.rect(screen, white, rect, 2)

    return box_coordinate_list

然后在窗体的代码的 while True: 循环结构体内部添加 matrix() 函数即可呈现出游戏区域网格。如下图:

游戏区域网格

一般情况下,我们不需要在游戏区域背景中显示网格,那么我的 matrix() 函数需要调整一下,就是不需要双重 for 循环的代码部分了

5、优化代码

上面的编码步骤是根据 pygame 库的特性以及如何创建 Rect 矩形的思路来一步一步进行编码的,像窗体、小方格和游戏区域的大小以及颜色等变量的管理比较凌乱。所以到这一步,我将相关变量进行统一管理,对代码进行优化。

# -*- coding: utf-8 -*-

import pygame

__author__ = {
    'name': "东方鹗",
    'github': "https://github.com/eastossifrage",
    'B 站主页': "https://space.bilibili.com/194359739",
    '知乎专栏': "https://zhuanlan.zhihu.com/ousi-python",
    '简书专栏': "https://www.jianshu.com/c/2036276cf0e8",
    'version': "1.0"
}
# 定义几个颜色     R   G   B
bgcolor       = ( 30,  25,  25) # 背景设置为黑色
yellow        = (255, 245,  40) # 黄色
light_yellow  = (175, 175,  20)
white         = (255, 245, 245)
gray          = (185, 185, 185)
black         = (  0,   0,   0)
red           = (155,   0,   0)
light_red     = (175,  20,  20)
green         = (  0, 155,   0)
light_green   = ( 20, 175,  20)
blue          = (  0,   0, 155)
light_blue    = ( 20,  20, 175)

# 定义屏幕大小
s_width = 800
s_height = 600

# 定义俄罗斯方块游戏区域的大小
a_width = 364
a_height = 544

# 定义正方形的大小
edge = 20

# 定义游戏区域左上角坐标,主要为了 Rect 类的使用方便。
coordinate = ((s_width-a_width)//4, s_height-a_height)

# 定义游戏区域中的小方格的行列数
box_row = int(a_height/edge) # 小方格的每列个数,也就是行数
box_col = int(a_width/edge)  # 小方格的每行个数,也就是列数

def box(x:"x表示在窗体内的横坐标", y:"y表示在窗体内的纵坐标"):
    ''' 功能:画出用于组成图形的单个正方形
    '''
    rect = pygame.Rect(x, y, 20, 20)
    pygame.Surface.fill(screen, yellow, rect) # 填充方格内的颜色
    pygame.draw.rect(screen, white, rect, 1)  # 画出方格的线条
    return rect

def area():
    ''' 功能:画出游戏区域
    '''
    rect = pygame.Rect(coordinate, (a_width, a_height))
    pygame.draw.rect(screen, light_blue, rect, 5)          # 画出游戏区域

def matrix():
    ''' 功能:以游戏区域为基础,画出用于呈现方块图形左上角坐标的矩阵。
    '''
    # 下面一行列表推导的代码用于构造小方格左上角坐标的二维列表
    box_coordinate_list = [[((coordinate[0] + x*edge + 2),
                            (coordinate[1] + y*edge + 2))
                            for x in range(box_col)] for y in range(box_row)]

    # 以下代码是画出游戏区域的网格,网格线是白色,网格内填充灰色。
    for i in range(len(box_coordinate_list)):
        for j in box_coordinate_list[i]:
            rect = pygame.Rect(j[0], j[1], edge, edge)
            pygame.Surface.fill(screen, gray, rect)
            pygame.draw.rect(screen, white, rect, 2)

    return box_coordinate_list


if __name__ == "__main__":
    pygame.init()  # 使用 pygame 之前先进行初始化
    screen = pygame.display.set_mode((s_width, s_height), pygame.RESIZABLE, 32)
    # 上面一行代码的功能为设置屏幕大小,此实例为 800*600,
    # 第二个参数是 RESIZABLE,表示打开一个可以改变大小的窗口,
    # 第三个参数是 32 位真彩色。
    pygame.display.set_caption("俄罗斯方块") # 设置窗体名称

    while True:
        screen.fill(bgcolor)  # 表示填充背景颜色。
        for event in pygame.event.get():
            if event.type == pygame.QUIT: # 检测退出动作
                exit()

        area()          # 绘制游戏区域
        matrix()        # 绘制游戏区域的网格线
        box(50, 50)     # 在坐标 (50, 50) 处绘制一个小方格
        pygame.display.update()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 224,642评论 6 522
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,168评论 3 402
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 171,809评论 0 366
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,921评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,924评论 6 399
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,415评论 1 314
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,794评论 3 428
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,765评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,297评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,331评论 3 345
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,458评论 1 354
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,065评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,777评论 3 337
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,233评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,366评论 1 275
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,001评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,524评论 2 365

推荐阅读更多精彩内容