@rdb is probably right. Although I’ve not used coroutines in Python, they are about as clean as he presents them. I didn’t know what they were called.
[edit] In C# they’re as clean as presented.
But, I found the problem interesting. So, I made this. This is the full constructor signature DynamicFuncSequence(method<, method_args><, method_kwargs_in_dict><, follow_up_intervals><, name=your_name>)
So, the example is DynamicFuncSequence(myFunc, 1, 2, {'k': 'k', 'w': 'w'}, Func(afterFinish))
For follow up intervals, I only checked for (Func, Sequence, Interval) which likely isn’t correct/full as you can in init.
from direct.interval.IntervalGlobal import *
from direct.showbase.ShowBase import ShowBase
from direct.directnotify.DirectNotify import DirectNotify
notify = DirectNotify().newCategory("Game::Logger")
class Game(ShowBase):
def __init__(self):
ShowBase.__init__(self)
class DynamicFuncSequence(Sequence):
def __init__(self, func, *args_ivals, name=""):
super(Sequence, self).__init__(name=name) # behavior of other keywords is unknown
ival_idx = -1
for i in range(0, len(args_ivals)):
if isinstance(args_ivals[i], (Func, Sequence, Interval)): # this list need to change, I'm sure
ival_idx = i
break
if ival_idx != -1:
if ival_idx == 0:
parms, ivals = None, args_ivals
else:
parms, ivals = args_ivals[:ival_idx], args_ivals[ival_idx:]
elif len(args_ivals) > 0:
parms, ivals = args_ivals, ()
else:
parms, ivals = None, ()
if parms is not None:
if isinstance(parms[-1], dict):
pre, kw = parms[:-1], parms[-1] # empty pre means not positional args
if pre == ():
self.args = None
self.kwargs = kw
else:
self.args = pre
self.kwargs = kw
else:
self.args = parms
self.kwargs = None
else:
self.args = None
self.kwargs = None
self._func_ = func
# self.ivals = [Func(self.wrapper), ]
self.later_ivals = ivals
self.do_continue = True
self.append(Func(self.wrapper))
def isPlaying(self):
return self.do_continue or super(DynamicFuncSequence, self).isPlaying()
def continue_running(self):
if self.do_continue:
base.taskMgr.do_method_later(0, lambda x: self.start(), 'do_sequence_later')
def wrapper(self):
if self.args is not None and self.kwargs is not None:
self._func_(*((self, ) + self.args), **self.kwargs)
elif self.kwargs is not None:
self._func_(*(self, ), **self.kwargs)
else:
self._func_(*(self, ))
if self.isPlaying():
self.continue_running()
def quit(self):
self.do_continue = False
self.finish()
if self.later_ivals:
seq = Sequence()
for i in range(0, len(self.later_ivals)):
seq.append(self.later_ivals[i])
base.taskMgr.do_method_later(0, lambda x: seq.start(), 'DynamicFuncSequence')
# end DynamicFuncSequence
run_count = 0
def myFunc(*args, **kwargs):
nonlocal run_count
run_count += 1
seq = args[0]
notify.warning('myFunc count {} isPlaying {}'.format(run_count, seq.isPlaying()))
if run_count == 10 and seq.isPlaying():
notify.warning("run count hit")
seq.quit()
pass
def beforeSeq():
notify.warning("before all")
def afterFinish(seq=None):
notify.warning('after finish')
dyn = DynamicFuncSequence(myFunc, 1, 2, {'k': 'k', 'w': 'w'}, Func(afterFinish))
se = Sequence(Func(beforeSeq), dyn)
se.start()