pygame演示----黑猩猩小游戏

pygame演示----黑猩猩小游戏

导入模块
这是将所有需要的模块导入到程序中的代码。它还检查一些可选的pygame模块的可用性。

import os, sys
import pygame
from pygame.locals import *

if not pygame.font: print('Warning, fonts disabled')
if not pygame.mixer: print('Warning, sound disabled')

首先,我们导入标准的"os"和"sys" python模块。它们允许我们做一些事情,比如创建平台独立的文件路径。
在下一行中,我们导入pygame包。当pygame被导入时,它会导入属于pygame的所有模块。一些pygame模块是可选的,如果没有找到它们,它们的值将被设置为None。
有一个特殊的pygame模块叫做locals。这个模块包含pygame的一个子集。这个模块的成员是常用的常量和函数,它们被证明可以放入程序的全局命名空间中。这个locals模块包括“Rect”等函数来创建一个矩形对象,以及许多常量,如“QUIT, HWSURFACE”,这些常量用于与pygame的其余部分交互。像这样将locals模块导入全局命名空间完全是可选的。如果您选择不导入它,则所有locals的成员在pygame模块中总是可用的。
最后,如果pygame中的字体或混音模块不可用,我们决定打印一个漂亮的警告消息。

加载资源
这里我们有两个函数可以用来加载图像和声音。我们将在本节中分别研究每个函数。

def load_image(name, colorkey=None):
    fullname = os.path.join('data', name)
    try:
        image = pygame.image.load(fullname)
    except pygame.error as message:
        print('Cannot load image:', name)
        raise SystemExit(message)
    image = image.convert()
    if colorkey is not None:
        if colorkey is -1:
            colorkey = image.get_at((0, 0))
        image.set_colorkey(colorkey, RLEACCEL)
    return image, image.get_rect()

这个函数接受要加载的图像的名称。它还可以选择接受一个参数,用于设置图像的颜色键。颜色键在图形中用于表示图像的一种颜色,它是透明的。
这个函数做的第一件事是创建文件的完整路径名。在本例中,所有资源都在“data”子目录中。通过使用os.path.join函数,将创建一个路径名,该路径名适用于游戏所运行的任何平台。
接下来,我们使用pygame.image.load()从文件(或类文件对象)函数加载新图像。我们将这个函数包装在一个try/except块中,因此如果在加载图像时出现问题,我们可以优雅地退出。加载图像后,我们对convert()函数进行重要调用。这将生成一个Surface的新副本,并将其颜色格式和深度转换为与显示器匹配的颜色。这意味着将图像以尽可能快的速度分割到屏幕上。
最后,我们为图像设置颜色键。如果用户为colorkey参数提供了一个参数,我们就使用这个值作为图像的colorkey。这通常只是一个颜色RGB值,就像白色的(255,255,255)。您还可以传递一个值-1作为colorkey。在本例中,该函数将在图像的toppleft像素处查找颜色,并将该颜色用作颜色键。

def load_sound(name):
    class NoneSound:
        def play(self): pass
    if not pygame.mixer:
        return NoneSound()
    fullname = os.path.join('data', name)
    try:
        sound = pygame.mixer.Sound(fullname)
    except pygame.error as message:
        print('Cannot load sound:', fullname)
        raise SystemExit(message)
    return sound

接下来是加载声音文件的函数。这个函数做的第一件事是检查是否pygame。加载和播放声音的Mixerpygame模块被正确导入。如果不是,它返回一个小的类实例,它有一个虚拟的play方法。这将足够像一个正常的声音对象运行这个游戏,没有任何额外的错误检查。
这个函数类似于图像加载函数,但处理一些不同的问题。首先,我们创建声音图像的完整路径,并在try/except块中加载声音文件。然后我们简单地返回加载的Sound对象。

游戏对象类
在这里,我们创建了两个类来表示游戏中的对象。几乎所有的游戏逻辑都包含在这两个类中。我们将在这里逐一查看。

class Fist(pygame.sprite.Sprite):
    """随着鼠标在屏幕上移动一个握紧的拳头"""
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)  # call Sprite initializer
        self.image, self.rect = load_image('fist.bmp', -1)
        self.punching = 0

    def update(self):
        ""根据鼠标位置移动拳头"""
        pos = pygame.mouse.get_pos()
        self.rect.midtop = pos
        if self.punching:
            self.rect.move_ip(5, 10)

    def punch(self, target):
        """如果拳头与目标冲突返回true"""
        if not self.punching:
            self.punching = 1
            hitbox = self.rect.inflate(-5, -5)
            return hitbox.colliderect(target.rect)

    def unpunch(self):
        """called to pull the fist back"""
        self.punching = 0

这里我们创建了一个类来表示玩家的拳头。它派生自pygame中包含的Sprite类。带有基本游戏对象类模块的Spritepygame模块。创建该类的新实例时调用__init__函数。我们要做的第一件事是确保调用基类的__init__函数。这允许Sprite的__init__函数准备我们的对象作为一个Sprite使用。这个游戏使用了一个精灵绘图组类。这些类可以绘制具有“image”和“rect”属性的精灵。通过简单地更改这两个属性,渲染器将在当前位置绘制当前图像。
所有精灵都有一个update()方法。这个函数通常每帧调用一次。这是你应该放置用于移动和更新精灵变量的代码的地方。拳头的update()方法将拳头移动到鼠标指针的位置。如果拳头处于“出拳”状态,它也会略微抵消拳头的位置。
下面两个函数punch()和unpunch()改变拳头的打孔状态。如果拳头与给定的目标精灵发生碰撞,punch()方法也会返回一个真值。

class Chimp(pygame.sprite.Sprite):
    """在屏幕上移动一个小猴子。它可以旋转
当它被打时,猴子。"""
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)  # call Sprite intializer
        self.image, self.rect = load_image('chimp.bmp', -1)
        screen = pygame.display.get_surface()
        self.area = screen.get_rect()
        self.rect.topleft = 10, 10
        self.move = 9
        self.dizzy = 0

    def update(self):
        """行走或旋转,这取决于猴子的状态"""
        if self.dizzy:
            self._spin()
        else:
            self._walk()

    def _walk(self):
        """移动猴子在屏幕上,并在结束时转身"""
        newpos = self.rect.move((self.move, 0))
        if not self.area.contains(newpos):
            if self.rect.left < self.area.left or \
                    self.rect.right > self.area.right:
                self.move = -self.move
                newpos = self.rect.move((self.move, 0))
                self.image = pygame.transform.flip(self.image, 1, 0)
            self.rect = newpos

    def _spin(self):
        """旋转猴子的形象"""
        center = self.rect.center
        self.dizzy += 12
        if self.dizzy >= 360:
            self.dizzy = 0
            self.image = self.original
        else:
            rotate = pygame.transform.rotate
            self.image = rotate(self.original, self.dizzy)
        self.rect = self.image.get_rect(center=center)

    def punched(self):
        """这将导致猴子开始旋转"""
        if not self.dizzy:
            self.dizzy = 1
            self.original = self.image

黑猩猩班比拳头班做的工作多一点,但没有比拳头更复杂。这个类将在屏幕上来回移动黑猩猩。当猴子被打了一拳后,它会旋转起来,达到令人兴奋的效果。这个类也是从基Sprite类派生出来的,初始化方式和fist一样。在初始化时,类还将属性“area”设置为显示屏幕的大小。
黑猩猩的更新函数只是查看当前的“眩晕”状态,这在猴子被击打后旋转时是正确的。它调用_spin或_walk方法。这些函数前面有一个下划线。这只是一个标准的python习惯用法,建议这些方法只能由Chimp类使用。我们甚至可以给它们一个双下划线,这将告诉python真正尝试让它们成为私有方法,但我们不需要这样的保护。😃
_walk方法通过将当前矩形移动一个给定的偏移量来为猴子创建一个新的位置。如果这个新位置穿过屏幕显示区域之外,它将反转移动偏移量。它还使用pygame.transform.flip()垂直和水平翻转函数来镜像图像。这是一种粗糙的效果,让猴子看起来像是在转向它移动的方向。
当monkey当前处于“眩晕”状态时,调用_spin方法。眩晕属性用于存储当前的旋转量。当猴子旋转了所有的方式(360度),它将重置猴子的图像回到原来的,非旋转的版本。在调用pygame.transform.rotate()旋转图像函数之前,您将看到代码对函数进行了一个简单的局部引用,名为“rotate”。对于这个示例,不需要这样做,只是为了保持下面一行的长度更短一些。请注意,在调用rotate函数时,我们总是从原始的monkey图像开始旋转。旋转时,质量略有下降。重复旋转相同的图像,每次质量都会变差。另外,当旋转图像时,图像的大小实际上会改变。这是因为图像的角将被旋转出去,使图像更大。我们确保新图像的中心与旧图像的中心相匹配,所以它不会移动。
最后一个方法是punch(),它告诉精灵进入其眩晕状态。这将导致图像开始旋转。它还将当前图像的副本命名为“original”。

初始化
在使用pygame进行更多操作之前,我们需要确保它的模块已经初始化。在本例中,我们还将打开一个简单的图形窗口。现在我们在程序的main()函数中,它实际上运行所有的东西。

pygame.init()
screen = pygame.display.set_mode((468, 60))
pygame.display.set_caption('Monkey Fever')
pygame.mouse.set_visible(0)

初始化pygame的第一行为我们做了一些工作。它检查导入的pygame模块,并尝试初始化每个模块。可以回去检查模块是否初始化失败,但这里我们就不费事了。也可以采用更多的控制并手动初始化每个特定的模块。这种类型的控制通常是不需要的,但如果您愿意,可以使用。
接下来,我们设置显示图形模式。请注意pygame。显示模块用于控制所有显示设置。在本例中,我们要求一个简单的瘦窗口。有一个完全独立的教程来设置图形模式,但如果我们真的不关心,pygame将做得很好,让我们得到一些工作。Pygame会选择最好的颜色深度,因为我们没有提供。
最后,我们设置窗口标题并关闭窗口的鼠标光标。非常基本的操作,现在我们有一个小的黑色窗口准备执行我们的命令。通常光标默认为可见,所以没有必要真正设置状态,除非我们想隐藏它。

创建背景
我们的程序会在后台有文本信息。我们最好创建一个单一的表面来代表背景,并反复使用它。第一步是创建表面。

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

这为我们创建了一个与显示窗口相同大小的新表面。注意在创建Surface之后对convert()的额外调用。不带参数的转换将确保我们的背景与显示窗口的格式相同,这将给我们提供最快的结果。
我们也用纯白色填充整个背景。Fill使用RGB三元组作为颜色参数。

把文字放在背景,居中
现在我们有了一个背景表面,让我们把文本渲染到它。我们只有看到pygame才会这么做。用于加载和呈现字体模块的Fontpygame模块已正确导入。如果没有,我们就跳过这一节。

if pygame.font:
    font = pygame.font.Font(None, 36)
    text = font.render("Pummel The Chimp, And Win $$$", 1, (10, 10, 10))
    textpos = text.get_rect(centerx=background.get_width()/2)
    background.blit(text, textpos)

如您所见,有几个步骤可以完成此工作。首先,我们必须创建字体对象,并将其渲染到一个新的表面。然后我们找到这个新表面的中心,并将其块(粘贴)到背景上。
字体是通过字体模块的font()构造函数创建的。通常,您将传递一个TrueType字体文件的名称给这个函数,但我们也可以传递None,它将使用默认字体。Font构造函数还需要知道要创建的字体的大小。
然后,我们将该字体渲染到一个新的表面。渲染函数为我们的文本创建一个合适大小的新表面。在这种情况下,我们也告诉渲染创建反锯齿的文本(为了一个漂亮的光滑的外观),并使用深灰色。
接下来,我们需要找到显示文本的居中位置。我们从文本尺寸创建一个“Rect”对象,这允许我们轻松地将它分配到屏幕中心。
最后我们blit (blit就像复制或粘贴)文本到背景图像上。

安装完成时显示背景
屏幕上还有一个黑色的窗口。让我们在等待其他资源加载的同时显示我们的后台。

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

这将把我们的整个背景分割到显示窗口上。这是不言自明的,但是这个翻盖程序呢?
在pygame中,对显示表面的更改不是立即可见的。通常,必须更新已更改区域的显示,以便用户可以看到。使用双缓冲显示时,必须交换(或翻转)显示以使更改变为可见。在这种情况下,flip()函数工作得很好,因为它只处理整个窗口区域,并且处理单缓冲和双缓冲的表面。

准备游戏对象
这里我们创建了游戏需要的所有对象。

whiff_sound = load_sound('whiff.wav')
punch_sound = load_sound('punch.wav')
chimp = Chimp()
fist = Fist()
allsprites = pygame.sprite.RenderPlain((fist, chimp))
clock = pygame.time.Clock()

首先,我们使用上面定义的load_sound函数加载两个声音效果。然后我们为每个精灵类创建一个实例。最后,我们创建一个精灵组,它将包含我们所有的精灵。
我们实际上使用了一个名为RenderPlain的特殊精灵组。这个精灵组可以将它所包含的所有精灵绘制到屏幕上。它被称为RenderPlain,因为实际上有更高级的渲染组。但对于我们的游戏,我们只需要简单的绘图。我们通过传递一个包含所有应该属于该组的精灵的列表来创建名为“allsprites”的组。我们可以稍后在这个组中添加或删除精灵,但在这个游戏中我们不需要这样做。
我们创建的时钟对象将用于帮助控制我们的游戏的帧速率。我们将在游戏的主循环中使用它,以确保它不会运行得太快。

** 主循环**
这里没什么,只是一个无限循环。

while 1:
    clock.tick(60)

所有游戏都在某种循环中运行。通常的操作顺序是检查计算机状态和用户输入,移动并更新所有对象的状态,然后将它们绘制到屏幕上。您将看到这个示例没有什么不同。
我们还调用了时钟对象,这将确保我们的游戏运行速度不会超过每秒60帧。

处理所有输入事件
这是一个处理事件队列的极其简单的例子。

for event in pygame.event.get():
    if event.type == QUIT:
        return
    elif event.type == KEYDOWN and event.key == K_ESCAPE:
        return
    elif event.type == MOUSEBUTTONDOWN:
        if fist.punch(chimp):
            punch_sound.play()  # 重击
            chimp.punched()
        else:
            whiff_sound.play()  # 错过
    elif event.type == MOUSEBUTTONUP:
        fist.unpunch()

首先,我们从pygame中获得所有可用的事件,并对每个事件进行循环。前两个测试是查看用户是否退出了我们的游戏,或按下了退出键。在这些情况下,只需从main()函数返回,程序就会干净地结束。
接下来,我们只是检查鼠标按钮是否被按下或释放。如果按钮被按下,我们会询问第一个物体是否与黑猩猩相撞。我们播放适当的声音效果,如果猴子被击中了,我们告诉它开始旋转(通过调用它的punching()方法)。

更新精灵

allsprites.update()

精灵组有一个update()方法,它只是调用它所包含的所有精灵的更新方法。每个对象都将移动,这取决于它们所处的状态。在这个阶段,黑猩猩会向一边移动一步,或者如果它最近被打过,会转得更远一点。

绘制整个场景
现在所有的物体都在正确的位置,是时候画它们了。

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

第一个blit调用将把背景绘制到整个屏幕上。这将删除我们在前一帧中看到的所有内容(虽然有点低效,但对于这款游戏来说已经足够好了)。接下来我们调用精灵容器的draw()方法。因为这个精灵容器实际上是“DrawPlain”精灵组的一个实例,所以它知道如何绘制我们的精灵。最后,我们将pygame的软件双缓冲区的内容翻转()到屏幕上。这使得我们画的所有东西都同时可见。

游戏结束
用户已退出,该清理了。
清理pygame中的运行游戏是非常简单的。事实上,由于所有变量都被自动析构,所以我们真的不需要做任何事情。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值