Last week, I discovered the yield statement and I must say it fascinates me.
So, when I tried to use it within Panda tasks, it realised it wasn’t yet supported. I decided to write a bit of code that would make the usage of generators possible.
I managed to write this little piece of code. It’s primitive and doesn’t use all of yield’s power, but I’ll try to improve it!
Right now, it simply takes a generator as argument and then acts like a function.
class GeneratorTask:
def __init__(self,func):#where func returns a generator
self.generator=func
self.__isfirstcall__=True
self._task=None
def __call__(self,task,*args,**kwargs):
#grab the task instance
self._task=task
#check is it's the first call
if self.__isfirstcall__:
self.generator=self.generator(self._task)
self.__isfirstcall__ = False
#do the thingy
try:
yielded=self.generator.next()
except StopIteration:
return Task.done
#the generator ought to yield Task attributes
#if None is yielded the Panda Reference specifies
#it will end the task
return yielded
The following code:
def foo(task):
x=0
while x<10:
x+=1
print "FOO",x
yield Task.cont
yield Task.done
taskMgr.add(GeneratorTask(foo),"test")
Outputs:
The following code:
def bar(task):
x=0
while x<10:
x+=1
print "BAR",task.time,task.frame,task.id,task.name
yield Task.cont
yield Task.done
taskMgr.add(GeneratorTask(bar),"test")
Outputs:
Here is an example of how I used it:
class Camera:
"""Creates a camera"""
def __init__(self,center):
self.center=center
self.x=0 #xposition
self.y=0 #ypos
self.z=0
self.h=0 #xrotation
self.p=0 #yrot
self.r=0 #zrot
self.current_task=None
self.tasks=[self.camTask1,self.camTask2]
self.next_yield_task()
taskMgr.add(self.SetPosNHpr,"SetCamPos",priority=0)
def setZeros(self):
self.target=None
self.x=self.y=self.z=self.h=self.p=self.r=0
def next_yield_task(self,task=None):
self.current_task=GeneratorTask(random.choice(self.tasks))
taskMgr.add(self.current_task,"task",uponDeath=self.next_yield_task)
def camTask1(self,task):
"""A simple zoom-out"""
self.setZeros()#sets all to 0
z=20
while z<100:
z+=1
self.z=z
yield Task.cont
yield Task.done
def camTask2(self,task):
"""A simple rotation"""
a=0
self.setZeros()
self.z=20
self.p=340
while a<360:
a+=1
self.h=a
yield Task.cont
yield Task.done
def SetPosNHpr(self,task):
"""simply sets the position and the rotation according to self attributes"""
base.cam.setPos(self.x,self.y,self.z)
if type(self.target)==NodePath:base.cam.lookAt(self.target)
else: base.cam.setHpr(self.h,self.p,self.r)
return Task.cont
The only actual problem in this code is that it goes at an incredible speed , so don’t try to run it unless you want a psycho vision, it just shows how it can be used.
So basically that’s it. Some things should be added in the future, like use of arguments, sending values, etc…
At the moment I can’t really improve this script, I’m quite busy , you can take the initiative !
Any suggestion is welcome!