Append function does not appear to work in BGE

Could you please have a look at the blend file and tell me why on earth the append function doesn’t appear to work? :o
Seems utterly trivial and still it looks like I’m missing something but…what?

Attachments

array_issues.blend (611 KB)

It does work as it’s written. Every time a sensor triggers the script (when either sensor becomes positive or negative), it creates a blank list, and then checks if the sensors are positive, in which case appending to the list.

You are using script mode, which evaluates the entire script every time it’s triggered. Instead, you should use module mode of the python controller, to reduce the overhead of the script.

You probably only want to define the list once, so create a second function “init” triggered with an always sensor to set the list object.

@agoose

how do you make a text script to a module?

Set the controller to module mode.
Remove the main() call
Type “myscript.main” if your script is called myscript.py

The BGE will call that function in that module when the controller is triggered.

Oh, I see…so the append function does work but the list is reset every time so that explains why it’s always the last item!!! (*facepalm)

You are using script mode, which evaluates the entire script every time it’s triggered. Instead, you should use module mode of the python controller, to reduce the overhead of the script.

A ha! That’s a critical detail

You probably only want to define the list once, so create a second function “init” triggered with an always sensor to set the list object.

I think I see what you’re suggesting but I’m kinda stuck with the implementation. I’ve tried to separate the two functions as follows but it still fails miserably :frowning:
Any pointers?

 
import bge
import random

def init(value):
    cont = bge.logic.getCurrentController()
    own = cont.owner
    own['items'] = []
    own['items'].append(value)
    print("list items:", (own['items']))

def main():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    mo = cont.sensors["mo"]
    click = cont.sensors["click"]
    value = own["value"]
    print("initial value is:", value)    

    value = random.randint(1,10)
    print("randomized value is:", value)
    
    if mo.positive and click.positive:
        init(value)

@agoose
if you run scripts through the module controller, does the controller read through all the other modules too if there are more than 1 in the script?

@blendercomp
what exactly does not work?
if it does nothing at all: you have to change “python” to “module” in the python controller in the logic bricks editor, and name the module

@Leralass:
The idea is to store random ints in an array every time the user clicks on an obj.
I know how to do this in Python (e.g. create a list and return it from function 1, access the list from function 2 and populate it with ints). However, I’m not sure I’ve grasped how exactly to do this in BGE python.
All I get now is only the last item entered, not a list as I would expect. As agoose77 pointed out, this is because the list is created anew every time the obj is pressed. How does one get around this?

ill comment on your code:

 
import bge
import random

def init(value):
    cont = bge.logic.getCurrentController()
    own = cont.owner
    own['items'] = [] ####here you reset the list####
    own['items'].append(value)
    print("list items:", (own['items']))

def main():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    mo = cont.sensors["mo"]
    click = cont.sensors["click"]
    value = own["value"]
    print("initial value is:", value)    

    value = random.randint(1,10)
    print("randomized value is:", value)
    
    if mo.positive and click.positive:
        init(value) ####here you run the above defined function where you reset the list####

so it still resets everytime you run the code

edit:
as a solution you could:

 
import bge
import random

def init(value):
    cont = bge.logic.getCurrentController()
    own = cont.owner
    if not "items" in own.getPropertyNames():
         own['items'] = [] #so you only reset/create the property if it doesnt exist
    own['items'].append(value)
    print("list items:", (own['items']))

def main():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    mo = cont.sensors["mo"]
    click = cont.sensors["click"]
    value = own["value"]
    print("initial value is:", value)    

    value = random.randint(1,10)
    print("randomized value is:", value)
    
    if mo.positive and click.positive:
        init(value) #will not reset the list

if not "items" in own.getPropertyNames():
         own['items'] = [] #so you only reset/create the property if it doesnt exist

Elementary, my dear Watson! :0

Thank you!

For the record, here’s the polished solution:


import bge
import random

def set():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    if not "items" in own.getPropertyNames():
        own['items'] = []
    return (own['items'])

def main():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    mo = cont.sensors["mo"]
    click = cont.sensors["click"]
    value = own["value"]

    value = random.randint(1,10)
    print("randomized value:", value)
    c_list = set()  
    
    if mo.positive and click.positive:
        c_list.append(value)
        print("c_list final is: ", c_list)


import bge
import random

def set():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    if not "items" in own.getPropertyNames():
        own['items'] = []
    return (own['items'])

def main():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    mo = cont.sensors["mo"]
    click = cont.sensors["click"]
    value = own["value"]

    value = random.randint(1,10)
    print("randomized value:", value)
    c_list = set()  
    
    if mo.positive and click.positive:
        c_list.append(value)
        print("c_list final is: ", c_list)

ooops, double post, sorry!

Use two python controllers. One is triggered by a default Always sensor (no triggering), and runs myscript.init
The other is triggered as you do presently, and runs the main (might want to rename that to something more descriptive)

Be aware that main is triggered every time the mouse button is pressed and released, and the mouse over sensor is triggered (by default) when the mouse enters the object and when it leaves it.

Also, don’t use bge.logic.getCurrentController() in this mode of operation. If you define an argument to the functions called by the Python controller, it will be given (by the BGE) as the current controller. (So remove cont = ... and add a cont argument to both init and main (and remove the init(value) in the main function))

Also, you don’t need to check if the property name is in getPropertyNames(), just check prop_name in obj.