I have made quite a lot of progress on a game, and I have hit a brick wall, I have little knowledge of python, and I need to be able to save a property to a text file and load property from the text and over write it onto the original object.
I would really appreciate any feedback, and if you want, I will post my blend.
# Using simple text IO.
# some_string is the value you wish to save.
# some_path is the path of the new simple text file.
>>>with open(some_path,'wb') as f_out:
>>> f_out.write(some_string)
# To read the value back.
>>>with open(some_path,'rb') as f_in:
>>> some_string = f_in.read()
# The pickle module is a better solution here though, because you can
# store anything, dictionaries, instances of custom classes, you name it.
# Its most simple usage follows.
# my_obj is some object I want to pickle.
>>>import pickle
>>>with open(some_path,'wb') as f_out:
>>> pickle.dump(my_obj,f_out)
# And to read it back...
>>>import pickle
>>>with open(some_path,'rb') as f_in:
>>> my_obj = pickle.load(f_in)
Simple file objects are documented here.
Check out the pickle module documentation here.
You’ll also probably not want to blindly try to open files.
That is to say you want to trap errors.
# Adding to the example of reading the string file.
# I wrap the I/O in a try..except block
# to make sure that reading a non-existent file
# doesn't crash my game, or fail silently, which
# can be worse.
>>>try:
>>> with open(some_path,'wb') as f_out:
>>> f_out.write(some_string)
>>>except IOError:
>>> print("File not found (%s)"%some_path)
# Note that a naked "except:" is frowned upon.
Sure, here’s a simple example of pickling an object’s worldPosition.
(I’ve shown the script here for discussion’s sake. I wrote the attached blend file with the most recent 2.55 beta)
# Hello!
# Simple pickling demo.
# Use the arrow keys to move the mighty default cube about.
# Press S to save its position to 'cube_coords.tmp'
# in the current directory.
# Press L to load the saved position.
import pickle
import os
import bpy
import bge
import mathutils
def main():
# First, I set the current working directory this blend's directory.
blend_path = bpy.context.blend_data.filepath
os.chdir(os.path.dirname(blend_path))
# Get the objects and sensors.
cont = bge.logic.getCurrentController()
own = cont.owner
save_sense = cont.sensors['save_sense']
load_sense = cont.sensors['load_sense']
# Load routine.
if load_sense.positive:
try:
with open('cube_coords.tmp','rb') as f_in:
# I need the Vector object from mathutils to
# plug into the KX_GameObject's worldPosition.
own.worldPosition = mathutils.Vector(pickle.load(f_in))
except IOError:
print('File not found.')
# Save routine.
elif save_sense.positive:
with open('cube_coords.tmp','wb') as f_out:
# Blender wouldn't let me save a Vector object.
# Presumably because it isn't a pure Python object.
# So I converted it into a tuple.
pickle.dump(tuple(own.worldPosition),f_out)
main()
Here’s how to do the same thing as lightweight as possible. I’ve commented it out heavily to try and describe everything as best I could!
I hope you’re able to learn from this
## first off let's go ahead and create a dictionary to store all of our variables.
## dictionaries are the best solution as they allow you to continually store "virtual"
## variables and load them at any time!
variables = {}
## now let's go ahead and create some variables, you can create how ever many you'd like
## and put whatever you'd like in them (ie: strings,integers,floats, ever another dictionary!)
money = 10
health = 50
xp = 200
level = 2
## now let's go ahead and insert those variables we created inside the dictionary "variables"
variables["money"] = money
variables["health"] = health
variables["xp"] = xp
variables["level"] = level
## finally we're going to go ahead and save that data to a file! Let's open a file in write mode.
f = file("mysavedata.dat","w")
## in order to write out dict to a file we're going to need to convert it to a string, then write.
f.write(str(variables))
## close the file to save memory.
f.close()
## loaaaaddddiiiinngggg!!!!
## that's right! Time to load that data back into a readable dictionary!
## let's start by opening our file in read mode this time.
f = file("mysavedata.dat","r")
## the reason we use exec is simply to convert our dictionary (which we turned into a string)
## back into a dictionary. Think of it as a way to create dynamic variables.
exec("variables = " + f.read())
f.close()
## now to retrieve a variable we simply call the method below with our desired variables name.
money = variables["money"]
## if we want to assign that value to a property we simply call
myobject["myprop"] = variables["money"]
Yep. Killer’s solution is perfect for collections of generic types. Generic file IO is there for a reason, and it works great.
Pickle, and its cousin cpickle, are serialization modules that perform quite well with large and complex objects. With, as you can see, very little extra code. It scales very well also. For instance, in my own code, I’d probably be using a GameCharacter class to group xp, hp, as well various behaviors.
Thanks for the scripts, but I cant get them to work.
the myobject[“myprop”] = variables[“money”] keeps coming up with the error: NameError name ‘module’ is not defined
(I replaced the “myobject” with the name of the object that the script was running on, and I replaced the “myprop” with the property “points”, which was on the module object.)
also how do you assign the variables to a property?
Thanks for all the feedback!
and if its not to much to ask, could you make a blend?
thanks killer.
No problem. Just let me know what paypal account I can invoice for my time
just kidding, I enjoy writing code for other people. Because it actually gets finished, and I learn. When I write code for myself I constantly change my mind and add new stuff, it never gets anywhere and I don’t feel accomplished.