利用pygame开发一款游戏:「跳跳兔」(六)

1,259 阅读4分钟

HackPython改名为「懒编程」,纯粹是因为我有另外一个写杂文的号叫「懒写作」,此外,感觉「懒编程」比HackPython好记。

前言

在第5节内容中,实现了积分机制、玩家死亡逻辑以及游戏开始界面逻辑,本节继续完善游戏,来实现游戏结束逻辑与玩家图片化,不再使用方块。

游戏结束逻辑

回忆一下整体逻辑:

g = Game()
g.show_start_screen()
while g.running:
    g.new()
    g.show_go_screen()

pg.quit()

可以通过show_go_screen()方法实现游戏结束逻辑,代码如下:

# main.py/Game

# 每轮游戏结束后,都会调用该方法
def show_go_screen(self):
        # game over/continue
        if not self.running: # 是否在运行
            return
        self.screen.fill(BGCOLOR) # 游戏框背景颜色填充
        # 绘制文字
        self.draw_text("GAME OVER", 48, WHITE, WIDTH / 2, HEIGHT / 4)
        self.draw_text("Score: " + str(self.score), 22, WHITE, WIDTH / 2, HEIGHT / 2)
        self.draw_text("Press a key to play again", 22, WHITE, WIDTH / 2, HEIGHT * 3 / 4)
        # 判断分数
        if self.score > self.highscore:
            self.highscore = self.score
            self.draw_text("NEW HIGH SCORE!", 22, WHITE, WIDTH / 2, HEIGHT / 2 + 40)
            # 记录新的最高分到文件中 - 持久化
            with open(os.path.join(self.dir, HS_FILE), 'w') as f:
                f.write(str(self.score))
        else:
            self.draw_text("High Score: " + str(self.highscore), 22, WHITE, WIDTH / 2, HEIGHT / 2 + 40)
        # 翻转
        pg.display.flip()
        # 等待敲击任意键,重新开始新的一轮游戏
        self.wait_for_key()

show_go_screen()方法逻辑可以阅读详细的注释,不再赘述。

show_go_screen()通过文件的方式来记录最高的分数,所以在游戏一开始,就需要从文件中读取此前的分数,好为这部分逻辑做判断,逻辑如下:

class Game:
    def __init__(self):
        # ...
        # 加载最高分数
        self.load_data()

    def load_data(self):
        self.dir = os.path.dirname(__file__)
        filepath = os.path.join(self.dir, HS_FILE)
        with open(filepath, 'r') as f:
            try:
                self.highscore = int(f.read())
            except:
                self.highscore = 0

玩家图片化

一个正常的游戏,肯定要有相应的图片素材的,图片素材是否精美也是影响他人是否要玩你游戏的重要因素。

通常,一个游戏,会有多张大图,多个同类元素都放在这张大的png图片中,而不是每个元素都是一个png元素,通过这种方式,让整个游戏包更小。

如下,一张完整的图

与其对应的就是图中不同元素其坐标位置(x,y)以及元素图片大小

写一段从完整图片中获取对应元素的逻辑,代码如下:

# sprites.py

# 加载与解析精灵图片
class Spritesheet:
    def __init__(self, filename):
        # 主要要使用convert()进行优化, convert()方法会 改变图片的像素格式
        # 这里加载了整张图片
        self.spritesheet = pg.image.load(filename).convert()

    # 从比较大的精灵表中,通过相应的xml位置,抓取中出需要的元素
    def get_image(self, x, y, width, height):
        # 创建Surface对象(画板对象)
        image = pg.Surface((width, height))
        # blit — 画一个图像到另一个
        # 将整张图片中,对应位置(x,y)对应大小(width,height)中的图片画到画板中
        image.blit(self.spritesheet, (0, 0), (x, y, width, height))
        #  pygame.transform.scale 缩放的大小
        # 这里将图片缩放为原来的一半
        image = pg.transform.scale(image, (width // 2, height // 2))
        return image

在__init__()中,通过pygame.image.load()方法加载完整的图片,记得使用convert()方法进行优化,随后定义了get_image()方法,该方法的逻辑也很直接,先实例化Surface类,获得与图片大小相同的面板对象,然后,通过blit()方法将完整图片中对应位置与大小的元素剥离出来。

经过实践,原本图片元素太大,所以通过pygame.transform.scale()方法将图片元素缩小2倍。

编写完Spritesheet类后,在Game类的load_data()方法中实例化一下

# main.py/Game

def load_data(self): # 加载数据
        self.dir = os.path.dirname(__file__)
        filepath = os.path.join(self.dir, HS_FILE)
        with open(filepath, 'r') as f:
            try:
                self.highscore = int(f.read())
            except:
                self.highscore = 0
        img_dir = os.path.join(self.dir, 'img')
        # 加载精灵图片
        self.spritesheet = Spritesheet(os.path.join(img_dir, SPRITESHEET))

做完这些后,在Player类初始化时调用其中的get_image()方法就大功告成了。

class Player(pg.sprite.Sprite):
    def __init__(self, game):
        pg.sprite.Sprite.__init__(self)
        self.game = game
        # 加载 bunny1_ready状态的兔子图片, xml文件中给出的(x,y)与(width,height)
        self.image = self.game.spritesheet.get_image(614, 1063, 120, 191)
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH / 2, HEIGHT / 2)
        self.pos = vec(WIDTH / 2, HEIGHT / 2)
        self.vel = vec(0, 0) # 速度
        self.acc = vec(0, 0) # 加速度

为了整体美观,修改了一下,游戏框整体的背景颜色,具体通过self.screen.fill(BGCOLOR)方法。

最后,效果如下:

结尾

在本节中,我们实现了游戏结束界面以及使用了玩家元素,后面,会进一步优化玩家元素,让玩家在左右移动时,是不同的图片,从而让整个游戏显得更加灵动。

因为考虑到篇幅,文中没有给出完整的代码,但为了方便大家理解,我将相应的代码上传到了github

github.com/ayuLiao/jum…

如果文章对你有帮助或你觉得有点意思,点击「在看」支持作者一波。