You need to store and restore the game state.
Game State
The game state are all changes to the game that happens while playing the game. This includes the position of the camera as well as the currently played pose of an action as well if a menu is visible or not.
In general the game state is covered by the active scenes. When you remove a scene all states from that scene will get removed too.
-> imagine you moved the default cube from (0,0,0) to (2,0,0). You remove the scene ... the cube will be removed together with the changed position and everything else in the scene. There is no way to recover that information.
Storing
As the scene will get lost you can't use the scene as storage. Alternative storage is:
- other scenes (exist as long as the other scene exist)
- messages (exist for a single frame, can store a single string)
- python modules (exist until the module get unloaded or the game ends)
- files (exist longer than the game session)
In all cases you will need Python to at least restore the data.
This answer will focus on using python modules as storage as this is the most flexible and generic storage (beside keeping the scene alive).
Python module storage
Advantages:
- the storage lives until the game session ends
- accessible from any active scene
- fast read
- fast write
(Do not confuse python modules with python scripts - scripts will not persist!)
Basically you write the data to be stored into a module attribute.
storage = "I'm a string to be stored"
The storage has to be at module level (no indentation)
Alternative you can write to a module attribute from within a function:
def demonstrateStoring(dataToBeStored):
global storage
storage = dataToBeStored
...
demonstrateStoring("I'm a string to be stored")
...
Do not forget keyword global
!
Typically you want to store more than a single object. The easiest way is to create a separate object that acts as "sub-storage". It can be any container.
Example usable at your situation
Here I suggest to use a dictionary. It allows you to access the data by a key such as a string:
[Module]
storage.py
- do not set it up at the python controller directly
storage = {}
def put( key, data ):
storage[key] = data
def get(key, fallback=None):
return storage.get(key, fallback)
[Script]
store_audio_already_played
import storage
storage.put("audio already played", True)
[Script]
activate_when_audio_never_played
import storage
import bge
if not storage.get("audio already played", False):
controller = bge.logic.getCurrentController()
for actuator in controller.actuators:
controller.activate(actuator)
This example is already a solution to your question. What will happen:
A) when the start-up scene gets loaded you check if the storage contains the key "audio already played". At the first run it should not be present. The above script activate_when_audio_never_played
will activate all actuators (including your audio actuator).
B) You need to run the script store_audio_already_played
after A). Either you place the controller below the controller of A) or you activate the controller at the second frame of the scene. The last one would be better. That way you can be sure it was played at least a little bit.
This one does not need actuators as it acts as actuator already.
Finally that is all.
Process flow:
frame 1 - startup scene:
- always sensor triggers controller
activate_when_audio_never_played
- controller checks storage for "audio already played"
- "audio already played" not present
- activate actuators
- audio get played
frame 61 - startup scene (after 1 second):
- delay sensor triggers controller
store_audio_already_played
- controller stores True with key "audio already played"
frame 61 + t - startup scene:
frame 61 + t + s - any scene:
frame 61 + t + s +1 - startup scene:
- always sensor triggers controller
activate_when_audio_never_played
- controller checks storage for "audio already played"
- "audio already played" is present
- no actuators get activated
- no audio get played
I suggest to evaluate the process flow when the scene gets switched before frame 61.
Remarks
The module storage is quite powerful. You can store any object your like. You can store as many objects you like. You can even store other containers (such as lists and dicts) in the storage.
It is important to note that you should not store data that can be destroyed such as game objects. You can store them but as soon as you switch scenes your storage will refer to invalid objects (see: KX_GameObject.invalid). It is better to avoid them.
Such a storage can easily be used to create save points. Save points contain the data at the moment of creating them. On request you can restore this data back to scene.
Typically you can save a storage to a file (saving) and load it within the same or another game session (loading). This way the data survives ending the current game. [Assuming you do not store objects that can't be restored such as KX_GameoObject or mathutils.Vector].
You can never "return" to a scene. When you removed it the scene and all of the changes are gone. You can load a scene from the same source. It looks equal as it is constructed the same way. But it is a completely new scene. Any changes of the other (dead) scene will not be present in the new scene.