Pygame:保存对象/类/表面的列表
Posted
技术标签:
【中文标题】Pygame:保存对象/类/表面的列表【英文标题】:Pygame: Save a list of objects/classes/surfaces 【发布时间】:2013-10-25 11:40:08 【问题描述】:我正在开发一款游戏,您可以在其中创建迷宫。您将块放置在 16x16 网格上,同时从各种块中进行选择以制作关卡。每当您创建一个块时,它都会添加此类:
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
到一个名为instances
的列表。
我尝试将它搁置到 .bin 文件中,但它返回一些处理表面的错误。如何保存和加载关卡?
感谢任何帮助! :)
这是整个代码供参考:
import pygame
from pygame.locals import *
#initstuff
pygame.init()
screen=pygame.display.set_mode((640,480))
pygame.display.set_caption('PiMaze')
instances=[]
#loadsprites
menuspr=pygame.image.load('images/menu.png').convert()
b1spr=pygame.image.load('images/b1.png').convert()
b2spr=pygame.image.load('images/b2.png').convert()
currentbspr=b1spr
curspr=pygame.image.load('images/curs.png').convert()
curspr.set_colorkey((0,255,0))
#menu
menuspr.set_alpha(185)
menurect=menuspr.get_rect(x=-260,y=4)
class MenuItem(object):
def __init__(self,pos,spr):
self.x=pos[0]
self.y=pos[1]
self.sprite=spr
self.pos=(self.x,self.y)
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
while True:
#menu items
b1menu=b1spr.get_rect(x=menurect.left+32,y=48)
b2menu=b2spr.get_rect(x=menurect.left+64,y=48)
menuitems=[MenuItem(b1menu,b1spr),MenuItem(b2menu,b2spr)]
screen.fill((20,30,85))
mse=pygame.mouse.get_pos()
key=pygame.key.get_pressed()
placepos=((mse[0]/16)*16,(mse[1]/16)*16)
if key[K_q]:
if mse[0]<260:
if menurect.right<255:
menurect.right+=1
else:
if menurect.left>-260:
menurect.left-=1
else:
if menurect.left>-260:
menurect.left-=1
for e in pygame.event.get():
if e.type==QUIT:
exit()
if menurect.right<100:
if e.type==MOUSEBUTTONUP:
if e.button==1:
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
for i in to_remove:
instances.remove(i)
if not to_remove:
instances.append(Block(placepos[0],placepos[1],currentbspr))
for i in instances:
screen.blit(i.sprite,i.rect)
if not key[K_q]:
screen.blit(curspr,placepos)
screen.blit(menuspr,menurect)
for item in menuitems:
screen.blit(item.sprite,item.pos)
if item.rect.collidepoint(mse):
if pygame.mouse.get_pressed()==(1,0,0):
currentbspr=item.sprite
pygame.draw.rect(screen, ((255,0,0)), item, 1)
pygame.display.flip()
【问题讨论】:
【参考方案1】:你不能序列化/pickle/搁置 pygame 的 Surface
对象(至少不是不费力气)。所以你的问题的答案是:不要尝试序列化你的表面(无论如何它只会浪费磁盘空间)。
例如,您可以创建一个简单的dict
来存储您的表面,并让您的类只存储密钥,例如:
menuspr=pygame.image.load('images/menu.png').convert()
b1spr=pygame.image.load('images/b1.png').convert()
b2spr=pygame.image.load('images/b2.png').convert()
currentbspr=b1spr
curspr=pygame.image.load('images/curs.png').convert()
curspr.set_colorkey((0,255,0))
# create a dict to store all surfaces
surf_dict = 'b1spr': b1spr,
'b2spr': b2spr,
'currentbspr': currentbspr,
'curspr': curspr
...
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
# self.sprite is no longer a Surface, but a str
self.rect=surf_dict[self.sprite].get_rect(x=self.x,y=self.y)
...
...
# don't pass the surface to the Block, just the key
instances.append(Block(placepos[0],placepos[1], 'currentbspr'))
...
for i in instances:
# get the Surface from the dict, not from the instance itself
screen.blit(surf_dict[i.sprite],i.rect)
现在您可以节省地尝试腌制/搁置所有Block
-instances(我看到您提出了一个相关问题here)。
【讨论】:
【参考方案2】:我自己找到了解决方法。我使用python内置的open(fname,mode)
创建了一个关卡文件。
每当创建一个块时,它都会获取该块的精灵名称和坐标,并将其以 .bin 格式添加到保存文件中:
f.write('Block('+str(placepos[0])+','+str(placepos[1])+',b1spr).')
然后我创建了一个函数来读取它,并相应地创建关卡:
def CreateLevel(levelname):
f=open(levelname,'r')
obj=f.read()
f.close()
obj=obj.split('.')
for b in obj:
instances.append(eval(b))
而且效果很好!
这是整个代码,谢谢大家的帮助。
import pygame
from pygame.locals import *
#initstuff
pygame.init()
screen=pygame.display.set_mode((640,480))
pygame.display.set_caption('PiMaze')
instances=[]
level='save.bin'
#loadsprites
menuspr=pygame.image.load('images/menu.png').convert()
b1spr=pygame.image.load('images/b1.png').convert()
b2spr=pygame.image.load('images/b2.png').convert()
b3spr=pygame.image.load('images/b3.png').convert()
currentbspr=b1spr
curspr=pygame.image.load('images/curs.png').convert()
curspr.set_colorkey((0,255,0))
#menu
menuspr.set_alpha(185)
menurect=menuspr.get_rect(x=-260,y=4)
class MenuItem(object):
def __init__(self,pos,spr):
self.x=pos[0]
self.y=pos[1]
self.sprite=spr
self.pos=(self.x,self.y)
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
def CreateLevel(levelname):
f=open(levelname,'r')
obj=f.read()
f.close()
obj=obj.split('.')
for b in obj:
instances.append(eval(b))
try:
CreateLevel(level)
except:
pass
f=open(level,'a+')
while True:
#menu items
b1menu=b1spr.get_rect(x=menurect.left+32,y=48)
b2menu=b2spr.get_rect(x=menurect.left+64,y=48)
b3menu=b3spr.get_rect(x=menurect.left+96,y=48)
menuitems=[MenuItem(b1menu,b1spr),MenuItem(b2menu,b2spr),MenuItem(b3menu,b3spr)]
screen.fill((20,30,85))
mse=pygame.mouse.get_pos()
key=pygame.key.get_pressed()
placepos=((mse[0]/16)*16,(mse[1]/16)*16)
if key[K_q]:
if mse[0]<260:
if menurect.right<255:
menurect.right+=1
else:
if menurect.left>-260:
menurect.left-=1
else:
if menurect.left>-260:
menurect.left-=1
for e in pygame.event.get():
if e.type==QUIT:
f.close()
exit()
if menurect.right<100:
if key[K_LSHIFT]:
if pygame.mouse.get_pressed()==(1,0,0):
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
if not to_remove:
instances.append(Block(placepos[0],placepos[1],currentbspr))
f.write('Block('+str(placepos[0])+','+str(placepos[1])+',b1spr).')
to_remove = []
if not key[K_LSHIFT] or key[K_RSHIFT]:
if e.type==MOUSEBUTTONUP:
if e.button==1:
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
for i in to_remove:
instances.remove(i)
if not to_remove:
instances.append(Block(placepos[0],placepos[1],currentbspr))
f.write('Block('+str(placepos[0])+','+str(placepos[1])+',b1spr).')
if key[K_RSHIFT]:
if pygame.mouse.get_pressed()==(1,0,0):
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
for i in to_remove:
instances.remove(i)
to_remove=[]
for i in instances:
screen.blit(i.sprite,i.rect)
if not key[K_q]:
screen.blit(curspr,placepos)
screen.blit(menuspr,menurect)
for item in menuitems:
screen.blit(item.sprite,item.pos)
if item.rect.collidepoint(mse):
if pygame.mouse.get_pressed()==(1,0,0):
currentbspr=item.sprite
pygame.draw.rect(screen, ((255,0,0)), item, 1)
pygame.display.flip()
【讨论】:
以上是关于Pygame:保存对象/类/表面的列表的主要内容,如果未能解决你的问题,请参考以下文章