2001-01-25 00:07:53 +00:00

373 lines
10 KiB
Python

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()
"""