|
|
|
| Author |
Message |
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
Some related topics :
http://www.panda3d.org/phpbb2/viewtopic.php?t=2579
http://www.panda3d.org/phpbb2/viewtopic.php?t=2116
I took different route than those.
main.py :
| Code: | from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from direct.interval.IntervalGlobal import *
from direct.gui.OnscreenText import OnscreenText
from direct.directutil.Mopath import Mopath
from direct.actor.Actor import Actor
from direct.task import Task
import direct.directbase.DirectStart
import os,sys, random
from PRtest_smileyClass import Smiley
from PRtest_pandaClass import Panda
import PauseResume as PR
unstoppable_namePrefix='unstoppable-'
class World(DirectObject):
def __init__(self):
camera.setPos(10.00, -40.00, 15.00)
camera.setHpr(18.43, -21.57, 0.00)
mat=Mat4(camera.getMat())
mat.invertInPlace()
base.mouseInterfaceNode.setMat(mat)
self.accept('escape',sys.exit)
self.accept('enter',self.printTask_n_IvalMgr)
self.accept('space',self.toggleSceneActive)
self.isPaused=0
lilsmi=loader.loadModel('misc/lilsmiley')
lilsmi.reparentTo(aspect2d)
lilsmi.getChild(0).setScale(.2)
lilsmi.getChild(0).setAlphaScale(.5)
taskMgr.add( self.moveLilsmi, unstoppable_namePrefix+'moveLilsmi',
extraArgs=[lilsmi,lilsmi.getChild(0)] )
OnscreenText('unstoppable\ntask',parent=lilsmi,scale=.05,pos=(0,-.15),fg=(1,1,1,1))
lilsmi2=loader.loadModel('misc/lilsmiley').copyTo(aspect2d)
lilsmi2.getChild(0).setScale(.2)
OnscreenText('unstoppable\ninterval',parent=lilsmi2,scale=.05,pos=(0,-.15),fg=(1,1,1,1))
Sequence( lilsmi2.posInterval(5,Point3(-.9,0,.9),Point3(.9,0,.9)),
lilsmi2.posInterval(5,Point3(.9,0,.9),Point3(-.9,0,.9)),
name=unstoppable_namePrefix+'smiIval').loop()
barDuration=2
OT=OnscreenText('doLater 0',scale=.075,fg=(1,1,1,1),align=TextNode.ARight,mayChange=1)
OT.index=0
NodePath(OT).setPos(render2d,.95,0,-.95)
T=taskMgr.doMethodLater(barDuration,self.updateText,'updateText',[OT])
CM=CardMaker('')
card=render2d.attachNewNode(CM.generate())
card.setPos(-1,0,-1)
card.scaleInterval(barDuration,Vec3(2,1,.04),Vec3(1e-5,1,.04)).loop()
## create smileys
self.smileys=Smiley()
#### create pandas
num=7
self.pandas=[Panda() for p in xrange(num)]
# Ralph
ralphLoc='../samples/Roaming-Ralph/models/'
self.Ralph = Actor(ralphLoc+'ralph',{'walk':ralphLoc+'ralph-walk','run':ralphLoc+'ralph-run'})
# self.Ralph.enableBlend()
# interpolate frames
# self.Ralph.find('**/+Character').node().getBundle(0).setFrameBlendFlag(1)
# self.Ralph.setControlEffect('walk', .5)
# self.Ralph.setControlEffect('run', .5)
# self.Ralph.loop('run')
self.Ralph.loop('walk')
self.Ralph.reparentTo(render)
self.Ralph.setPos(-2,-15,0)
# self.Ralph.setTag('nopause','') # to exclude this actor from getting paused
# Eve
eveLoc='../samples/Looking-and-Gripping/models/'
self.Eve = Actor(eveLoc+'eve', {'walk' : eveLoc+'eve_walk'})
self.Eve.reparentTo(render)
self.Eve.setPos(2,-15,0)
self.Eve.actorInterval("walk", playRate = 2).loop()
# self.Eve.setTag('nopause','') # to exclude this actor from getting paused
# motion path interval
np=render2d.attachNewNode('')
child=np.attachNewNode('')
LS=LineSegs()
NC=NurbsCurve()
NC.setOrder(2)
num=100
degInc=360./num
for v in range(num):
np.setR(-v*degInc)
child.setX(.6+.3*random.random())
x, z = child.getX(render2d),child.getZ(render2d)
NC.appendCv(x,0,z)
LS.drawTo(x,0,z)
if v==0: ox,oz=x,z
LS.drawTo(ox,0,oz)
NC.recompute()
render2d.attachNewNode(LS.create())
s=loader.loadModel('misc/lilsmiley')
s.reparentTo(render2d)
s.setScale(.07)
Sequence(
s.colorScaleInterval(.5,Vec4(0,0,0,1)),
s.colorScaleInterval(.5,Vec4(1)),
# to make it not pausable
# name=unstoppable_namePrefix+'colorscale-%s'%id(s)
).loop()
mp=Mopath('mp1')
mp.loadNodePath(NodePath(NC))
mpi=MopathInterval( mp, s, duration=30,
# to make it not pausable
# name=unstoppable_namePrefix+'mopath-%s'%id(mp)
)
mpi.loop()
# pausable sound
# s1=loader.loadSfx('/use/your/own/sound/file')
# s1.setVolume(.7)
# s1.setLoop(1)
# # s1.setPausable(0) # to make it not pausable
# s1.play()
# background sound that keeps playing
# s2=loader.loadSfx('/use/your/own/sound/file')
# s2.setVolume(.3)
# s2.setLoop(1)
# s2.setPausable(0) # to make it not pausable
# s2.play()
# movie texture
# movie='../samples/Media-Player/PandaSneezes.avi'
# movTex=loader.loadTexture(movie)
# movTexUV=movTex.getTexScale()
# CM=CardMaker('')
# CM.setFrameFullscreenQuad()
# CM.setUvRange(movTex)
# card=render.attachNewNode(CM.generate())
# card.setTwoSided(1)
# scale=8
# card.setScale(movTexUV[0]*scale,1,movTexUV[1]*scale)
# card.setPos(-15,5,2)
# card.setTexture(movTex)
# playAudioToo=1 # play audio ?
# pausable=1
# if playAudioToo:
# mA=loader.loadSfx(movie)
# mA.setLoop(1)
# mA.play()
# mA.setPausable(pausable) # to make it pausable or not
# movTex.synchronizeTo(mA)
# else:
# movTex.play()
# movTex.setPausable(pausable) # to make it pausable or not
# RTT
textParent=NodePath('')
text = OnscreenText(parent=textParent,text="You can't\npause me\nHO HO HO")
b3=text.getTightBounds()
bHalf=(b3[0]+b3[1])*.5
b=(b3[1]-b3[0])*.5
ratio=b[0]/b[2]
b.setZ(b[0]) if ratio>1 else b.setX(b[2])
b*=1.05 # give a little gap from the border, to avoid artifact on texture's small mip level
textBuffer = base.win.makeTextureBuffer('text buffer', 512,512)
textBuffer.setClearColor(Vec4(1))
textCam = base.makeCamera2d(textBuffer)
textCam.reparentTo(textParent)
textCam.setPos(bHalf) # put it exactly at text's center
textCam.setScale(b[0],1,b[2]) # auto-zoom in to text
self.textTexture = textBuffer.getTexture()
self.textTexture.setMinfilter(Texture.FTLinearMipmapLinear)
base.graphicsEngine.renderFrame()
base.graphicsEngine.removeWindow(textBuffer)
self.setupLights()
self.loadFloor()
self.loadColliders()
taskMgr.doMethodLater(3,self.spawnNewPanda,'spawnNewPanda')
def spawnNewPanda(self,t):
p=Panda().pandaModel
p.setY(-10)
p.colorScaleInterval(3,Vec4(0,.7,0,1),Vec4(1)).start()
p.setTag('nopause','') # to exclude this actor from getting paused
proj = LensNode('proj')
proj.setLens(OrthographicLens())
proj=p.attachNewNode(proj)
proj.setScale(4)
proj.setZ(4.7)
p.projectTexture(TextureStage(''),self.textTexture,proj)
taskMgr.doMethodLater(3,p.cleanup,'removeNewPanda',extraArgs=[])
return Task.again
def setupLights(self):
ambientLight = AmbientLight( 'ambientLight' )
ambientLight.setColor( Vec4(.3, 0.3, 0.3, 1) )
self.ambientLight=render.attachNewNode( ambientLight )
render.setLight(self.ambientLight)
directionalLight = DirectionalLight( 'directionalLight1' )
directionalLight.setDirection( Vec3( 0, 2, -1 ) )
directionalLight.setColor( Vec4( .7, .7, .7, 1 ) )
self.directionalLight=render.attachNewNode( directionalLight )
render.setLight(self.directionalLight)
def loadFloor(self):
self.floorBit=BitMask32.bit(1)
self.sphereBit=BitMask32.bit(2)
self.offBit=BitMask32.allOff()
self.floor=loader.loadModel('misc/rgbCube')
self.floor.reparentTo(render)
self.floor.setScale(18,18,.2)
self.floor.setR(25)
self.floor.flattenLight()
box=loader.loadModel('box')
box.reparentTo(self.floor)
box.setScale(7,5,.5)
box.setPos(-4,2,1.5)
box.setR(-25)
self.floor.flattenLight()
self.floor.setPos(-5,-10,-7)
self.floor.setCollideMask(self.floorBit)
box.setCollideMask(self.floorBit|self.sphereBit)
self.floor.setLightOff(1)
self.floor.hprInterval(3,Vec3(360,0,0)).loop()
def loadColliders(self):
base.cTrav=CollisionTraverser()
base.cTrav.setRespectPrevTransform(1)
self.arrows=[]
for c in xrange(5):
arrow=loader.loadModel('misc/Spotlight')
arrow.reparentTo(render)
arrow.setP(90)
arrow.setScale(.3)
arrow.setColor(.5+.5*random.random(),.5+.5*random.random(),.5+.5*random.random())
arrow.flattenStrong()
arrow.setPos(self.floor,random.uniform(-4,4),random.uniform(-4,4),10)
rayNP = arrow.attachCollisionRay('', 0,0,2, 0,0,-1, self.floorBit,self.offBit)
rayNP.show()
sphereNP = arrow.attachCollisionSphere('', 0,0,1.5, .7, self.sphereBit,self.sphereBit)
# sphereNP.show()
CHgravity = CollisionHandlerGravity()
CHgravity.addCollider(rayNP,arrow)
CHpusher= CollisionHandlerPusher()
CHpusher.addCollider(sphereNP,arrow)
base.cTrav.addCollider(rayNP,CHgravity)
base.cTrav.addCollider(sphereNP,CHpusher)
self.arrows.append([arrow,CHgravity])
taskMgr.add(self.moveArrows, 'move arrows')
def moveArrows(self,task):
dt=globalClock.getDt()
if dt>.2: return Task.cont
speed=10*dt
for a,CHG in self.arrows:
if CHG.isOnGround():
a.setH(a,random.uniform(-20,20))
lastPos=a.getPos()
a.setFluidY(a,speed)
pos=a.getPos(self.floor)
if not ( (-5 < pos[0] < 5) and (-5 < pos[1] < 5) ):
a.setFluidPos(lastPos)
a.headsUp(self.floor) # looks at floor while stays upright
a.setFluidY(a,speed)
return Task.cont
def moveLilsmi(self,np,geom):
dt=globalClock.getDt()
if dt>.2: return Task.cont
geom.setR(geom,random.uniform(-10,10))
speed=1.5*dt
np.setZ(geom,speed)
if np.getDistance(aspect2d)>.5:
geom.setR(geom,180)
np.setZ(geom,speed)
return Task.cont
def updateText(self,text):
text.index+=1
text['text']='doLater %s'%text.index
return Task.again
def printTask_n_IvalMgr(self):
print taskMgr
print taskMgr.getTasksNamed('move arrows')
print ivalMgr
def toggleSceneActive(self):
self.isPaused=not self.isPaused
if self.isPaused:
PR.pause( allAnims=0,
allAudios=0,
allMovies=0,
collision=1,
excludedTaskNamePrefix=unstoppable_namePrefix,
excludedIvalNamePrefix=unstoppable_namePrefix,
)
else:
PR.resume()
if __name__=='__main__':
World()
run() |
PRtest_pandaClass.py :
| Code: | from direct.actor.Actor import Actor
from random import random, uniform
class Panda:
def __init__(self):
self.pandaModel=Actor('panda',{'walk':'panda-walk'})
self.pandaModel.reparentTo(render)
scale=.2+random()*.7
self.pandaModel.setScale(scale)
self.pandaModel.setPos(uniform(-5,5),uniform(-2,6),0)
self.pandaModel.setColorScale(scale,scale,scale,1)
self.pandaModel.setPlayRate(1./scale,'walk')
self.pandaModel.setP(1/(.8*scale*scale))
self.pandaModel.loop('walk')
self.other=[]
|
PRtest_smileyClass.py :
| Code: | from pandac.PandaModules import Vec3
from direct.interval.IntervalGlobal import LerpFunc
from math import pi, sin
class Smiley:
def __init__(self):
scale=.8
num=int(10/scale)
self.smileys=[]
self.moves = [0 for i in xrange(num)]
self.roll = [0 for i in xrange(num)]
for s in xrange(num):
smi=loader.loadModel('smiley')
smi.reparentTo(render)
smi.setScale(scale)
smi.setPos((-(num-1)*.5+s)*scale*2,-6,scale*1.25)
self.smileys.append(smi)
self.moves[s] = LerpFunc(
self.oscilateSmiley,
duration = 2,
fromData = 0,
toData = 2*pi,
extraArgs=[self.smileys[s], pi*(s%2)]
)
self.moves[s].loop()
self.roll[s]=self.smileys[s].hprInterval(3.,Vec3(720,0,360))
self.roll[s].loop()
def oscilateSmiley(self, rad, np, offset):
np.setZ(sin(rad + offset) *.9)
|
PauseResume.py :
| Code: | __all__ = []
import sys,time
importTime = time.clock()
PRmodules = [k for k in sys.modules.keys() if k.find(__name__)>-1]
PRmodulesTime = [sys.modules[m].importTime for m in PRmodules]
PRmodulesTime.sort()
PRmod1stImport = [sys.modules[m] for m in PRmodules if sys.modules[m].importTime==PRmodulesTime[0]][0]
# print PRmodules,PRmodulesTime
if len(PRmodules)>1:
for k in PRmodules:
if importTime==sys.modules[k].importTime:
sys.modules[k] = PRmod1stImport
print 'WARNING : PauseResume module was ALREADY IMPORTED,\n using the 1st imported one.'
break
else:
import os
from direct.task import Task
directModulesDir=os.path.abspath(os.path.join(os.path.dirname(sys.modules[Task.__name__].__file__),os.pardir))
from pandac.extension_native_helpers import Dtool_funcToMethod
from pandac.PandaModules import AnimControl, AudioSound, MovieTexture, NodePath, PandaSystem, AsyncTaskManager
from direct.interval.IntervalGlobal import ivalMgr
from myMessenger import Messenger
atLeast16=PandaSystem.getMajorVersion()*10+PandaSystem.getMinorVersion()>=16
taskFunc=lambda t: t.getFunction() if atLeast16 else t.__call__
taskFuncNameQuery=lambda t: 'getFunction' if atLeast16 else '__call__'
taskXArgs=lambda t: t.getArgs() if atLeast16 else t.extraArgs
taskXArgsName=lambda t: 'getArgs' if atLeast16 else 'extraArgs'
taskWakeT=lambda t: t.getDelay() if atLeast16 else t.wakeTime
PRmsg = Messenger()
IDE_ivalsName = 'IDE_IVALS_'
IDE_tasksName = 'IDE_TASKS_'
PAUSED_TASKCHAIN_NAME = 'YNJH paused tasks'
isPaused = 0
resumeLocked = 0
# keeps the original C++ functions
AnimControl__origPlay=AnimControl.play
AnimControl__origLoop=AnimControl.loop
AnimControl__origPingpong=AnimControl.pingpong
AnimControl__origStop=AnimControl.stop
AudioSound__origPlay=AudioSound.play
AudioSound__origStop=AudioSound.stop
MovieTexture__origPlay=MovieTexture.play
MovieTexture__origStop=MovieTexture.stop
# defines the new method wrappers for intercepting messages
# ANIMATIONS ################################################################
def newAnimPlay(self):
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self,0])
PRmsg.accept('pauseNotTaggedAnims',self,pauseAnim,[self])
AnimControl__origPlay(self)
Dtool_funcToMethod(newAnimPlay,AnimControl,'play')
del newAnimPlay
def newAnimLoop(self,restart=1,_from=None,_to=None):
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self,0])
PRmsg.accept('pauseNotTaggedAnims',self,pauseAnim,[self])
if _from is not None and _to is not None :
AnimControl__origLoop(self,restart,_from,_to)
else:
AnimControl__origLoop(self,restart)
Dtool_funcToMethod(newAnimLoop,AnimControl,'loop')
del newAnimLoop
def newAnimPingpong(self,restart=1,_from=None,_to=None):
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self,0])
PRmsg.accept('pauseNotTaggedAnims',self,pauseAnim,[self])
if _from is not None and _to is not None :
AnimControl__origPingpong(self,restart,_from,_to)
else:
AnimControl__origPingpong(self,restart)
Dtool_funcToMethod(newAnimPingpong,AnimControl,'pingpong')
del newAnimPingpong
def newAnimStop(self):
for e in PRmsg.getAllAccepting(self):
PRmsg.ignore(e,self)
AnimControl__origStop(self)
Dtool_funcToMethod(newAnimStop,AnimControl,'stop')
del newAnimStop
def pauseAnim(self,respectTag=1):
if respectTag:
part=self.getPart()
for n in xrange(part.getNumNodes()):
if NodePath(part.getNode(n)).hasNetTag('nopause'):
return
PRmsg.ignore('pauseAllAnims',self)
PRmsg.ignore('pauseNotTaggedAnims',self)
PRmsg.accept('resumeAllAnims',self,resumeAnim,[self,self.getPlayRate()])
self.setPlayRate(0)
def resumeAnim(self,PR):
PRmsg.ignore('resumeAllAnims',self)
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self,0])
PRmsg.accept('pauseNotTaggedAnims',self,pauseAnim,[self])
self.setPlayRate(PR)
# AUDIO SOUNDS ##############################################################
notPausableSounds = []
invulnerableSounds = []
def newAudioPlay(self):
PRmsg.accept('pauseAllSounds',self,pauseAudio,[self,0])
PRmsg.accept('pausePausableSounds',self,pauseAudio,[self])
AudioSound__origPlay(self)
newAudioPlay.__doc__=AudioSound__origPlay.__doc__
Dtool_funcToMethod(newAudioPlay,AudioSound,'play')
del newAudioPlay
def newAudioStop(self):
for e in PRmsg.getAllAccepting(self):
PRmsg.ignore(e,self)
AudioSound__origStop(self)
newAudioStop.__doc__=AudioSound__origStop.__doc__
Dtool_funcToMethod(newAudioStop,AudioSound,'stop')
del newAudioStop
def setPausable(self,status):
if self in notPausableSounds:
notPausableSounds.remove(self)
if not status:
notPausableSounds.append(self)
Dtool_funcToMethod(setPausable,AudioSound)
del setPausable
def setInvulnerable(self,status):
if self in invulnerableSounds:
if status:
return
else:
invulnerableSounds.remove(self)
elif status:
invulnerableSounds.append(self)
Dtool_funcToMethod(setInvulnerable,AudioSound)
del setInvulnerable
def pauseAudio(self,respectTag=1):
if self in invulnerableSounds:
return
if respectTag:
if self in notPausableSounds:
return
PRmsg.ignore('pauseAllSounds',self)
PRmsg.ignore('pausePausableSounds',self)
PRmsg.accept('resumeAllSounds',self,resumeAudio,[self])
AudioSound__origStop(self)
self.setTime(self.getTime())
def resumeAudio(self):
PRmsg.ignore('resumeAllSounds',self)
PRmsg.accept('pauseAllSounds',self,pauseAudio,[self,0])
PRmsg.accept('pausePausableSounds',self,pauseAudio,[self])
AudioSound__origPlay(self)
# MOVIE TEXTURES ############################################################
notPausableMovies = []
def newMoviePlay(self):
PRmsg.accept('pauseAllMovies',self,pauseMovie,[self,0])
PRmsg.accept('pausePausableMovies',self,pauseMovie,[self])
MovieTexture__origPlay(self)
newMoviePlay.__doc__=MovieTexture__origPlay.__doc__
Dtool_funcToMethod(newMoviePlay,MovieTexture,'play')
del newMoviePlay
def newMovieStop(self):
for e in PRmsg.getAllAccepting(self):
PRmsg.ignore(e,self)
MovieTexture__origStop(self)
newMovieStop.__doc__=MovieTexture__origStop.__doc__
Dtool_funcToMethod(newMovieStop,MovieTexture,'stop')
del newMovieStop
def setPausable(self,status):
if self in notPausableMovies:
notPausableMovies.remove(self)
if not status:
notPausableMovies.append(self)
Dtool_funcToMethod(setPausable,MovieTexture)
del setPausable
def pauseMovie(self,respectTag=1):
if respectTag:
if self in notPausableMovies:
return
PRmsg.ignore('pauseAllMovies',self)
PRmsg.ignore('pausePausableMovies',self)
PRmsg.accept('resumeAllMovies',self,resumeMovie,[self])
MovieTexture__origStop(self)
def resumeMovie(self):
PRmsg.ignore('resumeAllMovies',self)
PRmsg.accept('pauseAllMovies',self,pauseMovie,[self,0])
PRmsg.accept('pausePausableMovies',self,pauseMovie,[self])
self.restart()
# INTERVALS #################################################################
def pauseIvals(excludeNamePrefix=''):
global pausedIvals
pausedIvals=ivalMgr.getIntervalsMatching('*')
excluded=[]
for i in pausedIvals:
if ( (excludeNamePrefix and i.getName().find(excludeNamePrefix)==0) or
i.getName().find(IDE_ivalsName)==0
):
excluded.append(i)
else:
#~ print 'PAUSED IVAL:',i.getName()
i.pause()
for e in excluded:
pausedIvals.remove(e)
def resumeIvals():
for i in pausedIvals:
i.resume()
# TASKS #####################################################################
def pauseTasks(excludedTaskNamePrefix,noCollision):
global unneededTasks
if not AsyncTaskManager.getGlobalPtr().findTaskChain(PAUSED_TASKCHAIN_NAME):
taskMgr.setupTaskChain(PAUSED_TASKCHAIN_NAME,
frameBudget=0) # frameBudget=0 doesn't allow any task to run
unneededTasksName=[]
# collects unneeded tasks
if noCollision:
unneededTasksName+=['collisionLoop','resetPrevTransform']
unneededTasks=[ taskMgr.getTasksNamed(tn)[0] for tn in unneededTasksName]
# collects all scene's tasks
for t in taskMgr.getTasks(): # ordinary tasks
if ( t and hasattr(t,taskFuncNameQuery(t)) and t.name.find(IDE_tasksName)!=0 and
( not excludedTaskNamePrefix or
(excludedTaskNamePrefix and t.name.find(excludedTaskNamePrefix))
)
):
func=taskFunc(t)
mod=func.__module__
# python-based intervals
if mod.find('direct.interval')==0:
if not (func.im_class.__name__=='ActorInterval' and\
func.im_self.actor.hasNetTag('nopause')):
unneededTasks.append(t)
t.interval.pause()
elif mod not in sys.modules or sys.modules[mod].__file__.find(directModulesDir)<0:
unneededTasks.append(t)
currT=globalClock.getFrameTime()
for t in taskMgr.getDoLaters(): # doLater tasks
if ( t and hasattr(t,taskFuncNameQuery(t)) and
( not excludedTaskNamePrefix or
(excludedTaskNamePrefix and t.name.find(excludedTaskNamePrefix)) )
):
unneededTasks.append(t)
# I need to alter the wakeTime during task resume,
# so I have to save the remaining time.
# Just save it as its attribute, nobody would notice :D
t.remainingTime=t.wakeTime-currT
# "pauses" tasks
for t in unneededTasks:
t.ORIG_extraArgs=taskXArgs(t) if hasattr(t,taskXArgsName(t)) else None
if hasattr(t,taskFuncNameQuery(t)):
t.ORIG_call=taskFunc(t)
t.ORIG_priority=t._priority if hasattr(t,'_priority') else t.getSort()
# only active tasks can be moved to other chain, so removes doLater
# tasks since they are in sleeping state
if hasattr(t,'remainingTime'): # doLater tasks
t.remove()
else: # ordinary tasks
t.lastactivetime=-t.time if hasattr(t,'time') else 0
try:
t.setTaskChain(PAUSED_TASKCHAIN_NAME)
except:
pass
def resumeTasks():
# restarts tasks
for t in unneededTasks:
if hasattr(t,'interval'): # it must be python-based intervals
t.interval.resume()
if hasattr(t,'ORIG_call'):
if atLeast16:
t.setFunction(t.ORIG_call)
else:
t.__call__=t.ORIG_call
else:
if hasattr(t,'remainingTime'): # doLater tasks
tempDelay=t.remainingTime-(globalClock.getRealTime()-globalClock.getFrameTime())
if hasattr(t,'uponDeath'):
uponDeath=t.uponDeath
else:
uponDeath=None
# no need to pass appendTask, since if it's already true,
# the task is already appended to extraArgs
newTask=taskMgr.doMethodLater( tempDelay, t.ORIG_call,
t.name, priority=t.ORIG_priority,
extraArgs=t.ORIG_extraArgs,
uponDeath=uponDeath)
# restore the original delayTime
if hasattr(t,'remainingTime'):
newTask.delayTime=t.delayTime
else: # ordinary tasks
t.setDelay(t.lastactivetime)
t.setTaskChain('default')
# very important to avoid assertion error on resume
t.clearDelay()
def pause( allAnims=0,allAudios=0,allMovies=0,collision=1,
excludedTaskNamePrefix='',excludedIvalNamePrefix='',
lowerLevelOperation=1
):
'''
allAnims : pause all animations or only the not "nopause" tagged ones
allAudios : pause all audio sounds or only the pausable ones
allMovies : pause all movies or only the pausable ones
collision : pause collision detection or not
excludedTaskNamePrefix : do not pause tasks with this name prefix
excludedIvalNamePrefix : do not pause intervals with this name prefix
lowerLevelOperation : <DO NOT use this>
'''
global isPaused,resumeLocked
if isPaused:
print 'WARNING : SCENE IS ALREADY PAUSED !'
return isPaused
PRmsg.send('pauseAllAnims') if allAnims else PRmsg.send('pauseNotTaggedAnims')
PRmsg.send('pauseAllSounds') if allAudios else PRmsg.send('pausePausableSounds')
PRmsg.send('pauseAllMovies') if allMovies else PRmsg.send('pausePausableMovies')
pauseIvals(excludedIvalNamePrefix)
pauseTasks(excludedTaskNamePrefix,collision)
base.disableParticles()
isPaused=1
resumeLocked=lowerLevelOperation
# print 'PR:',isPaused
return isPaused
def resume(lowerLevelOperation=1):
global isPaused,resumeLocked
if resumeLocked and not lowerLevelOperation:
# print 'WARNING : RESUME IS LOCKED'
return 2
if not isPaused:
print 'WARNING : SCENE IS ALREADY RESUMED'
return isPaused
PRmsg.send('resumeAllAnims') # resume all animations
PRmsg.send('resumeAllSounds') # resume all audio
PRmsg.send('resumeAllMovies') # resume all movie
resumeIvals()
resumeTasks()
base.enableParticles()
isPaused=0
# print 'PR:',isPaused
return isPaused |
NOTE :
myMessenger module is the old Messenger.py, you can use 1.5's, because 1.6's wants python-only receiver object.
http://panda3d.cvs.sf.net/viewvc/panda3d/direct/src/showbase/Messenger.py?revision=1.40.12.1&view=markup
Use SPACE to toggle pause/resume, ENTER to investigate taskMgr & ivalMgr.
One issue about doLater tasks :
I don't know what I missed, it's hard to get it right. The doLater task's wakeTime is reached to soon if I do pause/resume rapidly.
Last edited by ynjh_jo on Sun Nov 29, 2009 2:00 am; edited 13 times in total |
|
drwr
Posts: 8005 Location: Glendale, CA
 |
| Quote: | | I don't know what I missed, it's hard to get it right. |
You're not supposed to fiddle with task.wakeTime after it has been started. That really ought to be a private member, because if you change it, you invalidate the priority queue of tasks already stored in taskMgr, and thereby risk screwing up the wake times for other tasks than the one you are fiddling with.
The right thing to do is to compute the appropriate delayTime before re-queuing the task.
David |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
OK, I've tried it this way :
| Code: | if hasattr(t,'remainingTime'):
tempDelay=t.remainingTime-(globalClock.getRealTime()-taskMgr.currentTime)
else:
tempDelay=t.delayTime
# no need to pass appendTask, since if it's already true,
# the task is already appended to extraArgs
newTask=taskMgr.doMethodLater( tempDelay, t.ORIG_call,
t.name, priority=t.ORIG_priority,
extraArgs=t.ORIG_extraArgs,
uponDeath=uponDeath)
# restore the original delayTime
if hasattr(t,'remainingTime'):
newTask.delayTime=t.delayTime |
But it didn't help at all. _________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
treeform
 Posts: 2027 Location: Seattle
 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
What did you mean by that ? A task doesn't have _wakeTime attr. Did you mean wakeTime ? If so, I already use it originally. _________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
treeform
 Posts: 2027 Location: Seattle
 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
|
drwr
Posts: 8005 Location: Glendale, CA
 |
Well, ynjh_jo's second approach should have solved the problem, so maybe there are other problems I'm not seeing right now.
treeform, I understand what you're saying: you're suggesting that we rename task.wakeTime to task._wakeTime in our code to prevent similar misunderstands. Yes, I agree, and this is what I meant when I said it "really ought to be a private member". But this is low-level code that is already being used in several production games, so I'm reluctant to change it now without real good reason--we might accidentally break something somewhere that's querying task.wakeTime, for instance.
David |
|
treeform
 Posts: 2027 Location: Seattle
 |
|
drwr
Posts: 8005 Location: Glendale, CA
 |
This is just part of the cost of having a graphics engine that's actively being used for professional games--we have to be sensitive about compatibility issues like this. Sure, if we could rewrite everything from the ground up, we'd do it differently this time around, and fix all the stupid things we did the first time through. But if everyone wrote software this way, we'd never have any usable software, since everything would always be in rewrite.
Mostly, we've been dealing with this on a case-by-case basis: when an issue comes up, we evaluate (a) the urgency of fixing it and (b) the potential risk of making a change in that code. Then we decide whether it should be fixed, and if so, what is the plan for fixing it. If we accidentally "fix" something that we later discover breaks existing code, well, we just have to deal with that here at Disney. That's the flip side: part of the cost of developing professional games on a graphics engine that's open to the public.
There are parts of the system that might lend themselves to complete rewrites without risking breaking existing code. For instance, several people have proposed replacement gui interfaces, which don't interfere with the existing DirectGui stuff. I think this is great.
I sometimes wonder if we shouldn't rewrite the whole DirectStart/ShowBase thing at some point, and come up with a new way of starting Panda that doesn't do all the terrible things that the current system does (like shoving names into the builtin dictionary). If anyone tackled this, it would have to be a new system that completely replaces the old system, while still allowing the old system to work the way it always has.
David |
|
treeform
 Posts: 2027 Location: Seattle
 |
| Quote: | | I sometimes wonder if we shouldn't rewrite the whole DirectStart/ShowBase thing at some point, and come up with a new way of starting Panda that doesn't do all the terrible things that the current system does (like shoving names into the builtin dictionary). If anyone tackled this, it would have to be a new system that completely replaces the old system, while still allowing the old system to work the way it always has. |
What would be other things that you would fix? (besides the builtins pollution?) I am kinda interested in writing such a replacement but still don't feel that "direct" is in such a sad shape to warrant it. The talks of a panda3d "framework" on other threads and IRC makes me think of cool things to add (not just fix) that could warrant such a rewrite thought. Your thoughts?
If we do rewrites - i feel total rewrites are bad (being on several such projects in the past) we just need fork it and tackle it peace meal one class at a time. _________________ Panda3d IRC irc://irc.freenode.net/panda3d | BUGs https://bugs.launchpad.net/panda3d
My MMORTS game: http://aff2aw.com
GitHub: http://github.com/treeform | Twitter: http://twitter.com/treeform |
|
drwr
Posts: 8005 Location: Glendale, CA
 |
I would also change the way it opened a window automatically at startup, and probably rework the whole openWindow() system to be a little less magical. But, yeah, it's not really that bad now, which is one reason it's still the way it is.
It makes sense to integrate this kind of a redesign into a proposed framework system.
David |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
David, is it worth to extend AnimControl to entirely skip all anims if the Character it is bound to is stashed ?
So I can pause all anims simply by
| Code: | pausedActors=np.findAllMatches('**/+Character')
pausedActors.stash() |
and resume them by pausedActors.unstash()
Scanning Python namespaces for actors is slow.
About the doLater tasks, try to do 5 keypresses rate per second, for at least 5 seconds, and you'll see the doLater tasks get out of sync to the whitebar's interval. _________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
drwr
Posts: 8005 Location: Glendale, CA
 |
| Quote: | | David, is it worth to extend AnimControl to entirely skip all anims if the Character it is bound to is stashed ? |
The AnimControl has no way of knowing whether the Character is stashed. In fact, asking whether a node is stashed doesn't always have an answer, because a node might have multiple instances, and some of them might be stashed and others unstashed. Furthermore, I don't think skipping animations on stashed Characters is the right behavior, anyway--you might want to start the animations, and then immediately unstash the model and you would expect to see the animations playing.
David |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
CONGRATULATIONS !!
(I hope nobody would mind if I congratulate myself)
pause/resume animation :
Finally I think I can put aside the stupid namespaces scanning idea for good.
I've figured out the simplest hack to pause/resume all animations correctly, by taking advantage of Dtool and Messenger. This works too with blended animations, since I directly strike the heart of the animation system's base class : AnimInterface.
| Code: | PRmsg=Messenger()
# keeps the original C++ functions
AnimInterface.DtoolClassDict['__origPlay']=AnimInterface.play
AnimInterface.DtoolClassDict['__origLoop']=AnimInterface.loop
AnimInterface.DtoolClassDict['__origPingpong']=AnimInterface.pingpong
AnimInterface.DtoolClassDict['__origStop']=AnimInterface.stop
# defines the new method wrappers for intercepting messages
def newAnimPlay(self):
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self])
self.__origPlay()
Dtool_funcToMethod(newAnimPlay,AnimInterface,'play')
del newAnimPlay
def newAnimLoop(self,restart=1,_from=None,_to=None):
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self])
if _from is not None and _to is not None :
self.__origLoop(restart,_from,_to)
else:
self.__origLoop(restart)
Dtool_funcToMethod(newAnimLoop,AnimInterface,'loop')
del newAnimLoop
def newAnimPingpong(self,restart=1,_from=None,_to=None):
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self])
if _from is not None and _to is not None :
self.__origPingpong(restart,_from,_to)
else:
self.__origPingpong(restart)
Dtool_funcToMethod(newAnimPingpong,AnimInterface,'pingpong')
del newAnimPingpong
def newAnimStop(self):
evts=PRmsg.getAllAccepting(self)
for e in evts:
PRmsg.ignore(e,self)
self.__origStop()
Dtool_funcToMethod(newAnimStop,AnimInterface,'stop')
del newAnimStop
def pauseAnim(self):
PRmsg.ignore('pauseAllAnims',self)
PRmsg.accept('resumeAllAnims',self,resumeAnim,[self,self.getPlayRate()])
self.setPlayRate(0)
# print id(self),lastPR
def resumeAnim(self,PR):
self.setPlayRate(PR)
PRmsg.ignore('resumeAllAnims',self)
PRmsg.accept('pauseAllAnims',self,pauseAnim,[self])
# print id(self),PR |
What does anybody think ? _________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
I made up my mind. I think it'd be better if I strike AnimControl instead, so I can exclude some actors from getting paused, in case there is any freak want this behavior. I did it simply by setting a tag on the actor.
The pause method now :
| Code: | def pauseAnim(self):
part=self.getPart()
for n in xrange(part.getNumNodes()):
if NodePath(part.getNode(n)).hasNetTag('nopause'):
return
PRmsg.ignore('pauseAllAnims',self)
PRmsg.accept('resumeAllAnims',self,resumeAnim,[self,self.getPlayRate()])
self.setPlayRate(0)
# print id(self),lastPR |
_________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
Another update.
1. added actors exclusion refusal. It's done per pause() call, if you pass allAnims=0, the "nopause" tagged actors won't be paused, allAnims=1 will pause all actors.
2. This one is to keep it compatible with my IDE. My IDE also uses this module, so it's possible to use this module too in the test scene. Naturally, my IDE uses its PauseResume module, and the test scene uses its own module. So there are 2 exactly the same PauseResume modules, but located at different places, so they are loaded twice at runtime, and exist twice in sys.modules. I've set it up so there is only 1 module reference across the app. I did it by replacing the 2nd loaded module by the 1st loaded one. It's also to keep the consistency of paused/resumed status, seen by the IDE and the test scene. To keep this status safe, i.e. not paused/resumed twice, I give my IDE no privilege to pause/resume when the scene already paused itself. If I don't do this, when the scene is paused due to menu popup or something, and I go back to my IDE and resume it, I can't imagine the havoc would happen. To let this works correctly, don't change module's name, keep it "PauseResume". _________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
UPDATE :
1. sounds now paused individually instead of at audioLoop level, so it's possible to exclude some sounds from getting paused, e.g. background music.
2. same thing applied to movie textures, with or without sound synchronization. _________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
UPDATE :
[_1_] 1.6 compatible,
[_2_] fixed actor interval pause
[_3_] added actor interval and motion path interval into the sample _________________ http://ynjh.panda3dprojects.com | http://ynjh.p3dp.com
Intel P4Prescott 2.8GHz HT | Elixir 1.5GB | ATI HD4670 1GB GDDR3 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
|
ynjh_jo
 Posts: 1596 Location: Malang, Indonesia
 |
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
| | |