| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- from libpandaexpressModules import *
- from DirectNotify import *
- from PythonUtil import *
- import time
- exit = -1
- done = 0
- cont = 1
- # Store the global clock
- globalClock = ClockObject.getGlobalClock()
- def getTimeFrame():
- # WARNING: If you are testing tasks without an igloop,
- # you must manually tick the clock
- # Ask for the time last frame
- t = globalClock.getTime()
-
- # Get the new frame count
- f = globalClock.getFrameCount()
- return t, f
- class Task:
- def __init__(self, callback):
- self.__call__ = callback
- self.uponDeath = None
-
- def setStartTimeFrame(self, startTime, startFrame):
- self.starttime = startTime
- self.startframe = startFrame
-
- def setCurrentTimeFrame(self, currentTime, currentFrame):
- # Calculate and store this task's time (relative to when it started)
- self.time = currentTime - self.starttime
- self.frame = currentFrame - self.startframe
- def doLater(delayTime, task, taskName):
- task.name = taskName
- # make a sequence out of the delay and the task
- seq = sequence(pause(delayTime), task)
- return seq
- def spawnMethodNamed(self, func, name):
- task = Task(func)
- self.spawnTaskNamed(task, name)
-
- def pause(delayTime):
- def func(self):
- if (self.time < self.delayTime):
- return cont
- else:
- # Time is up, return done
- TaskManager.notify.debug('pause done: ' + self.name)
- return done
- task = Task(func)
- task.name = 'pause'
- task.delayTime = delayTime
- return task
- def release():
- def func(self):
- # A release is immediately done
- TaskManager.notify.debug('release done: ' + self.name)
- return done
- task = Task(func)
- task.name = 'release'
- return task
- def sequence(*taskList):
- return make_sequence(taskList)
- def make_sequence(taskList):
- def func(self):
- # If we got to the end of the list, this sequence is done
- if (self.index >= len(self.taskList)):
- TaskManager.notify.debug('sequence done: ' + self.name)
- return done
- else:
- task = self.taskList[self.index]
- # If this is a new task, set it's start time and frame
- if (self.index > self.prevIndex):
- task.setStartTimeFrame(self.time, self.frame)
- self.prevIndex = self.index
- # Calculate this task's time since it started
- task.setCurrentTimeFrame(self.time, self.frame)
-
- # Execute the current task
- ret = task(task)
- # Check the return value from the task
- # If this current task wants to continue,
- # come back to it next frame
- if (ret == cont):
- return cont
-
- # If this task is done, increment the index so that next frame
- # we will start executing the next task on the list
- elif (ret == done):
- self.index = self.index + 1
- return cont
- # If this task wants to exit, the sequence exits
- elif (ret == exit):
- return exit
- task = Task(func)
- task.name = 'sequence'
- task.taskList = taskList
- task.prevIndex = -1
- task.index = 0
- return task
- def makeSpawner(task, taskName, taskMgr):
- def func(self):
- self.taskMgr.spawnTaskNamed(self.task, self.taskName)
- return done
- newTask = Task(func)
- newTask.name = taskName + "-spawner"
- newTask.task = task
- newTask.taskName = taskName
- newTask.taskMgr = taskMgr
- return newTask
- def makeSequenceFromTimeline(timelineList, taskMgr):
- timeline = []
- lastPause = 0
- sortedList = list(timelineList)
- sortedList.sort()
- for triple in sortedList:
- t = triple[0] - lastPause
- lastPause = triple[0]
- task = triple[1]
- taskName = triple[2]
- timeline.append(pause(t))
- timeline.append(makeSpawner(task, taskName, taskMgr))
- return make_sequence(timeline)
- def timeline(*timelineList):
- def func(self):
- # Step our sub task manager (returns the number of tasks remaining)
- lenTaskList = self.taskMgr.step()
-
- # The sequence start time is the same as our start time
- self.sequence.time = self.time
- self.sequence.frame = self.frame
-
- if (not self.sequenceDone):
- # Execute the sequence for this frame
- seqRet = self.sequence(self.sequence)
- # See if sequence is done
- if (seqRet == done):
- self.sequenceDone = 1
- # See if the timeline is done
- if (lenTaskList == 0):
- TaskManager.notify.debug('timeline done: ' + self.name)
- return done
- else:
- return cont
- else:
- return cont
- else:
- return cont
- task = Task(func)
- task.name = 'timeline'
- task.taskMgr = TaskManager()
- task.sequence = makeSequenceFromTimeline(timelineList, task.taskMgr)
- task.sequenceDone = 0
- return task
- class TaskManager:
- notify = None
-
- def __init__(self):
- self.running = 0
- self.stepping = 0
- self.taskList = []
- self.currentTime, self.currentFrame = getTimeFrame()
- if (TaskManager.notify == None):
- TaskManager.notify = directNotify.newCategory("TaskManager")
- # TaskManager.notify.setDebug(1)
- def stepping(value):
- self.stepping = value
- def spawnMethodNamed(self, func, name):
- task = Task(func)
- return self.spawnTaskNamed(task, name)
-
- def spawnTaskNamed(self, task, name):
- TaskManager.notify.debug('spawning task named: ' + name)
- task.name = name
- task.setStartTimeFrame(self.currentTime, self.currentFrame)
- self.taskList.append(task)
- return task
- def doMethodLater(self, delayTime, func, taskName):
- task = Task(func)
- seq = doLater(delayTime, task, taskName)
- return self.spawnTaskNamed(seq, 'doLater-' + taskName)
- def removeAllTasks(self):
- # Make a shallow copy so we do not modify the list in place
- taskListCopy = self.taskList[:]
- for task in taskListCopy:
- self.removeTask(task)
- def removeTask(self, task):
- TaskManager.notify.debug('removing task: ' + `task`)
- try:
- self.taskList.remove(task)
- except:
- pass
- if task.uponDeath:
- task.uponDeath(task)
- def removeTasksNamed(self, taskName):
- removedTasks = []
- TaskManager.notify.debug('removing tasks named: ' + taskName)
-
- # Find the tasks that match by name and make a list of them
- for task in self.taskList:
- if (task.name == taskName):
- removedTasks.append(task)
- # Now iterate through the tasks we need to remove and remove them
- for task in removedTasks:
- self.removeTask(task)
- # Return the number of tasks removed
- return len(removedTasks)
- def step(self):
- TaskManager.notify.debug('step')
- self.currentTime, self.currentFrame = getTimeFrame()
- for task in self.taskList:
- task.setCurrentTimeFrame(self.currentTime, self.currentFrame)
- # Run the task and check the return value
- if task.name == 'test':
- print 'before task'
- ret = task(task)
- if task.name == 'test':
- print 'after task'
- if (ret == cont):
- continue
- elif (ret == done):
- self.removeTask(task)
- elif (ret == exit):
- self.removeTask(task)
- else:
- raise 'invalid task state'
- return len(self.taskList)
- def run(self):
- # Set the clock to have last frame's time in case we were
- # Paused at the prompt for a long time
- t = globalClock.getTime()
- globalClock.setTime(t)
- if self.stepping:
- self.step()
- else:
- self.running = 1
- while self.running:
- try:
- self.step()
- except KeyboardInterrupt:
- self.stop()
- except:
- raise
- def stop(self):
- # Set a flag so we will stop before beginning next frame
- self.running = 0
- def __repr__(self):
- str = ''
- str = str + 'taskList\n'
- str = str + '--------------------\n'
- for task in self.taskList:
- str = str + ' ' + task.name + '\n'
- return str
- """
- import Task
- from ShowBaseGlobal import * # to get taskMgr, and run()
- # sequence
- def seq1(state):
- print 'seq1'
- return Task.done
- def seq2(state):
- print 'seq2'
- return Task.done
- t = Task.sequence(Task.pause(1.0), Task.Task(seq1), Task.release(),
- Task.pause(3.0), Task.Task(seq2))
- taskMgr.spawnTaskNamed(t, 'sequence')
- run()
- # timeline
- def keyframe1(state):
- print 'keyframe1'
- return Task.done
- def keyframe2(state):
- print 'keyframe2'
- return Task.done
- def keyframe3(state):
- print 'keyframe3'
- return Task.done
-
- testtl = Task.timeline(
- (0.5, Task.Task(keyframe1), 'key1'),
- (0.6, Task.Task(keyframe2), 'key2'),
- (0.7, Task.Task(keyframe3), 'key3')
- )
- t = taskMgr.spawnTaskNamed(testtl, 'timeline')
- run()
- # do later - returns a sequence
- def foo(state):
- print 'later...'
- return Task.done
- seq = Task.doLater(3.0, Task.Task(foo), 'fooLater')
- t = taskMgr.spawnTaskNamed(seq, 'doLater-fooLater')
- run()
- # tasks with state
- # Combined with uponDeath
- someValue = 1
- def func(state):
- if (state.someValue > 10):
- print 'true!'
- return Task.done
- else:
- state.someValue = state.someValue + 1
- return Task.cont
- def deathFunc(state):
- print 'Value at death: ', state.someValue
- task = Task.Task(func)
- # set task state here
- task.someValue = someValue
- # Use instance variable uponDeath to specify function
- # to perform on task removal
- # Default value of uponDeath is None
- task.uponDeath = deathFunc
- t = taskMgr.spawnTaskNamed(task, 'funcTask')
- run()
- """
|