07 pygame编程实践篇(上)

pygame编程入门之七:Making Games With Pygame1

1. Introduction

首先假设您已经阅读了在线黑猩猩教程的代码,它介绍了Python和pygame的基础知识。
本教程的目标读者是那些懂得如何制作一个非常简单的小“游戏”的人,他们要做一个相对简单的游戏,比如“乒乓”。它向你介绍了游戏设计的一些概念,通过简单的数学计算出了球物理反弹,以及一些让游戏易于维护和扩展的方法。
本教程中的所有代码都致力于实现TomPong功能。在本教程结束时,你不仅应该对pygame有更强理解,而且还应该了解TomPong是如何工作的,以及以后如何制作自己的游戏。
现在,简单回顾一下pygame的基础知识。为游戏组织代码的一种常见方法是将其划分为以下六个部分:

  • 1、在游戏中需要的加载模块。标准内容,除此以外,记得导入pygame本地名称以及pygame模块本身。
  • 2、资源类处理;定义一些类来处理基本资源,这些资源将加载图像和声音,以及连接和断开网络、加载保存游戏文件和任何其他资源。
  • 3、游戏对象类;为游戏对象定义类。
    在pong的例子中,这些将是玩家的bat(你可以多次初始化一次,为游戏中的每个玩家初始化一个),一个用于球(可以有多个实例)。如果要一个漂亮的游戏菜单,那么做一个菜单类也是个好主意。
  • 4、其他游戏功能;定义其他必要的功能,如记分板、菜单处理等。任何放入主游戏逻辑的代码,将使理解逻辑更加困难,如果是功能块,应该放到它的功能中。
    因此,绘制计分板并不是游戏逻辑,应该被移动到一个函数中。
  • 5、初始化游戏,包括pygame对象本身、背景、游戏对象(初始化类的实例)和其他您可能想要添加的代码。
  • 6、主循环,放入任何输入处理(例如,监视用户点击键盘/鼠标按钮),更新游戏对象的代码,最后是更新屏幕。

所做的每一款游戏都有这样一些或全部的版块,可能还有更多自定义版块。
本教程将写关于“乒乓”如何布局,这样的想法可以被移植到任何做的游戏中。
假设将所有代码保存在单个文件中,但如果您正在进行一个相当大的游戏,那么将某些部分提供到模块文件中通常是一个好主意。
将游戏对象类放入名为object的文件中。py可以帮助您将游戏逻辑与游戏对象分离开来。
如果有大量的资源处理代码,那么将其放入resources.py也很方便。然后,您可以从对象、资源 import *来导入所有的类和函数。

1.1. 编码风格

在进行任何编程项目时,首先要记住的是决定一种编码风格,并保持一致。
严格解释的空格和缩进,Python可以解决很多问题。你可以选择缩进的大小,把每个模块导入一个新行,如何注释代码,等等。
你会看到我如何处理这些代码示例;你不需要使用的风格,但是无论采用什么风格,都要在程序代码中使用它。
尝试为所有类加说明,并对任何看起来晦涩难懂的代码进行注释,不过不要开释明显的代码。我见过很多人这样做:

player1.score += scoreup        # Add scoreup to player1 score

最糟糕的代码就是布局很差,样式随意变化,说明文档也很糟糕。
糟糕的代码不仅会让其他人厌烦,而且还让你难以维护。

2。修订:Pygame基本面

2.1基本Pygame游戏

为了修正,以假定你已经熟悉Pygame程序的基本结构。我运行一段简单的Pygame代码,它会显示一个窗口有一些文本,差不多这样。(当然不同的系统,窗口可能会不同):

#!/usr/bin/python

import pygame
from pygame.locals import *

def main():
    # Initialise screen
    pygame.init()
    screen = pygame.display.set_mode((150, 50))
    pygame.display.set_caption('Basic Pygame program')

    # Fill background
    background = pygame.Surface(screen.get_size())
    background = background.convert()
    background.fill((250, 250, 250))

    # Display some text
    font = pygame.font.Font(None, 36)
    text = font.render("Hello There", 1, (10, 10, 10))
    textpos = text.get_rect()
    textpos.centerx = background.get_rect().centerx
    background.blit(text, textpos)

    # Blit everything to the screen
    screen.blit(background, (0, 0))
    pygame.display.flip()

    # Event loop
    while 1:
        for event in pygame.event.get():
            if event.type == QUIT:
                return

        screen.blit(background, (0, 0))
        pygame.display.flip()


if __name__ == '__main__': main()

2.2。基本Pygame对象

如您所见,代码主要由三个对象组成:屏幕、背景和文本。
每个对象通过首先调用内置Pygame对象的实例来创建,然后修改它以满足我们的需要。
屏幕是一个稍微特殊的例子,通过Pygame调用来修改显示,而不是调用属于屏幕对象的方法。
但是对于所有其他Pygame对象,我们首先创建对象作为Pygame对象的副本,赋予它一些属性,并从它们构建游戏对象。
对于背景,首先创建了一个Pygame_Surface对象,并使其大小为屏幕的大小。然后我们执行convert()操作,将表面转换为单个像素格式。
当几个图像和表面有不同的像素格式时,这显然是必要的,渲染速度会非常慢。通过转换所有的表面,可以大大减少渲染时间。
最后,用白色填充背景表面(255,255,255)。这些值是RGB(红绿蓝),可以从任何好的色板程序获得。
对于文本,可能需要不止一个对象。首先创建一个字体对象,它定义要使用哪种字体,以及字体的大小。
然后创建一个文本对象,通过使用属于字体对象的render方法,需要提供三个参数:要呈现的文本内容,是否反锯齿(1=yes,0=no),以及文本的颜色(RGB格式)。
接下来,创建第三个文本对象,它获取文本的矩形。理解这一点的最简单的方法是:想象画个矩形,包围所有的文本;然后用这个矩形来获取/设置屏幕上文本的位置。
我们得到了矩形,把它的centerx属性设置为背景centerx属性(所以文本的中心将与背景的中心相同,也就是文本将以x轴上的屏幕为中心)。我们也可以设置y坐标,没有设置垢话,默认文本以屏幕的顶部对齐。由于屏幕很小,没有必要设置值。

2.3。Blitting

现在已经创建了游戏对象,我们需要渲染它们。如果不这样,我们运行程序,只会看到一个空白的窗口,这些对象将不可见。
渲染对象的术语是“Blitting”,即将属于该对象的像素复制到目标对象上。为了渲染背景对象,把它Blitting在屏幕上。在这个例子中,为了变得简单,我们把文本Blitting在背景上(这样背景就会有一个文本的副本),然后将背景Blitting在屏幕上。
在任何游戏中,Blitting是最慢的操作之一,所以你需要小心,不要在每一帧中都Blitting太多内容到屏幕。
如果你一个背景图像,一个球在屏幕上滚动,你可以把背景和球Blitting在每一帧上,这样就可以掩盖球的前一个位置并呈现出新的球,但这是相当慢的。
一个更好的解决方案是把背景设置在球之前的区域,通过球的此矩形找到这个区域,然后把球Blitting到球的新位置,这样就只会在两个小区域上Blitting。

2.4。事件循环

一旦设置好了游戏,需要把它放到一个无限循环中,这样它就会一直运行,直到用户发出他/她退出的信号。
你开始一个打开的while循环,然后对于循环的每次迭代,也就是游戏的每一帧,更新游戏。
第一件事是检查任何Pygame事件,用户点击键盘,点击鼠标按钮,移动操纵杆,调整窗口大小,或者试图关闭它。
我们只要注意,用户试图通过关闭窗口来退出游戏,游戏返回,结束while循环。
只需要重新设置背景,然后flip(update)显示,把所有的东西画出来。
好吧,例子中没有任何变化或发生,严格地说,在每次迭代都需要重新调整背景,当对象在屏幕上移动时,你需要重做所有Blitting。

2.5。Ta-da!

这就是一个完整的游戏!所有的游戏都将采用类似形式。对于实际的游戏来说,还会有更多的代码。
但是基本功能与这个差不多,在结构上没有比这更复杂。本教程的真正内容,就是细化整个流程,现在继续下去。

3。开始做事了

代码第一部分相对简单,并且一旦编写完成,通常可以在以后的每一个游戏中重用。
他们把所有无聊的、一般的任务,比如加载模块,加载图片,打开网络连接,播放音乐等等完成。它们还包括一些简单但有效的错误处理,以及您导入诸如sys和pygame等模块,在功能之上提供的更多的模块。

3.1。第一行和加载模块

首先,需要开始游戏并加载模块。设置一些东西直接在顶部的主要源文件,如文件的名称,它包含什么许可,和其他有用信息。给那些会看到代码的人,这是一个好主意。
然后加载模块,并进行一些错误检查,这样Python就不会打印出令人讨厌的回馈,而这是非程序员所无法理解的。
代码相当简单,所以不需要解释任何一句:

#!/usr/bin/env python
#
# Tom's Pong
# A simple pong game with realistic physics and AI
# http://www.tomchance.uklinux.net/projects/pong.shtml
#
# Released under the GNU General Public License

VERSION = "0.4"

try:
    import sys
    import random
    import math
    import os
    import getopt
    import pygame
    from socket import *
    from pygame.locals import *
except ImportError, err:
    print "couldn't load module. %s" % (err)
    sys.exit(2)

3.2. 资源处理函数

在黑猩猩的例子中,第一段代码是加载图像和声音。由于这些模块完全独立于任何游戏逻辑或游戏对象,它们被编写为单独的函数,并且提前编写,以便后边代码可以使用。
我通常把所有这类性质的代码放在类型无关函数中;一般来说,这些都是资源处理函数。
当然,可以为这些创建类,这样就可以把它们组合在一起,或者有一个可以控制所有资源的对象。与任何好的编程环境一样,这取决于你自己的最佳实践和风格。
编写自己的资源处理函数总是一个好主意。尽管Pygame有打开图像和声音的方法,其他模块也有打开其他资源的方法。但通常不提供令人满意的错误处理,所以需要自己修改一致。
编写资源处理函数可以提供复杂的、可重用的代码,并使您对资源有更多的控制。以图像加载函数为例:

def load_png(name):
    """ Load image and return image object"""
    fullname = os.path.join('data', name)
    try:
        image = pygame.image.load(fullname)
        if image.get_alpha() is None:
            image = image.convert()
        else:
            image = image.convert_alpha()
    except pygame.error, message:
        print 'Cannot load image:', fullname
        raise SystemExit, message
    return image, image.get_rect()

这个函数假设所有图像都在一个名为data的目录中,它接受文件名并创建完整路径名,例如data/ball.png,使用操作系统模块来确保跨平台的兼容性。
然后尝试加载图像,并转换任何alpha区域,这样可以获得透明性.如果出现问题,它会返回一段更易于人类阅读的错误。如果正常,它返回image对象及其rect。
您可以为加载其他资源做类似的功能,比如加载声音。还可以创建资源处理类,以便在更复杂的资源中提供更大的灵活性。
例如,你可以创建一个音乐类,用一个init函数来加载声音(可能从loadsound()函数中调用),一个暂停音乐的函数,一个重新启动函数。
另一个方便的资源处理类用于网络连接。打开套接字,通过适当的安全性和错误检查传递数据,关闭套接字、寻址和其他网络任务。可以使编写具有网络功能的游戏相对轻松。
记住,这些函数/类的主要任务是,当您开始编写游戏对象类和主循环时,在循环里几乎没有什么可做的了。
类继承可以使这些基本类特别友好。不过不要走极端。只被一个类使用的函数应该作为该类的私有函数,而不能作为全局方法。

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

推荐阅读更多精彩内容