To take a pause from a script i can’t find how to solve a bug, i created this little module.
Since it happened i needed a clean and easy way to do a cycle that iterates only one element per frame, i created a module that helps doing this.(this is for blender 2.5)
In addition, my “Simple_For” statement support iterators and generators as well as strings and lists
In the attached blend there is a script with 4 tests and the module, and here the module alone
class EachFrame:
'''A class that manages the python's cycling statement, executing the code one time per each time the class is called'''
class For:
'''This class iterates over the item of the object_to_cycle one item per call, and run the function_to_run *ALWAYS* passing the just iterated item as first argument '''
#storing_global_class is a "workaround" so that i don't have to import bge. When you call this script, always set storing_global_class as bge( unless you know what you are doing while you set it differently)
def __init__(self, storing_global_class, name, object_to_cycle, function_to_run):
#set an unique name to use for storing the data in the bge as global vars
self._storingC = storing_global_class
self._label = str(hash(str(name)))
self._cycleobj = object_to_cycle
self._func = function_to_run
#if is the first time the class in called, it sets all it needs
if not hasattr(self._storingC, self._label):
setattr(self._storingC, self._label, 0)
def execute(self, *args):
#retrieve how many cycle have been already processed
step = getattr(self._storingC, self._label)
#retrieve the next object to cycle
if step < len(self._cycleobj):
s = (self._cycleobj)[step]
#exectute the function with his arguments
self._func(s, *args)
setattr(self._storingC, self._label, step+1)
return(step)
else:
return None
class Simple_For:
'''This class does the some thing the for statement does, but it can cycle even generators and iterator, and it cycle on element per call. It returns the cycled element'''
def __init__(self, storing_global_class, name, object_to_cycle):
self._storingC = storing_global_class
self._label = str(hash(str(name)))
self._cycleobj = object_to_cycle
if not hasattr(self._storingC, self._label):
setattr(self._storingC, self._label, 0)
def execute(self):
#retrieve how many cycle have been already processed
step = getattr(self._storingC, self._label)
#retrieve the next object to cycle
if isinstance(self._cycleobj, str) or isinstance(self._cycleobj, list) or isinstance(self._cycleobj, range):
if step < len(self._cycleobj):
setattr(self._storingC, self._label, step+1)
return (self._cycleobj)[step]
else:
return None
else:
try:
for index in range(step-1):
(self._cycleobj).next()
setattr(self._storingC, self._label, step+1)
return (self._cycleobj).next()
except StopIteration:
return None
class Strict_While:
'''This class will execute the function_to_run for each time it is called, but *ONLY* if the condition is true and have always been true(if you call this function one time with a false condition, then even if the next time the condition is true the function wont be executed'''
#storing_global_class is a "workaround" so that i don't have to import bge. When you call this script, always set storing_global_class as bge( unless you know what you are doing while you set it differently)
def __init__(self, storing_global_class, name, condition, function_to_run):
self._storingC = storing_global_class
self._label = str(hash(name))
self._condition = condition
self._func = function_to_run
if not hasattr(self._storingC, self._label):
setattr(self._storingC, self._label, True)
def execute(self, *args):
never_been_false = getattr(self._storingC, self._label)
#controll if the condition is true and have never been false
if self._condition and never_been_false:
self._func(*args)
else:
setattr(self._storingC, self._label, False)
class While:
'''This class execute the function each time it is called if the condition is true'''
def __init__(self, storing_global_class, name, condition, function_to_run):
self._storingC = storing_global_class
self._label = str(hash(name))
self._condition = condition
self._func = function_to_run
def execute(self, *args):
#controll if the condition is true and then execute
if self._condition:
self._func(*args)
With this, if you want to run do
for obj in objlist:
myfunc(obj, myargs)
but go trough the list one object per frame, you can
------------------------- -----------------------------
-----Always sensor------- ---> ----Python Controller----
-True tick enabled at 0-- -------script:text----------
text:
function = EachFrame.For(bge, "my function", objlist, myfunc)
function.execute(myargs)
or
function = EachFrame.Simple_For(bge, "my function", objlist)
iterated_object = function.execute()
myfunc(iterated_object, myargs)
and it will do the work for you
Hope it can help you
Ps: if the module will be appreciate i can write a little more documentation, there are few things that at first time can give a little problems (for example if you use the EachFrame.For class, the function you call must have as first parameter the iterate object
Attachments
Each Frame Module.blend (64.4 KB)