-1

所以我有一个在程序退出时导出的已定义类的列表。它看起来像这样:

<__main__.Block object at 0x02416B70>, 
<__main__.Block object at 0x02416FF0>,
<__main__.Block object at 0x0241C070>, 
<__main__.Block object at 0x0241C0D0>, 
<__main__.Block object at 0x0241C130>, 
<__main__.Block object at 0x0241C190>, 
<__main__.Block object at 0x02416DF0>, 
<__main__.Block object at 0x0241C250>, 
<__main__.Block object at 0x0241C2B0>,
<__main__.Block object at 0x0241C310>, 
<__main__.Block object at 0x0241C370>, 
<__main__.Block object at 0x0241C3D0>, 
<__main__.Block object at 0x0241C430>, 
<__main__.Block object at 0x0241C490>, 
<__main__.Block object at 0x0241C4F0>, 
<__main__.Block object at 0x0241C550>,
<__main__.Block object at 0x0241C5B0>,
<__main__.Block object at 0x0241C610>

完美的!正确的?现在我应该可以轻松地将其转换为列表.. 所以我使用这个:

x=x.split(",")

它会将其转换为列表,是的,但它将类转换为字符串!使它们无法使用。

基本上我需要的是在文件关闭时“暂停”文件中的游戏状态,然后在打开文件时重新加载它。

那么如何在不将类名转换为字符串的情况下做到这一点呢?

4

1 回答 1

5

完美的!正确的?

可悲的是没有。您在此处看到的 ( <__main__.Block object at 0x02416B70>) 是类实例的典型字符串表示形式。它只是一个简单的字符串,没有办法将此字符串转换回Block.

我假设你从上一个问题开始还在玩这个游戏。

那么你如何真正持久化游戏的状态呢?最简单的方法是使用标准的 python 模块pickleshelve.

在下面的示例中,我将使用shelve,因为您不使用单个类来表示游戏状态:

“架子”是一个持久的、类似字典的对象。...货架中的值...本质上可以是任意 Python 对象...这包括大多数类实例、递归数据类型和包含大量共享子对象的对象。键是普通字符串。

首先,当我们退出游戏时,我们想要保存玩家和方块,所以我们save在游戏即将退出时调用一个新函数:

while True:
    ...
    for event in pygame.event.get():
        if event.type == QUIT: 
            save(player, blocklist)
            exit()

实现非常简单(为简洁起见,没有错误处理):

def save(player, blocks):
    f = shelve.open("save.bin") 
    f['player'] = player
    f['blocks'] = blocks
    f.close()

如您所见,使用shelve就像使用dict.

下一步是加载我们保存的数据。

player, blocklist = load() or (None, [])

我们调用一个新函数load,它要么返回已保存玩家对象的元组和已保存块对象的列表,要么返回None. 在 的情况下None,我们还没有创建玩家并为我们的块使用一个空列表。

实现就像函数一样简单save

def load():
    try:
        f = shelve.open("save.bin") 
        return f['player'], f['blocks']
    except KeyError:
        return None
    finally:
        f.close()

就是这样。

这是完整的代码:

import pygame,random
from pygame.locals import *
from collections import namedtuple
import shelve

pygame.init()
clock=pygame.time.Clock()
screen=pygame.display.set_mode((640,480))

max_gravity = 100

class Block(object):
    sprite = pygame.image.load("dirt.png").convert_alpha()
    def __init__(self, x, y):
        self.rect = self.sprite.get_rect(centery=y, centerx=x)

class Player(object):
    sprite = pygame.image.load("dirt.png").convert()
    sprite.fill((0,255,0))
    def __init__(self, x, y):
        self.rect = self.sprite.get_rect(centery=y, centerx=x)
        # indicates that we are standing on the ground
        # and thus are "allowed" to jump
        self.on_ground = True
        self.xvel = 0
        self.yvel = 0
        self.jump_speed = 10
        self.move_speed = 8

    def update(self, move, blocks):

        # check if we can jump 
        if move.up and self.on_ground: 
            self.yvel -= self.jump_speed

        # simple left/right movement
        if move.left: self.xvel = -self.move_speed
        if move.right: self.xvel = self.move_speed

        # if in the air, fall down
        if not self.on_ground:
            self.yvel += 0.3
            # but not too fast
            if self.yvel > max_gravity: self.yvel = max_gravity

        # if no left/right movement, x speed is 0, of course
        if not (move.left or move.right):
            self.xvel = 0

        # move horizontal, and check for horizontal collisions
        self.rect.left += self.xvel
        self.collide(self.xvel, 0, blocks)

        # move vertically, and check for vertical collisions
        self.rect.top += self.yvel
        self.on_ground = False;
        self.collide(0, self.yvel, blocks)

    def collide(self, xvel, yvel, blocks):
        # all blocks that we collide with
        for block in [blocks[i] for i in self.rect.collidelistall(blocks)]:

            # if xvel is > 0, we know our right side bumped 
            # into the left side of a block etc.
            if xvel > 0: self.rect.right = block.rect.left
            if xvel < 0: self.rect.left = block.rect.right

            # if yvel > 0, we are falling, so if a collision happpens 
            # we know we hit the ground (remember, we seperated checking for
            # horizontal and vertical collision, so if yvel != 0, xvel is 0)
            if yvel > 0:
                self.rect.bottom = block.rect.top
                self.on_ground = True
                self.yvel = 0
            # if yvel < 0 and a collision occurs, we bumped our head
            # on a block above us
            if yvel < 0: self.rect.top = block.rect.bottom

colliding = False
Move = namedtuple('Move', ['up', 'left', 'right'])

def load():
    try:
        f = shelve.open("save.bin") 
        return f['player'], f['blocks']
    except KeyError:
        return None
    finally:
        f.close()

def save(player, blocks):
    f = shelve.open("save.bin") 
    f['player'] = player
    f['blocks'] = blocks
    f.close()

player, blocklist = load() or (None, [])

while True:
    screen.fill((25,30,90))
    mse = pygame.mouse.get_pos()
    key = pygame.key.get_pressed()

    for event in pygame.event.get():
        if event.type == QUIT: 
            save(player, blocklist)
            exit()

        if key[K_LSHIFT]:
            if event.type==MOUSEMOTION:
                if not any(block.rect.collidepoint(mse) for block in blocklist):
                    x=(int(mse[0]) / 32)*32
                    y=(int(mse[1]) / 32)*32
                    blocklist.append(Block(x+16,y+16))
        else:
            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    to_remove = [b for b in blocklist if b.rect.collidepoint(mse)]
                    for b in to_remove:
                        blocklist.remove(b)

                    if not to_remove:
                        x=(int(mse[0]) / 32)*32
                        y=(int(mse[1]) / 32)*32
                        blocklist.append(Block(x+16,y+16))

                elif event.button == 3:
                    x=(int(mse[0]) / 32)*32
                    y=(int(mse[1]) / 32)*32
                    player=Player(x+16,y+16)

    move = Move(key[K_UP], key[K_LEFT], key[K_RIGHT])

    for b in blocklist:
        screen.blit(b.sprite, b.rect)

    if player:
        player.update(move, blocklist)
        screen.blit(player.sprite, player.rect)

    clock.tick(60)
    pygame.display.flip()

在这里你可以看到加载和保存的动作:

在此处输入图像描述

请注意,您不能以Surfaces这种方式保存(或“腌制”)。在此代码中,它之所以有效,是因为SurfacesofPlayerBlock是类变量,而不是实例变量,因此不会保存到磁盘。如果您想用Surface实例变量“腌制”一个对象,您必须删除第Surface一个(例如将其设置为None)并再次加载它(例如在load函数中)。

于 2013-09-25T12:08:55.733 回答