用Python和Pygame写游戏-从入门到精通(实战二:恶搞俄罗斯方块2)
admin
2023-07-31 00:37:01
0

我们接着来做这个整死人不偿命的俄罗斯方块。

代码组织和名词约定

上一次我们稍微整理了一下游戏运行的框架,这里需要整理一下python代码的框架,一个典型的pygame脚本结构如下:

其中,lib为pygame的脚本,游戏中声音、图像、控制模块等都放在这里;而data就是游戏的资源文件,图像、声音等文件放在这里。当然这东西并不是硬性规定的,你可以用你自己喜欢的结构来组织自己的pygame游戏,事实上,除了付你工钱的那家伙以外,没有人可以强迫你这样做或那样做~ 这次我还是用这种典型的方法来存放各个文件,便于大家理解。

因为我是抽空在Linux和Windows上交叉编写的,代码中没有中文注释,游戏里也没有中文的输出,所以希望看到清楚解释的话,还是应该好好的看这几篇文章。当然最后我会放出所有的代码,也会用py2exe编译一份exe出来,方便传给不会用python的人娱乐。

因为主要是讲解pygame,很多python相关的知识点就一代而过了,只稍微解释一下可能有些疑问的,如果有看不懂的,请留言,我会酌情追加到文章中。

我们约定,那个掉落方块的区域叫board,落下的方块叫shape,组成方块的最小单位叫tile

我们的lib中可能会有这几个文件(未必是全部):

123456 game.py     主循环,该文件会调用mainmenu来展示不同界面main.py     游戏界面,但为了实现不同模式,这里需再次调用tetrismenu.py     菜单界面,开始的选择等shape.py   方块的类tetris.py   游戏核心代码,各种不同种类的俄罗斯方块实现util.py     各种工具函数,如读取图片等

引导文件

run_game.py很简单,而且基本所有的pygame工程里都长得一样:

12345678910111213 #!/usr/bin/env python import sys, os try:    libdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), \’lib\’)    sys.path.insert(0, libdir)except:    # in py2exe, __file__ is gone…    pass import gamegame.run()

将lib目录加入搜索路径就完事了,没有什么值得特别说明的。

主循环文件

到现在为止,我们所有的pygame都只有一个界面,打开是什么,到关闭也就那个样子。但实际上的游戏,一般进去就会有一个开始界面,那里我们可以选“开始”,“继续”,“选项”……等等内容。pygame中如何实现这个呢?

因为pygame一开始运行,就是一根筋的等事件并响应,所以我们就需要在事件的循环中加入界面的判断,然后针对的显示界面。例如:

1234567891011121314151617     def loop(self):        clock = pygame.time.Clock()        while self.stat != \’quit\’:            elapse = clock.tick(25)            if self.stat == \’menu\’:                self.stat = self.menu.run(elapse)            elif self.stat == \’game\’:                self.stat = self.main.run(elapse)             if self.stat.startswith(\’level\’):                level = int(self.stat.split()[1])                print \”Start game at level\”, level                self.main.start(level)                self.stat = \”game\”             pygame.display.update()        pygame.quit()

因为有很多朋友说之前使用的while True的方法不能正常退出,这里我就听取大家的意见干脆把退出也作为一种状态,兼容性可能会好一些。不过在我的机器上(Windows 7 64bit + Python 2.6 32bit + Pygame 1.9.1 32bit)是正常的,怀疑是不是无法正常退出的朋友使用了64位的Python和Pygame(尽管64位Pygame也有,但并不是官方推出的,不保证效果)。

这里定义了几个游戏状态,最主要的就是’menu‘和’game‘,意义也是一目了然的。我们有游戏对象和菜单对象,当游戏处于某种状态的时候,就调用对应对象的run方法,这个run接受一个时间参数,具体意义相信大家也明白了,基于时间的控制。

同时,我们还有一个’level X‘的状态,这个主要是控制菜单到游戏之间的转换,不过虽然写的level,实际的意义是模式,因为我们希望有几种不同的游戏模式,所以在从菜单到游戏过渡的时候,需要这个信息。

这个程序中,所有的状态都是通过字符串来实现的,说实话未必很好。虽然容易理解但是效率等可能不高,也许使用标志变量会更好一些。不过既然是例子,首先自然是希望大家能够看的容易一些。所以最终还是决定使用这个方法。

菜单显示了一些选项,并且在用户调节的时候可以显示当前的选项(一般来说就是高亮出来),最后确定时,改变状态。

12345678910111213141516171819 class Menu:    OPTS = [\’LEVEL 1\’, \’LEVEL 2\’, \’LEVEL 3\’, \’QUIT\’]    def __init__(self, screen):        self.screen = screen        self.current = 0     def run(self, elapse):        self.draw()        for e in pygame.event.get():            if e.type == QUIT:                return \’quit\’            elif e.type == KEYDOWN:                if e.key == K_UP:                    self.current = (self.current 1) % len(self.OPTS)                elif e.key == K_DOWN:                    self.current = (self.current + 1) % len(self.OPTS)                elif e.key == K_RETURN:                    return self.OPTS[self.current].lower()        return \’menu\’

菜单的话,大概就是长这个样子,都是我们已经熟练掌握的东西,按上下键的时候会修改当前的选项,然后draw的时候也就判断一下颜色有些不同的标识一下就OK了。这里的draw就是把几个项目写出来的函数。绘图部分和控制部分尽量分开,比较清晰,也容易修改。

这里的run其实并没有用到elapse参数,不过我们还是把它准备好了,首先可以与main一致,其次如果我们想在开始菜单里加一些小动画什么的,也比较便于扩展。

工具函数

工具库util.py里其实没有什么特别的,都是一些便于使用的小东西,比如说在加载资源文件是,我们希望只给出一个文件名就能正确加载,那就需要一个返回路径的函数,就像这样:

1234567891011121314151617181920212223 _ME_PATH = os.path.abspath(os.path.dirname(__file__))DATA_PATH = os.path.normpath(os.path.join(_ME_PATH, \’..\’, \’data\’)) def file_path(filename=None):    \”\”\” give a file(img, sound, font…) name, return full path name. \”\”\”    if filename is None:        raise ValueError, \’must supply a filename\’     fileext = os.path.splitext(filename)[1]    if fileext in (\’.png\’, \’.bmp\’, \’.tga\’, \’.jpg\’):        sub = \’image\’    elif fileext in (\’.ogg\’, \’.mp3\’, \’.wav\’):        sub = \’sound\’    elif fileext in (\’.ttf\’,):        sub = \’font\’     file_path = os.path.join(DATA_PATH, sub, filename)    print \’Will read\’, file_path     if os.path.abspath(file_path):        return file_path    else:        raise ValueError, \”Cant open file `%s\’.\” % file_path

这个函数可以根据给定的文件名,自己搜索相应的路径,最后返回全路径以供加载。

这次把一些周边的代码说明了一下,当然仅有这些无法构成一个可以用的俄罗斯方块,下一次我们就要开始搭建俄罗斯方块的游戏代码了。


相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...