Question of the day, variable initialization

I’m having a major issue with variables, I am used to initializing them outside a function(beforehand) but I cannot figure out how to do this in python…
I would be ok with a run once type of function(some type of initialize function) so long as the variables would be exposed to other functions in a script.
Can anyone give me some advice on how to do this?..I am basically using a counter to see if my character is falling or just jumping based on how long it is not on the ground. The issue is quite clear, if I initialize the “jump_time” variable at the begining of my script it picks up that value(0) again on the next “loop” so the counter never advances past “1”…I am not using built in physics, aside from raycasting to the ground to get the players distance to the ground …raycasting usually falls under physics in godot, untiy etc…

I hope all that makes sense…

you could store your variable in the logic module. python is not like C, you dont have to perform a ritual to summon a variable into existence.

## PY/CORE.py ##

from bge import logic

logic.MYVAR = "somthincoolz"

def FIND():

    return logic.MYVAR

def SET(ARG=None):

    logic.MYVAR = ARG


## PY/SCRIPT.py ##

from bge import logic

import PY.CORE as CORE

print CORE.FIND()

CORE.SET(1234.5)  # omg, now its a float!

print CORE.FIND()

def SCRIPT(): # called from blender

    logic.MYVAR -= 0.5

I’m slightly confused by this line

import PY.CORE as CORE

because I am not sure if the name of the first script was “CORE”(I understand it is getting referenced) or what PY.CORE is(is it already a python module)?

aside from that it looks clear enough two scripts one that just initializes the variables and then being accessed in the second…or am I just an idiot? :slight_smile:

It would be far easier in c :slight_smile: , but this is not C and I need to get a better handle on it.

here is an example blend that could help you.

http://15b.dk/blendfiles/counter.blend

i just threw around a bunch of examples, none of that is required to get your variable to work other then “logic.MYVAR = X”.

the import is telling python to look in a folder called “PY” for the file called “CORE.py”. assume you have a blend which is executing code from a folder PY in the same directory as the blend. the python module logic brick would have “PY.SCRIPT.SCRIPT” (hm, im not sure if python would like these attributes being the same?). the “as CORE” simply is making it shorter to reference “CORE” vs “PY.CORE”.

when you import a py file, anything not in a function or class gets run ONCE, no matter how many times its imported.

apologies for not writing in PEP format standard, but i didnt learn that until i made my own little standard.

ok this works but I see I need to point to it’s owner


import bge

scene = bge.logic.getCurrentScene()
cont = bge.logic.getCurrentController()
own = cont.owner

text = scene.objects["Text"]
text.resolution = 3

if "counter" not in own:
    own["counter"] = 0
else:
    own["counter"] += 1

text["Text"] = own["counter"] 

def main():
    
    if own['counter'] >= 100:
        own['counter'] = 0
#This clearly does not work...meh
    #my_counter = own['counter']
    #if my_counter > 50:
        #my_counter = 0
main()

this works, Thank you very much it works fine for this use case. I can see it being an issue if you have to do that with several variables though.

THAT!! is extremely helpful, and I feel a little stupid(stoopid) at the same time…why did I not realize that…thanks guys.

I wrote an articleon using python classes in BGE. You might find it useful since it seems like you want to use a class here (an object with a custom initialization).
I’m sure you know about classes already, but it’s not always clear the best way to integrate python classes in to Blender Game Engine.

there is other ways to do it.

here is a few examples


import bge

scene = bge.logic.getCurrentScene()

dict = bge.logic.globalDict

text = scene.objects["Text"]
text.resolution = 3

if "counter" not in dict:
    dict["counter"] = 0
else:
    dict["counter"] += 1

text["Text"] = dict["counter"]


import bge

scene = bge.logic.getCurrentScene()
cont = bge.logic.getCurrentController()
own = cont.owner

text = scene.objects["Text"]
text.resolution = 3

if hasattr(bge.logic,"counter"):
    bge.logic.counter += 1
else:
    bge.logic.counter = 0

text["Text"] = bge.logic.counter


for something as simple as variables, why so many checks? just put the thing there to begin with. script mode is for noobs.

Initialization = set a value.

“outside a function” sounds like you need data that persists the end of the script. In that case local variables will not be sufficient as they will die when the script ends.

I suggest to use a property. A property lives in the scope of the 3D object. This makes a lot of sense as you do not need this data when the 3d character is not present anymore.

When I read it right you have two events:

  • on ground
  • in air

You want to know how long the in air state lasts.

So I suggest you store the time when the character enters the in-air state (begin time).
When the character leaves the in-air state you measure the time again (end time).

The difference between both times is the time in air (air time).

There are many ways to implement that - even with logic bricks it is no big deal (there is a timer property).

When using Python you need to be aware these are two different operation at different times. You will need to store at least the begin time in a way that it survives till it is need for the air time calculation.

beginInAir.py


import bge
from datetime import datetime




if all(sensor.positive for sensor in bge.logic.getCurrentController().sensors):
    beginTime = datetime.now()
    character = bge.logic.getCurrentController().owner
    character["beginTime"] = beginTime


    print("begin time", beginTime)

endInAir.py


import bge
from datetime import datetime




if all(sensor.positive for sensor in bge.logic.getCurrentController().sensors):
    endTime = datetime.now()
    character = bge.logic.getCurrentController().owner
    beginTime = character["beginTime"]


    airTime = endTime - beginTime
    print("end time", endTime)
    print("air time", airTime)

You might even want to combine them into one script. Be aware this increases complexity quite a lot. This can be useful when you have the same sensors measuring both events positive and not positive (e.g. a ray or collision sensor).


import bge
from datetime import datetime




if all(sensor.positive for sensor in bge.logic.getCurrentController().sensors):
    beginTime = datetime.now()
    character = bge.logic.getCurrentController().owner
    character["beginTime"] = beginTime


    print("begin time", beginTime)
else:
    endTime = datetime.now()
    character = bge.logic.getCurrentController().owner
    beginTime = character["beginTime"]


    airTime = endTime - beginTime
    print("end time", endTime)
    print("air time", airTime)

As the data is hold at the 3D object, you can use this code on any number of objects. Do not use it on the same object twice!

Requirements:

  • the object does not start in-air
  • the beginInAir code is executed first.

Otherwise you will get an error as the begin-time is not known.

using a class is probably the best solution, but I need to do more py homework before I setup a custom class…should not be too difficult…ofc I assumed I would have no issues with working with python in the first place :wink:

for the moment while I am learning assigning a property to the object seems to be what I am looking for, plus I can see the properties of one object while working with another script…this seems to be quite straightforward…


player['prop_timer'] -= 1#prop is a property naming convention for me

I did not realize there is also one for time as well as the normal variable types…I will read this thread again…I just came home from work and glazed over most of it, once I have eaten I can come back and more thoroughly read through it.

EDIT: My second thought on using a class is no, if it is an enemy object then I will probably get around to doing that, but this script will be specific to this object(the player)
using the properties is the most straightforward way I can imagine, and I am doing this with my son(he is 10) so keeping it simple is a lot of help for getting him into programming, and it helps me get my feet wet and learn as I go.

Thanks again for answering my question

worked like a charm.

OK. If you’re doing it with your son then simple properties will be best.
Remember that you can initialize properties in Blender in the logic panel. Just add a new property there and it will be accessible with python as well as the logic bricks.

If you want more info you can check the API.

lol you do not need to name all properties “prop_*”.

This keys are always properties.

You might want to use (pseudo) constants. Naming them with prefix or suffix would make sense.

sample:



PROPERTY_TIMER = "timer"

... 
# somewhere in your code

timer = object.get(PROPERTY_TIMER)

...
# somewhere else
object[PROPERTY_TIMER] = 0


This way you tell the reader right at the top that you expect these properties.
You have a single place where the names are defined.

If you decide to change the name (e.g. because you need a different timer) you do not need to find all occurrences and maybe miss one. Beside of that a Python IDE can show you when you use an undefined constant, before you even start the game (and maybe miss the issue).

Just some thoughts.

@monster: yeah I realized that after I did just the one…hell even “the boy” was laughing at me :)…he learns faster than I.
and I am using “visual studio code” as my less than integrated dev environment…I kinda like it for simple things.