Help with assigning data through scenes so it won't be "freed"

Hello again!

I have a animation module that is set of for my character. in transition to scenes it stop working because the data was destroyed apon the next scene. I can anyone give the best practices to not allow this not to happen. help me organize the code better. I’m trying to get better habits. How should I set the property? thanks!


from bge import logic

cont = logic.getCurrentController()
own = cont.owner


act_up = cont.actuators['lookingup']
act_goingup = cont.actuators['goingup']
act_down = cont.actuators['down']
act_fall = cont.actuators['fall']
act_edge = cont.actuators['edge']
act_ups = cont.actuators['up_spin']
act_slide = cont.actuators['slide']
act_push = cont.actuators['push']
act_hurt = cont.actuators['hurt']
act_die = cont.actuators['die']


act_idle = cont.actuators['idle_80']
act_walk = cont.actuators['walk']
act_jog_16 = cont.actuators['jog_16']
act_jog_10 = cont.actuators['jog_10']
act_run_1 = cont.actuators['run_spin']
act_spin = cont.actuators['spin']


act_active = act_idle
cont.activate(act_idle)


def activate(act):
    own = cont.owner
    global act_active
    
    if act != act_active:
        cont.deactivate(act_active)
        cont.activate(act)
        
        act_active = act


def anim():




        if own ['ANIMATIONS'] == int(0) :
            activate(act_idle)
        if own ['ANIMATIONS'] == int(10):
            activate(act_walk)
        if own ['ANIMATIONS'] == int(1) :
             activate(act_jog_16)
        
        if own ['ANIMATIONS'] == int(2) :
             activate(act_jog_10)
        if own ['ANIMATIONS'] == int(3) :
             activate(act_run_1)
        if own ['ANIMATIONS'] == int(4) :
             activate(act_spin) 
             
        if own ['ANIMATIONS'] == int(5) :
             activate(act_up)
        if own ['ANIMATIONS'] == int(6) :
             activate(act_down)         
        if own ['ANIMATIONS'] == int(7) :
             activate(act_fall) 
        if own ['ANIMATIONS'] == int(8) :
             activate(act_goingup) 
        if own ['ANIMATIONS'] == int(9) :
             activate(act_edge) 
        if own ['ANIMATIONS'] == int(11) :
             activate(act_ups) 
      
        if own ['ANIMATIONS'] == int(12) :
             activate(act_slide) 
        if own ['ANIMATIONS'] == int(13) :
             activate(act_push) 
        if own ['ANIMATIONS'] == int(14) :
             activate(act_hurt) 
        if own ['ANIMATIONS'] == int(15) :
             activate(act_die)           

What’s the issue? When you change scenes, the new scene is what is run, and the old scene is ended.

the script don’t work anymore because the property ANIMATIONS have been freed to the next scene. I was asking what would be the best practices to not to not let that happen. and set that property upon start of the scene.

I’m going to go ahead and guess that you’re using Module Mode for this script. Essentially, the problem is that once the module is imported, the “own” variable is set to reference the player object (I’m assuming) which isn’t the same object in the next scene. Since the module’s already been imported, the variable pointing to the last player object sticks around, and so you have an invalid reference.

You need to make sure that the relevant variables point to the current object any time a function related to the calling object is run (for example, put it all into a single function that gets run when you need it to). As an example, if you have an “animate” function, put the cont and obj lines in that function call. If you’re running a function in module mode, the controller gets provided to the function call (so you can have an argument to the anim() function be “cont”, or the Python controller running the function).

Module-level variables can be very useful for some things (like settings or global, game-wide variables, I’m finding), but they don’t do well for transitory uses.

I agree with SolarLune. This code is to “scripty”. It will work in script mode as in each run it updates all the variables.

In Module mode this module will work with exactly one object and only this object.

You would not get this problems when you create variables when you need them rather then creating them at a “cosmetic” place. Yes, ther are programming languages that expect you declare variables before you do any code. Python does not do that.

So with a little refactoring it looks much different:


from bge import logic

def anim():
        animationIndex = getAnimationIndex()
        if animationIndex == int(0) :
            activate('idle_80')
        elif animationIndex == int(10):
            activate('walk')
        elif animationIndex == int(1) :
             activate('jog_16')
        
        elif animationIndex == int(2) :
             activate('jog_10')
        elif animationIndex == int(3) :
             activate('run_spin')
        elif animationIndex == int(4) :
             activate('spin') 
             
        elif animationIndex == int(5) :
             activate('lookingup')
        elif animationIndex == int(6) :
             activate('down')         
        elif animationIndex == int(7) :
             activate('fall') 
        elif animationIndex == int(8) :
             activate('goingup') 
        elif animationIndex == int(9) :
             activate('edge') 
        elif animationIndex == int(11) :
             activate('up_spin') 
      
        elif animationIndex == int(12) :
             activate('slide') 
        elif animationIndex == int(13) :
             activate('push') 
        elif animationIndex == int(14) :
             activate('hurt') 
        elif animationIndex == int(15) :
             activate('die')
        else:
            activate('idle_80')

def activate(actuator_name):
    controller = logic.getCurrentController().
    
    activeActuatorName= getActiveActuatorName()
    
    if actuator_name != activeActuatorName:
        controller.deactivate(activeActuatorName)
        controller.activate(actuator_name)
        
        setActiveActuatorName(actuator_name)

def getActiveActuatorName():
    return getOwner().get("currentActuatorName")

def setActiveActuatorName(actuator_name):
    getOwner()["currentActuatorName"] = actuator_name
    
def getOwner():
    logic.getCurrentController().owner

def getAnimationIndex():
    getOwner()['ANIMATIONS']        


[code is untested]

I think you notice that all these actuator variables are gone. They are not necessary.
A) you need just one at the time.
B) you do not even need the actuator, just the name.

I also added “elif” because all conditions are exclusive. There is no need to check them all.

To increase readability I renamed some variables to full names. Cryptic abbreviations are a sign of missing professionalism.

I also encapsulated some low-level functions. That increases readability of the higher level-code and partly removes replicated code.

Typically you read top-down. So the code should go from high-level to low level. So I placed anim() [not renamed] at the top of the code.

All “persistent” data is stored at the controller owning object. This ensures it can run at any object independent from other objects. -> so it can run in your other scene.

The design of your code looks like you are replicating the logic bricks. If you do it that way, you can simply stay with them. The code does not offer any benefit.

The first thing I suggest to change is the animation index. Why do you want to fiddle with numbers? Do you really think that 1 is better to understand than ‘jog_16’… ok bad example. I recommend you choose better names for your animations.

Do you really think 10 is understandable as “walk”? Why not call it “walk” in the first place?

The code will reduce dramatically:


from bge import logic

def anim():
    activate(getAnimationName())

def activate(actuator_name):
    controller = logic.getCurrentController().
    
    activeActuatorName = getActiveActuatorName()
    
    if actuator_name != activeActuatorName:
        controller.deactivate(activeActuatorName)
        controller.activate(actuator_name)
        
        setActiveActuatorName(actuator_name)

def getActiveActuatorName():
    return getOwner().get("currentActuatorName")

def setActiveActuatorName(actuator_name):
    getOwner()["currentActuatorName"] = actuator_name
    
def getOwner():
    logic.getCurrentController().owner

def getAnimationName():
    getOwner()['ANIMATIONS']  
      

You do not even need to know any number. The code does not even know all the actuator names. Just ensure valid actuator names are placed in the property ‘ANIMATIONS’ (why plural?)

Also, 10 is already an integer (you can show this with “isinstance(10, int)”). So there is no need for the int() calls.

I tried this approach and the other piece off code that you gave a example. I always end up getting

 'NoneType' object is not subscriptable 

Ive also tried calling in the owner example “getOwner” function. it works however after my arg

 if own['ANIMATIONS'] == int(0) : 

become not subscriptable

The above code snippets are just quick examples to show a different approach. They are untested. This is simply not possible as you posted just a part if the logic. Such code only works with the context that I cant know.

This also belongs to the error. You post the message so I can tell you that something is None, but without the stach trace, I can’t even guess where this error belongs to. So please post the stack trace too. From the information I got, it might be a simple spelling error.

Please create a simple demo.blend