Global variables and structure

Hey guys,

Today I started to play with python in BGE. And understood that I’m not quite used to principles how do the script works in BGE.

As I understand there is main cycle in BGE that works all the time and I can control actions that goes on in this cycle. May be I didn’t describe the process absolutely correctly but I guess It’s approximately correct :slight_smile:

So I have question: How do I declare and initialize global variables in BGE script?

Because if I declare variable in any place, for example x = 0, then in every iteration of the cycle x will become 0.

While writing got thought maybe I can access some blender built in features, because I can access owner of the controller in any moment and get position of object.

But I do have also other small misconceptions and things I do not understand for example if I get position of owner with owner.getPosition() (I know It’s deprecated :))
after that change location of object with some_actuator.setDLoc(x,0,0,True) (I know It’s also deprecated :)) and than again get position of owner with owner.getPosition() it returns the same result it returned first time even thou x wasn’t 0 and position of object changed. I guess it has something to do with that BGE main cycle works with pulses and does some thingsasynchronously with my script.

So if there are some wise and willing to help people I would be grateful for some help :slight_smile:

Maybe somebody could paste some good example how correct and structured script should look in BGE, or give some good links to tutorials or explanations of how does python scripts works in BGE, because it’s hard to find something even with google :frowning:

And sorry that post is so long :wink:

hi

i basically do the following:

i create the object.

the object gets an always actuator set to tap and a script called init_objectname.py
inside that script you can init your globals:

g = GameLogic
c = g.getCurrentController()
o = c.owner

o["testvar"] = "hello. i have been initialized"
o["testint"] = 0

and a second script, called main_objectname.py, on an always pulsing always sensor:

g = GameLogic
c = g.getCurrentController()
o = c.owner

print o["testvar"]
o["testint"] += 1
print o["testint"]

this will work nicely and keep your global variables where you want them, in your object.

if you need your variables to live even if your object is removed, you can refer to the

g.globalDict["anyvalue"] = "testvalue"

or even:

g.globalDict["anyvalue"] = {}
g.globalDict["anyvalue"]["anyvalue"] = "testvalue inside other value"

will work

hope that helps,
greetings
manarius

1 Like

Thanks manarius,

The things you showed works great :slight_smile:

And I feel a little bit embarrassed of how simple it was :), my thoughts were going the right way but I wasn’t able to put all together!

So hope that some day will be able to help you too :wink:

And I think I will like blenderartists.org very much cause now I do for sure! :slight_smile:

An easier way to declare globals is as follows:

Let’s say you want a global variable called Timer, declare it inside the GameLogic module

GameLogic.Timer = 0.0

Alternatively you could do this:

import GameLogic as g

g.Timer = 0.0

It will be visible to all scripts and persist for the duration of the run-time app.

Regards,

Journeyman

Hy journeyman17,

thanks

You are right, it’s another way to initialize global variables.

It’s a bit simpler and it even gives me opportunity to interact between game objects in scene.

But I must say that I will stick with manarius. Because it is a bit more flexible.

(It just bothers me a little bit that when I try to assign new property to GameLogic, python tells that there is an error and GameLogic does not have such property, but even python does not like assignation like that, it does it’s work and assigns new property with value I set. So it just works :slight_smile: And I read somewhere that it’s not a big deal if BGE says that there is an error cause it’s don’t know what I want)

So here is real simple example that initializes global variables in one game object logic and print’s values of variables in other both ways manarius and journeyman17:

For initialization:
You have to create one object:
add to it one Always sensor with tap on and connect it to controller with python script:


g = GameLogic

#journeyman17
g.test_str = "Hello!"

#manarius, only one value
g.globalDict["anyvalue"] = "Hy I am initialized!"

#manarius, a value inside value
g.globalDict["anyvalue2"] = {}
g.globalDict["anyvalue2"]["insidevalue"] = "Hy again!"


and then add another object
add to it one Always sensor with (tap on [if you want preserve system resources in real game tap would be mostly off]) and connect it to controller with python script:


g = GameLogic

#journeyman17
print g.test_str

#manarius, only one value
print g.globalDict["anyvalue"]

#manarius, a value inside value
print g.globalDict["anyvalue2"]["insidevalue"]


This way objects can interact in scene.

If you do not need interaction, than you can assign property’s to owner as manarius showed in his post.

And while writing this post I got thought that it’s even possible to visually assign value to owner by clicking button Add Property and setting up needed value.

I made a test and it works, but I don’t know is it really nice way, cause it print’s out more than I need, just replace the code of first object’s script with this one:



g = GameLogic

#journeyman17
g.test_str = "Hello!"

#manarius, only one value
g.globalDict["anyvalue"] = "Hy I am initialized!"

#manarius, a value inside value
g.globalDict["anyvalue2"] = {}
g.globalDict["anyvalue2"]["insidevalue"] = "Hy again!"


#Visually assigned Property to First object
c = g.getCurrentController()
o = c.owner

print o.p1

o.p1 = 6

print o.p1


And I have 2 questions:

  1. May be someone can can lighten me why python print’s out 5 one time and 6 three times.(It does not look that tap is on? or what)?

  2. I guess it’s really easy to do, but while made these simple experiments I realized that I don’t see the way how can I delete objects from blender scene and GameLogic. For example to free system resources and delete one level of the game before I load another. I made quick look at API and for example Blender.Object or GameLogic does not have methods to delete object. (OK in GameLogic I can do it mannually by just assigning another object to particular variable. But I guess there must be be better way and old object even thou will stay in scene.).

just a quick tip, use the dir function on any object,sensor,controller or actuator.
most times you can do great things with the things :smiley:


#this shows you everything you can do with an object.
print dir(object)

to remove an object there is the endObject actuator. it unfortunately only removes the object that owns it, but it at least does its job.
the other way to remove is:


#destroy destroy destroy
o.endObject()

edit:
o.p1 is deprecated, use o[“p1”] instead, as far as i know o.p1 will not work in 2.5.

the tap of the always sensors calls the script twice, once when getting positive an once when getting negative, so you will have to check if sensor.positive:
just take a look at the blend file i attached, it works there.

have fun whilst playing around,
greetings
manarius

Attachments

init_and_end_object.blend (435 KB)

OK sweet, big thanks to you manarius!

  1. dir() in combination with API helps alot.

  2. Thanks also for getting me clear about taper

And I wouldn’t be a splinter if I didn’t do this :slight_smile: :

In the file you attached to your post you left some undone things with taper
For example if you run game and then press A key few time you will see result like this:

1
1
2
3
4
5

It’s because as you said tap works 1 time on positive result and 1 time on negative. That is why I had to paste test for positive sensor value also in the init script.

Because game worked like that init made p1 = 0 after that once sensor made p1 = 1 and tap in init worked once more on negative and made p1 = 0 again, so when I pressed A key python printed out 1 again.

And thanks for endObject():

This test had to be done also in destroy, cause even thou there was taper and even thou there wasn’t any printed values and even thou GameObject(owner) wouldn’t be deleted second time cause it is already deleted, for correct script work.

You also showed EditObject actuator with End Object property, but you didn’t used that so I made this also working now also by pressing X key it’s possible to delete particular object.
And here is good possibility to see why it is better to use python not visual logic bricks cause by pressing X key python at first goes to Edit Object actuator, then to actuator’s controller, then to controller’s owner and only then calls method of the owner(endObject()). In python we already have owner so can to call endObject() right away.
And a little bit more in addition in python we can make tap do it’s job only once but by using visually assigned Edit Object actuator tap always will run twice (once when sensor.positive is true, once when false).

So thanks(already 4 time in this post :slight_smile: ) to manarius and if it helps to anybody then you can compare blend of manarius with my blend(see attachment)

Attachments

init_and_end_object_2.blend (436 KB)

@splintercdo, Some remarks:

  • The execution order is always

  • [LIST=1]

  • all sensors,

  • all controllers receiving any pulse,

  • all active actuators.

[/LIST]

  • endObject() does not remove the object immediatly. See http://www.blender.org/documentation/249PythonDoc/GE/GameTypes.KX_GameObject-class.html#endObject. The object will be removed after the actuators are executed, regardles if you use the endObject actuator or the Python function.
  • The Tap at the sensor does not make the script executed twice. The Tap lets the sensor fire a False-Pulse one tick after the True-Pulse (ignoring the sensors condition to switch to false). The controller is executed if the controller receives ANY Pulse. See http://gameblender.wikia.com/wiki/Sensors for details on sensor pulses. Anyway it is always better to check if a sensor fires true or false pulses.
  • The controller receives pulses from the connected sensors. The controller determines if the connected actuators have to be active or or not. The actuators will be activated if the controller calculates true and deactivated if the controller calculates false. If the controller does not receive a pulse, the controller is not executed and therfore the actuators remain in the state they are.
    Example:
    When you press a key, the keyboard sensor sends a True-Pulse to the controller. If it is an AND controller it will activate the actuator. If it is a motion actuator, the object will perform the motion.
    If you still hold the key, the sensor does not fire a pulse. The controller gets not pulse. The actuator remains activated.
    By releasing the key the sensor sends a False-Pulse to the controller. The controller deactivates the actuator. The motion stopps.
    If you use Tap, the motion actuator will be deactiated one tick after the activation, regardless if you still hold the key.

…long text.
I hope it helps

just another quick tip:

if you want to have sensor independent control over script you can do

if not "init" in o:
    o["init"] = 1
    
    #the code in this if will only be executed once when the object is loaded.

another nice thing are functions and control over them, for example, create a script called:
class.py and paste this code:


#have to use import, dont know why, but sometimes fires an error if you dont
import GameLogic as g
def function():
    test_str = "bla"
    return test_str

after doing that, you create a second python script and sensorize it.
paste that:


g = GameLogic
c = g.getCurrentController()
o = c.owner

#no .py in the classname, but the python script which inherits function needs to be named class_file.py
from class import function
    
test_var = function()
print test_var


shame on me, i gave you wrong information. if you set the always sensor to not tapping the script will only be called once, so tapping makes that init problem appear.
but since i do not trust logic bricks and the setup users did to them i still prefer to do the “if not “init” in o:”

greetings again,
manarius

This is reply to monster’s last post

Yeah it is correct, inside destroy there is no need to make test - is sensor positive cause when script call’s o.endObject() BGE is deleting GameObject because there is no actuators to complete and next time when sensor should send fake pulse there is no sensor cause BGE deleted GameObject with sensor that had to send pulse.

The same goes with X Key there I call EndObject actuator and in next frame actuator wouldn’t be called cause tap is on and after TRUE it sends FAKE so it means controller would not activate actuator but this is not the reason why BGE doesn’t try to delete the GameObject it is because like in first case GameObject is already deleted cause there was only one actuator that did it’s job already and called endObject()

About the TAP you are correct that it calls actuator one time only on TRUE if controller has AND property, but it doesn’t change the fact that sensor with TAP sends two pulses TRUE and FAKE and that means that controller does it’s calculation job or in this case call’s script two times, so that means that even thou actuator would work with AND only once on TRUE impulse, script does it’s job twice.
(and if honestly it is great, because if script call would be in actuators our possibilities would be greately cut, so thanks BGE developers, even thou we have to be more carefull and paste checks of TRUE and FAKE pulses where they should be)

So I hope that I proved that your post helped me really much and the links were great I got through them understand them and now have much much much :wink: better understanding of how does sensors, controllers and actuators interact.

And for people who are interested in this I made little blend that helps to understand all the situations of how sensors sends their pulses, just go to link in monsters post take my blend(see attachment) and enjoy:D

I really enjoy blenderartists.org forum because of people like manarius, monster and others who are willing to spend their time helping to others I try to do the same.:slight_smile:

and manarius I will explore your post a bit later and give my splintery opinion again;)

Attachments

logictics.blend (132 KB)

Sorry, What I meant was:

  • The controllers run just once within a logic tick if they receive at least one pulse. It does not matter if TRUE or FALSE pulse (not FAKE).

Sensors have the state TRUE or FALSE. But the time when they send a pulse to the controllers depends on the configuration. At minimum the sensor fires a pulse when the state changes from false to true and true to false (2x). True to false has an exception: when the Tap option is set the pulse is send one tick after the preceeding pulse.

That means your script is executed everytime when any connected sensor fires any pulse.

I agree almost with everything, but it is not correct that

At minimum the sensor fires a pulse when the state changes from false to true and true to false (2x).
because Always sensor will send only once TRUE pulse and after that won’t send pulses anymore - (Try to change sensor property from Keyboard to Always and look at console you will see that there was only one pulse sent).

About FAKE and FALSE, of course I know that sensor sends FALSE value to controller it’s just that almost in all documentation it is called FAKE pulse so I did call it that way intentionally, but thanks for mentioning that it can help other people to understand what I meant.

And in last post I forgot to mention that yes you are right that endObject() is called only when object has done all of it’s job and all actuators are completed. But what I meant was that in example blend I made you can delete EndObject actuator after that of course the X Key won’t delete object anymore but D Key will, because it calls owner.endObject() through python script and if there were some other actuators it even thou would need to wait while all of them are done. But it wouldn’t have to go from actuator to controller then to owner and only then call owner method endObject() and while it seems not important at small projects, imagine large application that has to delete hundreds of objects during it’s work and if it has to work non stop it means that on larger periods of time you will start to lose time and as we know time is money:yes:

Indeed you are right. But the always sensor never changes to false, so I’m right as well :D. (Except Tap is enabled, than it changes to false as well.)

I’m not in doubt that, the endObject() function is really usefull, especially when removing multiple objects. I just want to say that an “ended” Object can still perform it’s actuators afterwards (as the endObject actuator does). For example it could send a message “Help, someone killed me!!!” or reloading the scene :evilgrin: etc…
I do not know the implementation of endObject() nor the implementation of the end object actuator, so I can’t tell if one of them is faster.

I haven’t seen a dokumentation with FAKE pulse. So I can’t tell. It does not really matter as long our scripts get any pulse :yes:.

Happy blending
Monster

OK, we are both correct:D

And yes you are right, in documentation there is only true and false pulses, I guess the FAKE value left in my mind after your second link about pulses there was description of false level triggering option in sensors I read it at 1 o clock in the night after quite hard day so I guess it’s possible to forgive me:D

And about endObject() yes I absolutely agree with you I wrote the same(even more it’s interesting that endObject() delay’s it’s work even in logic bricks there are no actuators it waits while all scripts and gameObject itself does all it’s job and only then deletes it, so yes it’s possible to write in script anything we like even after endObject() and it will be done).

Happy blending to you too;)

splintercdo

Hey manarius,

I liked very much the things you showed in your last post.

about not trusting users if it is blend file then yes it’s nice way to just test if the gameObject has key with particular name and if he doesn’t then create it.

For the second part with functions it’s just super great because it is much more python oriented and it allows to do global and local variable comparisions and basicaly can do anything whenever I want it. And for variables importing and using functions together with globalDict of GameLogic it’s close to perfect:yes:

And in general I appreciate possibility to control things from script as much as possible.

So thank you:yes: