Run code on game quit without overwriting ESC key

One frustration I’ve often had is that inside the embedded player, the python shell is maintained. This means that if you put something in bge.logic.GlobalDict, it will not be removed when the game quits, but only when the next game starts.
Couple that with the fact that theres no built in method to run a function when the game ends, and you can end up (particularly with multi-threaded applications) with it being very awkward to tidy up resources at the end of a game.

The solution? The RunOnPowerOff class:


class RunOnPowerOff(object):
    '''Runs a function when the scenario ends. Put it in a game object
    property'''
    def __init__(self, function):
        self.function = function


    def __del__(self):
        self.function()

How to use it:
Store it in a game object’s property. Make sure no variables ever reference it. Load it with a function:


def end_game():
    print("Game Ended")

obj = bge.logic.getCurrentScene().objects['some_name']
obj['RUNONPOWEROFF'] = RunOnPowerOff(end_game)

Why it works?
Python’s builtin del works well, but if you have circular references then python doesn’t call del. So by having a minute class that you never refer to in code - and thus the only reference will be from an in-game object, you know that del will be called reliably.

Be aware that many BGE things are in a weird state when the end_game function is called. So don’t try to delete in-game objects, remove scenes or so on.

Wow that’s really clever and I probably wouldn’t have ever thought of that myself.

You can also store the class reference into a global variable.


import bge

class Quit():
    def __init__(self):
        print("init")

    def __del__(self):
        print("del")

bge.logic.IQuit = Quit()

Thanks for the tips

I wonder if this is the source of some trouble I’ve been having with the texture class. If I create, link or load a texture then the game will crash on exit if I don’t del it before exiting.

I wonder if this is the source of some trouble I’ve been having with the texture class. If I create, link or load a texture then the game will crash on exit if I don’t del it before exiting.

Create a sample file and submit a bug report…
But yeah, there is pain in dynamic loading and crashes.

You can also create a custom mainloop script, and run your cleanup code at the end.

Custom mainloop scripts have several limitations - particularly when you jump through 5-10 different blend files as part of your game’s usual operation…

Should be fine as long as you use an entry file. What problems do you encounter?


from bge import logic, events
from time import clock


accumulator = 0.0
dt = 1 / logic.getLogicTicRate()
last_time = clock()


logic.on_cleanup = []


running = True
while running:
    now = clock()
    elapsed = now - last_time
    last_time = now


    accumulator += elapsed
    while accumulator > dt:
        accumulator -= dt
        
        logic.NextFrame()
        dt = 1 / logic.getLogicTicRate()


        if logic.getExitKey() in logic.keyboard.active_events:
            running = False
            break




for f in logic.on_cleanup:
    f()