make something happen only once

I run into this problem often. I want to alter a variable in a script, but if I don’t define the variable first I get an error, and if I do define the variable, the variable gets reset to what I define it to be every time the script runs. I’ve been using either global variables or properties to get around this problem, but that feels messy and incorrect for some things. I’ve tried using the “try-except” thing, but I can’t seem to get that to ever work properly. is there a way to make something only happen once in a script even if the script is triggered more than once, or is there a way to define variables once without using global variables or properties.

simple example:


import bge  

cont = bge.logic.getCurrentController()
own = cont.owner
lmc = cont.sensors["lmc"]                 #left mouse click

a = 1

if lmc.positive:  
    print (a)    
    a += 1

I want it to count up every time I left-click

the output:
1
1
1
1
1
1

what I want:
1
2
3
4
5
6

while this is just a very simple example, it would greatly simplify some of what I am working on.

-Garrett



import bge  

cont = bge.logic.getCurrentController()
own = cont.owner
lmc = cont.sensors["lmc"]                 #left mouse click

if not 'init' in own: # Initialize object variables
    own['init'] = 1
    own['a'] = 1

if lmc.positive:  
    print (own['a'])    
    own['a'] += 1

In this example, I initialize a new variable called ‘init’ if it doesn’t exist in the object’s variable dictionary (which you can check as I showed above, by just checking if the variable name is in the object). This way, we can see if the object had been initialized yet. You could also just check if ‘a’ is in the object.

I agree that it feels messy. The proper Pythonic way would be to use “self.a”, with “self.a = 1” in the init function.
Unfortunately, there is no way you can do this with logic bricks.

If there is only a single copy of the script, you can “fake it” with a Python controller in Module mode.
If you want to attach the script to multiple objects, then you will have to use the property dict, as in SolarLune’s solution.

Two proper solutions to this problem have been proposed, but they are both still in development, and not yet user-ready for casual scripters. One is Moguri’s components; see my signature for the other one.

Your resources are fantastic in explaining Python scoping, Monster, and beginners should definitely learn and use them to solve immediate problems. That does not change the fact that Garret’s “feels messy” sentiment is essentially correct and widely shared among programmers.
Property dicts are incredibly fragile. If you would want to manage a second variable using SolarLune’s scheme, you would have to 1. literally copy-paste the code into a second Text Block, 2. change ‘init’ to ‘init2’ in the second block in order to prevent a name clash. Yuck!
It is horrible that the BGE enforces such messy practices, especially from an educational point of view. Many young people learn their first Python through the BGE, and they have to unlearn all these bad habits if they start to write larger pieces of software. Python itself is much better designed, it scales up from beginner to very advanced programming.

Huh? You would just make another variable under the initial ‘init’ variable…?



import bge  

cont = bge.logic.getCurrentController()
own = cont.owner
lmc = cont.sensors["lmc"]                 #left mouse click

if not 'init' in own: # Initialize object variables
    own['init'] = 1
    own['a'] = 1
    own['b'] = 1

if lmc.positive:  
    print (own['a'])    
    own['a'] += 1
    own['b'] -= 1

EDIT: Okay, you meant manage another variable in another script on the same object, I see. You would probably set up all variables in an initialization script, and then go forward on different scripts with a check to see if the object has been initialized. Object variables exist in the object, not in the script, so you can have multiple scripts that use variables defined elsewhere. You could also write it all in a single file, which is how I do things (i.e. one for Player, one for NPCs, etc. You could also do different functions for each portion of the code, like one for an initialization function, one for an update function, etc.).

Hehe, I wanted to respond but then I saw your edit :slight_smile:
IMO, if a and b do not interact, they should have their own piece of code, not a big controller that manages both. And you can indeed program your own layer of managers and initializers, but that’s a very heavy solution: simple Python classes are more straightforward.

I somewhat agree with you, but in a normal Python game creation situation, I believe you would define variables for a game object in the class itself. You would define them all at the same time, not one by one across different files or functions. The BGE version can be split up in different ways (i.e. an initialization Python Controller, an Update controller, an Animation controller, etc., or one single controller with different functions, or whatever), but the variables for the object should probably be defined in a single place for simplicity. That’s my opinion, of course.

I somewhat agree with you as well. There are certainly cases where it makes sense to initialize everything in one place, e.g. variables that are shared by different controllers/components. On the other hand, IMO, variables that are used by only one component should be privately managed by that component. That makes it a lot easier to re-use it (like the example above: only one piece of code to link/import, no risk of name clashes), either within the same project or in a different project.

More importantly, the game logic system should give you the choice, and not enforce one approach or another.

Of course, that is also just my opinion, which heavily shows in the design of Hive. It is good for me to listen to disagreeing opinions, I don’t want to get stuck in my own echo chamber :slight_smile:

I suppose you mean without creating the property in the logic brick editor. Yes, you can create variables, or game properties, in Python code via assigning a value to them. Properties are the same thing, except graphical, and you can’t do as much with them as you can with Python.

yes, exactly.

To add my 5 cents:

Thanks, I hoped that it will be useful for beginners

… and to point experienced programmers to a useful perspective.

This is necessary as “Scripting” in other frameworks is often implemented in a complete different way. It might describes the complete game loop or it runs parallel to the game loop.
I had exactly the same problems at the beginning because of such “other” view.

I think we mainly see the same thing. Here is my opinion.

I was never a friend of this “init” variable thing. This is a contribution of the limitations of scripts. Nevertheless it is a good example of the problem.

Different scripts should not perform the same processing. Each script should do their own specific processing (e.g. their own initialization). If they share the same data they have to deal with possible conflicts. This is the nature of shared data. Typically scripts share the same game object especially when the controllers are owned by this game object.

Coming back to the “init” example:
The name “init” shows that this code was designed to ignore possible conflicts assuming there are none.
A more precise approach would be to use “script dependent” names e.g. “myScript.init” and “myOtherScript.init” [Attention: bad script names!]. The scripts share the same game object but they do not share the same properties just by naming convention. Another solution would be “purpose-related” names e.g. “mouse.init” and “joystick.init”.

[Hint: if the script name implies the purpose … you get “script and purpose” dependent names. e.g. mouse.py -> “mouse.sensitivity”, joystick.py -> “joystick.sensitivity” ].

I also think that we see mostly the same thing :slight_smile:
Scripts/components should keep their own stuff to themselves, and property dicts are only meant for information that is shared between many.

Are you are referring to module-mode variables/attributes? I agree that they are good as long as they are tied to a single game object. But when you spawn a new object, you normally want to spawn a new copy of the script/component, with all the appropriate start values initialized. IMO, this is the most important thing that needs to be fixed in the logic brick system (and I will).

If I am misunderstanding or misrepresenting your opinion, please say so.

No I refer to the “init” property, when it is used by two different code snippets to mark the “initialized”-status. If they share the same property, one will never initialize. I assumes this is what you meant with the "init vs.“init2” example.

The other problem is that people think they define a variable in the scope of the game object. But it resides in the scope of the (short-living) script execution.

I often see a similar misunderstanding with module variables as they live in the (long lasting) module scope, which is shared by all users of this module.

Exactly, the script/module is not tied to the game object.

Sorry, that was sloppy writing of me.
I meant that “MyScript.init” works fine if there is a single, module-mode Python controller in a single game object, referring to the “MyScript” text block. But if you then use it with “Add Object”, there will be multiple controllers using the same “init” property.

I mean’t “init” or “myScript.init” as property name, not module variables. I guess I should have been a bit more clear in the above description ;).

This way the data is stored at the game object (the game object the property belongs to) while it does not matter if the code is in a script or module or even a python object.

And no I do not want to suggest to use a module to store game object related data (bad bad bad :spin:).

ah, own[“MyScript.init”], now I see what you mean.