Sam*_*ubb -1 python persistence pygame
所以我有一个已在程序退出时导出的已定义类的列表..它看起来像这样:
<__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>
Run Code Online (Sandbox Code Playgroud)
完善!对?现在我应该可以轻松地将其转换为列表..所以我使用这个:
x=x.split(",")
Run Code Online (Sandbox Code Playgroud)
它将它转换为列表是,但它将类转换为字符串!使它们无法使用.
基本上我需要的是在文件关闭时"暂停"游戏状态,然后在打开文件时重新加载它.
那么如何在不将类名转换为字符串的情况下完成此操作呢?
完善!对?
可悲的是没有.你在这里看到的(<__main__.Block object at 0x02416B70>)是类实例的典型字符串表示.它只是一个简单的字符串,并且没有办法将此字符串转换回的实例Block.
我假设你在上一个问题中仍然处于这个游戏中.
那么你如何真正坚持游戏的状态呢?最简单的方法是使用标准的python模块pickle或shelve.
在下面的示例中,我将使用shelve,因为您不使用单个类来表示游戏状态:
"架子"是一个持久的,类似字典的对象.......架子中的值......基本上可以是任意的Python对象......这包括大多数类实例,递归数据类型和包含许多共享子对象的对象.键是普通的字符串.
首先,当我们退出游戏时,我们想要保存玩家和块,所以save当游戏即将退出时,让我们调用一个新功能:
while True:
...
for event in pygame.event.get():
if event.type == QUIT:
save(player, blocklist)
exit()
Run Code Online (Sandbox Code Playgroud)
实现非常简单(为简洁起见,没有错误处理):
def save(player, blocks):
f = shelve.open("save.bin")
f['player'] = player
f['blocks'] = blocks
f.close()
Run Code Online (Sandbox Code Playgroud)
如您所见,使用shelve就像使用一样简单dict.
下一步是加载我们保存的数据.
player, blocklist = load() or (None, [])
Run Code Online (Sandbox Code Playgroud)
我们调用一个新函数load,它将返回已保存的播放器对象的元组和已保存的块对象的列表,或者None.如果是None,我们还没有创建一个播放器,并为我们的块使用空列表.
实现就像功能一样简单save:
def load():
try:
f = shelve.open("save.bin")
return f['player'], f['blocks']
except KeyError:
return None
finally:
f.close()
Run Code Online (Sandbox Code Playgroud)
就是这样.
这是完整的代码:
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()
Run Code Online (Sandbox Code Playgroud)
在这里,您可以看到加载和保存操作:

请注意,您无法以Surfaces这种方式保存(或"pickle").在这段代码中,它的作用是因为Surfacesof Player和Block是类变量,而不是实例变量,因此不会保存到磁盘.如果你想用一个Surface实例变量"pickle"一个对象,你必须删除第Surface一个(例如设置为None)并再次加载它(例如在load函数中).
| 归档时间: |
|
| 查看次数: |
686 次 |
| 最近记录: |