2
$\begingroup$

I probably need the help of a Python script to make this work.

What I want is: The player will be able to save and turn off the game, but continue from where they saved when they next log in. Items such as gold, weapons, etc. must be stored.

It feels like something hard to do and I am not managing to figure it out alone. Although I love problems and solving them, in this case I need help.

I know that BSE People should not ask more questions.

But.

Is this stupid or must I have several Scenes in my game. Say that my player goes into a house. Should the house then be in another Scene, or should I move camera and player to inside the house from the same Scene?

Any advice would be very helpful. I have no one near me whom I can ask.

// Robin W

$\endgroup$
1
  • 1
    $\begingroup$ So have multi scene is for the best. its a Zelda spin off thing, Open world. but when enter a new area it will been in a other scene. Thanks. ( this time without google translate...) (hope you can understand.) $\endgroup$ May 24, 2016 at 21:43

2 Answers 2

1
$\begingroup$

you didn't specify what exactly you want to save :(


I added two custom properties to the default cube :
-an integer to store the score
-a string to store the player's name

enter image description here

for testing I will use the key S to save our properties and L to load,this is done by calling their respective method that we will define inside a script I named here script.py.

enter image description here

so , now we just have to write the script. in the text editor add a new file , I named it script.py

import bge

def save(cont):

    score = cont.owner['score']
    name = cont.owner['name']
    path = bge.logic.expandPath("//")

    if cont.sensors['save'].positive:
        with open(path + "save.txt" , 'w' ) as f:
            f.write("{0},{1}".format(str(score) , name) )


def load(cont):

    path = bge.logic.expandPath("//")    
    if cont.sensors['load'].positive:
        with open(path + "save.txt" , 'r' ) as f:
            line = f.read()
            vars = line.split(',')
            cont.owner['score'] = int(vars[0])
            cont.owner['name']  = vars[1]

you can also save and load without a script using the global dictionary

enter image description here

$\endgroup$
3
  • 1
    $\begingroup$ Thank you very much. I will test this and see. what I want to save is. gold that the player pick up. and weapons, Armor like a shield. And I can not make the save bge.logic.globalDict to work. I set up like this... when press keyboard (S) it will save. But when I try to load it. Nothing happen... (again without google translate I try my best) $\endgroup$ May 24, 2016 at 21:49
  • $\begingroup$ I edited my answer, it should work fine now. $\endgroup$
    – user2816
    May 25, 2016 at 7:40
  • $\begingroup$ This one Work perfekt. thank you again. Now I can continue with my game. I have already make sure that I can transform the script/module to scene to scene. It can´t not be more perfect then that. This make me happy. $\endgroup$ May 26, 2016 at 10:24
3
$\begingroup$

I suggest to abstract the requested features into different aspects of your game

  • Storage
  • Persistence

Storage

Convert game states into store-able data and back.

Store

  • extract the states from your game (positions, properties, animation frame ...)
  • convert it into a storable format (e.g. strings, lists, ...)
  • store it into a storage

Example:

import bge

storage = bge.logic.globalDict # globalDict is a predefined storage provided by the BGE

def store():
    playerStorage = {}
    storage["player"] = playerStorage # create a storage in storage

    player = bge.logic.getCurrentScene().objects["Player"]
    playerStorage["position"] = list(player.worldPosition)
    playerStorage["health"] = player["health"]

This is just a very simple example demonstrating a basic storage system. When you have more data, you will need a much more complex data structure to keep all the states of all the different objects.

You do not need to use bge.logic.globalDict. You can create your own storage (similar to playerStorage).

Do not store any references to data that can't be persisted such as KX_GameObjects, KX_Scene, Vector. You need to extract the data that can be applied to a different object later.

Beside game states you need to store enough data to uniquely identify target objects for later restore. In the example it is the key "player" assuming this data is from an object called "Player". [Object names are not unique, so you need to store additional data].

Restore

Is the reverse of Store.

  • read the data from storage
  • convert it to game states
  • identify the game objects it belongs to
  • apply it to that objects

Be aware the objects you stored the data from are not necessarily the same objects you will restore it to. If that sounds confusing: Imagine you restarted the scene. This means the original scene is gone and all of it's objects are dead. But you created and loaded a new scene with new objects that look the same. But they are different object.

The objects do not even need to be equal. E.g. you stored the data of a walking character (e.g. health). Then you restore the data to a vehicle as the character is sitting inside the vehicle.

Identifying objects can be tricky. In most cases the object name is sufficient enough.

Example:

import bge

storage = bge.logic.globalDict

def restore():
    playerStorage = storage["player"] # will result in error if nothing was stored before
    player = bge.logic.getCurrentScene().objects["Player"]
    player.worldPosition = playerStorage["position"]
    player["health"] = playerStorage["health"]

In this example we assume that data from storage "player" should be applied to an object called "Player". The above operations assume these data exist. Otherwise the processing will return an error. You need to apply a proper error handling.

Usage

Store and Restore are useful within several situations:

  • pre-step of persistence
  • scene switch by keeping game states of related objects (such as player stats)
  • object occlusion (objects out-of-sight are removed - and re-added when coming into sight again)
  • network communication

Persistence

Often referred as Save/Load. It means you ensure the game states persist without a running game session. A typical situation is to persist the game states to a file.

There are several different ways to implement such a system. A very simple one is to use the build-in Persistence via GameActuator:

Save

The GameActuator in Save mode marshals the data from bge.logic.globalDict into a file called <your-blend-file's-name>.bgeconf.

Example: enter image description here

You simply activate the actuator and the BGE persists the previously stored globalDict to file.

Be aware this overwrites any previously saved data!

Load

The GameActuator in Load mode replaces the content of globalDict with the content from file <your-blend-file's-name>.bgeconf.

enter image description here

Be aware: the complete globalDict will be overwritten! A missing .bgeconf file will show a warning in the console.

All together

Now you have all the aspects together. You always need to consider the timing. This means you better store before save, restore after load. You always have the option to skip the persistence (e.g. on scene switch).

Advanced

The above examples are very simple. You will need to establish you very own storage. You might even want several different storage objects.

Always be sure what you store where.

Do not mix storage with other purposes (e.g. managing an inventory via globalDict). This will sooner or later result in heavy design issues.

The python part can become quite a lot of code. I suggest you do some training first to be able to manage that.

There are other ways to persist data. E.g. you can pickle the data via Python and save the pickled data to file. This supports more data formats than marshalling. E.g. you can store custom classes.

I hope it helps

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .