Save a list of objects on exit of pygame game [closed]

2024/10/5 17:16:07

So I have a list of defined classes that gets exported on the exit of the program.. and it looks like this:

<__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>

Perfect! Right? Now I should easily be able to convert that to a list.. So I use this:

x=x.split(",")

And it converts it to a list yes, but it turns the classes into strings! Making them un-usable.

Basically what I need is to "suspend" the state of the game within a file when it is closed, and then reload it upon opening it.

So how can I do this without converting the class names to strings?

Answer

Perfect! Right?

Sadly, no. What you see here (<__main__.Block object at 0x02416B70>) is a typical string representation of a class instance. It's just a simple string, and there's no way to convert this string back to an instance of of Block.

I assume you're still on this game from your last question.

So how do you actually persist the state of the game? The easiest way is to use the standard python module pickle or shelve.

In the following example, I'll use shelve, because you don't use a single class to represent the game state:

A “shelf” is a persistent, dictionary-like object. ... the values ... in a shelf can be essentially arbitrary Python objects ... This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings.

First of all, when we exit the game, we want to save the player and the blocks, so let's call a new save function when the game is about to exit:

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

The implementation is quite easy (no error handling for brevity):

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

As you see, using shelve is as easy as using a dict.

Next step is loading our saved data.

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

We call a new function load which will either return a tuple of the saved player object and a list of the saved block objects, or None. In case of None, we don't create a player yet and use an empty list for our blocks.

The implementation is as simple as the save functon:

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

And that's it.

Here's the complete code:

import pygame,random
from pygame.locals import *
from collections import namedtuple
import shelvepygame.init()
clock=pygame.time.Clock()
screen=pygame.display.set_mode((640,480))max_gravity = 100class 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 jumpself.on_ground = Trueself.xvel = 0self.yvel = 0self.jump_speed = 10self.move_speed = 8def update(self, move, blocks):# check if we can jump if move.up and self.on_ground: self.yvel -= self.jump_speed# simple left/right movementif move.left: self.xvel = -self.move_speedif move.right: self.xvel = self.move_speed# if in the air, fall downif not self.on_ground:self.yvel += 0.3# but not too fastif self.yvel > max_gravity: self.yvel = max_gravity# if no left/right movement, x speed is 0, of courseif not (move.left or move.right):self.xvel = 0# move horizontal, and check for horizontal collisionsself.rect.left += self.xvelself.collide(self.xvel, 0, blocks)# move vertically, and check for vertical collisionsself.rect.top += self.yvelself.on_ground = False;self.collide(0, self.yvel, blocks)def collide(self, xvel, yvel, blocks):# all blocks that we collide withfor 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.leftif 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.topself.on_ground = Trueself.yvel = 0# if yvel < 0 and a collision occurs, we bumped our head# on a block above usif yvel < 0: self.rect.top = block.rect.bottomcolliding = False
Move = namedtuple('Move', ['up', 'left', 'right'])def load():try:f = shelve.open("save.bin") return f['player'], f['blocks']except KeyError:return Nonefinally:f.close()def save(player, blocks):f = shelve.open("save.bin") f['player'] = playerf['blocks'] = blocksf.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)*32y=(int(mse[1]) / 32)*32blocklist.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)*32y=(int(mse[1]) / 32)*32blocklist.append(Block(x+16,y+16))elif event.button == 3:x=(int(mse[0]) / 32)*32y=(int(mse[1]) / 32)*32player=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()

And here you can see loading and saving in action:

enter image description here

Note that you can't save (or "pickle") Surfaces this way. In this code, it works because the Surfaces of Player and Block are class variables, not instance variables, and thus don't get saved to disk. If you want to "pickle" an object with a Surface instance variable, you would have to remove the Surface first (e.g. setting it to None) and load it again (e.g. in the load function).

https://en.xdnf.cn/q/119902.html

Related Q&A

Trying to make loop for a function that stops after the result is lower than a certain value

Im taking a beginner python class and part of an exercise we were given was this:The point x with the property x= sin(x)−ax+ 30 is called a fixed point of the function f(x) = sin(x)−ax+ 30. It can b…

python url extract from html

I need python regex to extract urls from html, example html code :<a href=""http://a0c5e.site.it/r"" target=_blank><font color=#808080>MailUp</font></a> <…

Regex match each character at least once [closed]

Its difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying thi…

How to cluster with K-means, when number of clusters and their sizes are known [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.Want to improve this question? Update the question so it focuses on one problem only by editing this post.Closed 1…

Converting German characters (like , etc) from Mac Roman to UTF (or similar)?

I have a CSV file which I can read in and at all works fine except for the specific German (and possibly other) characters. Ive used chardet to determine that the encoding is Mac Roman import chardetde…

Caesar cipher without knowing the Key

Hey guys if you look at my code below you will be able to see that i was able to create a program that can open a file decode the content of the file and save it into another file but i need to input t…

how to convert u\uf04a to unicode in python [duplicate]

This question already has answers here:Python unicode codepoint to unicode character(4 answers)Closed 2 years ago.I am trying to decode u\uf04a in python thus I can print it without error warnings. In …

How can I display a nxn matrix depending on users input?

For a school task I need to display a nxn matrix depending on users input: heres an example: 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0(users input: 5) And here is my code until now:n = int(inpu…

How to launch 100 workers in multiprocessing?

I am trying to use python to call my function, my_function() 100 times. Since my_function takes a while to run, I want to parallelize this process. I tried reading the docs for https://docs.python.org/…

Indexes of a list Python

I am trying to find how to print the indexes of words in a list in Python. If the sentence is "Hello world world hello name") I want it to print the list "1, 2, 2, 1, 3")I removed a…