Scene transfer, character and data.

These are a number of questions I have concerning approximately the same subject.

  1. The character is moving from scene 1 to scene 2 (for any reason. Like… the next level). The only way I know how to do this is to have a copy of the player character in each scene. The problem I have with this are object names.
    The systems I have set up require a lot of messages being sent between objects, so the messages are being sent to specific object names. This gets completely ruined when the copy of the player object(s) get duplicate names assigned to them like “player object”, “player object.0001” etc.
    Is there any solution to this besides tediously going through each message and changing the destination object?

  2. There are 100 health charms (name still WIP) scattered around a level. Collecting 100 health charms will grant the player 1 extra life. There must be EXACTLY 100 health charms per level, so the player can go back to a level and collect the ones that the player missed. Also, the number of collected health charms should accumulate, meaning that if the player collected 60 health charms in the previous level and then collects 40 in the next it will also result in an extra life.
    If the player got an extra life, the player should also keep that extra life for every scene (level) afterwards.
    Where do I even begin with this?

  3. Should all levels really be part of the same .blend file as different scenes? Is there a way to have levels as separate files and the objects within them also as separate files to be loaded in when the level loads?
    To my understanding, this is how every game has done it for a very long time.

Be aware that if you leave one scene and go back to it, it will have reset. That may ruin your plans regarding health charms.

Number 1:
Have a separate scene with just the player, and then add the player to a group.
Now in each level scene you can link the player in. Because it is linked, the objects in the player will share the same name.

Number 2:
You need something that isn’t a level to store the number of charms/lives in. You can do this with an overlay scene that is never removed when changing level (ie change scene with the replace scene actuator rather than the set scene actuator)

Number 3:
If it’s a small game with a small number of levels, then having the levels all part of the same file is fine. However, as soon as you have more than a few levels, or the levels start getting complex, then you start needing more complex solutions. Linking is immensely useful, and is my preferred way of doing things for mid-sized projects. You can link groups or scenes from on blend into another. So if you had a blend file for the player, you could link the player group into each level blend. Then at the end of each level, instead of running “Replace Scene” you run “Start Game” and specify the blend file path.
For larger projects, you may want to investigate more dynamic solutions such as LibLoad - but there lie dragons (You suddenly have to think through about a lot​ more things - and definitely need python)

There needs to be a way to make it work with health charms. This is kind of important to make the gameplay less boring and give the player a reward for getting to tricky and dangerous places.
Since the project is too big to have all the levels in a single .blend file, having a separate scene that stores data is not an option. The game is neither intended to be finished within a few minutes, the intention being a platformer with a whole bunch of levels to play. So there will be saving and loading involved. I have a strong feeling there should be a way to store the data about how many charms a player collected and how many charms are left per level in the player’s save data and also have it keep count how many charms the player already has collected across levels (.blend files).
There are logic bricks for saving and loading but they don’t give me any real options, so I assume there is a way to python around this (though I have no experience with python or scripting).

Thanks, by the way. Linking was what I was looking for. I knew how to do it but the quarter didn’t drop until you explained it ^^;

i libload in all my assets on blend start, then load new blends for each new area or level.

the bge.logic.globalDict stays persistent until the game is quit unless you save it. loading a globalDict that was not saved yet will gracefully fail (no errors if it cant find the file, just a notice).

create a list for each level in your dictionary:

bge.logic.globalDict["Powerups"] = {"L1":[], "L2":[]}

when the game starts or a level loads, the spawners should check if the have been collected:

if owner.name not in bge.logic.globalDict["Powerups"]["L1"]:
    charm = scene.addObject("charm", owner, 0)
    charm["Spawner"] = owner.name  # remember who spawned the charm
    charm["Collected"] = False

each time a charm is collected, add the name of the spawner to the level list:

if owner["Collected"] == True:
    bge.logic.globalDict["Powerups"]["L1"].append(owner["Spawner"])
    owner.endObject()

does that mean I don’t have to place my object at every scene

Alriiiigghht… I don’t know much about python, so please be patient with me as I try and understand what it all does ^^;

I’m assuming that “Powerups” is where the name of the health charm goes. So instead of “powerups” I call it whatever the object is called.
“L1” and “L2” are names of levels and I assume I have to replace them with names of the .blend files. I also assume I can add as many as I like as long as I separate them by commas.
What’s the rectangle symbol, though?
Also, what should contain the script? An empty in every level?

For the other two scripts, I assume I’ll have to cover the level in empties that spawn in the charms.
Does each empty need its own name? (i.e. spawner001, spawner002, etc). I assume that’s what “Spawner” means.
“scene.addObject(“charm”, owner, 0)” I assume this spawns the charms, so I won’t have to do that with logic bricks. If I’m correct, “charm” I should replace with the object name of the health charm. Does it matter if it’s on another layer?
What is “Collected”? Is that an object or another script?
My idea is to have the charm add +1 to a property when collected. Once the property value reaches 100 the player will gain an extra life and the property will reset to 0. The property value should be carried over across levels. Not sure what “Collected” is/does and how that plays in with this.

i think ill setup a sample blend to get you started on using python, and to work out kinks. there are a few big issues i havent mentioned, like knowing what level dataset to use.

spawner empties should be just like any blender object, each having a unique name. the “Spawner” property is auto filled by actual object name.

the [ ] means a new empty python list. a populated list = [1, 2, 3]

you are correct about the addObject(). any and all objects that need to be added can NOT be on a selected layer.

“Collected” property is just a simple way of telling the script its been collected by the player. that way you can keep your pickup logic.

it is possible to have a builder empty that looks for all objects in the scene with a certain name and run spawn logic. vs having to add logic to all the spawners individually. i use “SPAWN.object.001”, it looks for SPAWN in the name, then adds “object”, and “001” is just for uniqueness.

the “Powerup” name is arbitrary, like naming a folder. whatever name means something to you. just make sure its consistent across your code. you can create as many of these folders in your globalDict as you want.

NOTE: the globalDict is picky about what goes in there. only plain numbers and strings really. lists, dictionaries, and tuples are ok too.

if I were to be changing scenes…I would simply hold all the variables in the player object, write it all to a script on leave-scene…> create player > write variables(init) to the player and just continue on…if it is all self contained it will be much easier to handle…plus you can keep a simple per scene entity list in player variables(properties)… but the important thing is to uninitiate the player and reinitiate during scene changes…all other scripts should not be running if the player does not exsist.

There are a million other ways to do it, I am just trying to point out the simplest and most straight forward method…this is ofc only my opinion.

So after some thinking I’ve narrowed down the exact things that need to be saved (assuming, and preferring, these things all to be written in the same save file).
-Player position.
-3 player properties, including lives, maximum lives and collected health charms.
-The charms that have been collected so far and the locations they have been collected at.
The idea is that these things get saved whenever the player character reaches a checkpoint, and not continuously.

@Daedalus_MDW,
I’d really love to try your method for saving the charms that got collected. I have a vague idea of what to do, but no idea where to begin.
(Take your time, though. It’s only just new year ^^)

Bump.
This is REALLY important…

i would have 1 blend with all overlay scenes. That scene libloads all the blends. Now we can store all the data in one of the overlay scenes(hud for example), and to save it you can use a save/load system.

you can find everything you need in the resource section, or in my sig.

Alright, I’ll take a look.

Point 2) I strongly suggest to setup a save/load system.

You will need it anyway to let a player leave the game and return at the last stage (or just to allow loading an old state).

Store/Restore Scene states
You can use a save/load system to store the state of a scene when the player leaves it. This way you can restore it’s state when the player return to the scene [it is a new scene, but loaded from the same original!].

Store/Restore Character States
A save/load system can be used to transfer status of the character when switching to other scenes. E.g. when the character wears an hat in one level, you typically still want it to wear an hat at the next level until the character put it off.

Be aware due to it’s dynamical behavior a save/load system needs to be implemented in python. You can’t store all scene data (e.g. the current frame of an action actuator in play mode can’t be applied). Sou you need to avoid “unrestorable” states to be noticeable by the audience.

Hint:
Have a look at SaveLoader. You do not need to use this one, but the thread explains some principles.

I realized it very quickly that I was basically talking about saving/loading and that’s what the conversation pretty much turned into.
The scene state saving seems to be what I’m looking for.
Question: Does this also save object states? For instance, can I switch an object from state 1 to state 2 and will it be loaded in at state 2?
EDIT: So I tried your demo, but attempting to load causes Blender (latest version) to completely crash to desktop.

@Cotaks
Been playing around with your save/load script, trying to implement it into my test map scene.
Doesn’t seem to like that very much…



My character, Nach, has the physics box “Nach Phys”. Everything of my chracter (like bones, various empties and the main camera) are parented to Nach Phys.
The the entire character is linked, not appended, from another .blend file. Is this what is causing the problem?

The the entire character is linked, not appended, from another .blend file. Is this what is causing the problem?

as long as the blends get loaded before you use the save and load script everything should be fine. I use libload for quite a while now and saving/loading is not a problem.

your error indicates that NachPhys cannot be found, so do you link it in an hidden layer or from the main layer?
As i see the saving output you have it on an hidden layer, if not then that is causing your problem.

Player character, saving, loading is all on the same layer in the same scene:


I would post the .blend file but I don’t know how to do that with linked objects involved.

Read the description, object from main layer need property save -> false
from an inactive layer needs save -> true.

could it be that you got it at true on the object?

My script works like this:
every object in main layer gets updated. (load in data from our save file)
every object in hidden layer, get removed from the main layer and then it will be freshly spawned and loaded with the data from the save file.

Ok, I feel stupid now. I was following the instructions and knew what to do but I just overlooked that one tiny detail -_-
Anyway, it seems to be working now. I’ve managed to save position, health and pick up count properties.
I’m going to play around with the saving and loading. What I need now is it to load only those pick ups that I haven’t collected yet, even after I would leave the level, save in a different level and come back later, though I’m getting a strong feeling I need a separate save file for that. One per level that loads in at the same time as the level.

I would post the .blend file but I don’t know how to do that with linked objects involved.

if ever needed, then just .zip it. (best is to make a demo file with the problem)

Ok, I feel stupid now. I was following the instructions and knew what to do but I just overlooked that one tiny detail -_-

i have given you a hint :wink:

“As i see the saving output you have it on an hidden layer, if not then that is causing your problem.”

What I need now is it to load only those pick ups that I haven’t collected yet, even after I would leave the level, save in a different level and come back later, though I’m getting a strong feeling I need a separate save file for that. One per level that loads in at the same time as the level.

for coins/charms etc, this is not so hard. just spawn in the coins give it a save property(true). now if you collect a coin/charm you delete it(endObject()) then whenever you save your game the deleted charms are not loaded anymore.

Yes, you can store/restore the state of a game object. It is the state attribute:


stateToBeStored = gameObject.state

....

gameObject.state = stateToBeRestored

(state is an int)