Pause and Resume

Does P3D come with a built in func/method for pausing a Game and Resuming, or do I have to “hard code” it in?

Deja vu lol. [url=https://discourse.panda3d.org/t/shouldnt-panda-have-a-pause-feature-built-in/7584/1]

So I guess the answer would be, you have to do it yourself. Not a hard thing to do, but very time consuming depending on your game.

I would need all world action to stop in place and not move, while my GUI is still alive.

I will wait until my game is almost “wrapped up” before I implement the pause because it can get tricky; especially if you want everything to stop exactly. That is, animation frame, actions, special effects, etc. would have to freeze in place, but then continue once the game is resumed.

The easiest way would be to simply store the state/action of everything, cause it to go into a loop where it’s just waiting for the game to resume, then restore all states/actions.

For instance, a bullet might be traveling to point(10,40,60). During a pause, that bullet would simply stop in place (and not interact with anything), but it will never forget where it was heading, so it can continue to its target later, which would be point(10,40,60).

I’ve actually “coded” a pause before in a game of mine. It’s just a pain to do it right down to the “nitty gritty.” You can however write a softer version of a pause, where it’s not so strict but makes sure certain key things don’t happen like a player taking damage while the main menu it up (even with the enemy still swinging a sword).

Not sure if it’s enough for you :
discourse.panda3d.org/viewtopic.php?t=4439

I gave this topic some thought and came up with the following idea:

  1. A distinction of tasks is required, between those having inpact on the game (let’s call those game-tasks) and fulltime tasks like rendering, culling, events etc.

  2. To pause and resume the game one would stop and resume all tasks from game-tasks.

  3. One step further, time dependency of all in-task functions implied, one could artificially control the output of getDt(). Simply multiplying the value of that function with a taskmanager global factor would make all movement act like in slowmotion or speedup.

Problems:
Intervals, Actor animations, sound-, and video loops all use the one and only global taskMgr, which is hardcoded.
So to overcome that one would need to rewrite lots of these classes. I have no idea if that’s even possible in all cases (it only is possible for the Python part AFAIK).

I’d like to try out that idea, but I’m uncertain what would be the best approach. Following ways jump to my mind:
-defining a special task chain (that would do for grouping and pausing, but no idea about modifying speed)
-putting all game-tasks in a single, specially managed task run by the global task manager
-something else?

I’m really missing support from Panda in terms of managing pause or dynamic time shifts.
Any help on this topic is welcome.

With a tip from rdb I got this snippet working. It’s dynamic slowmotion and speedup. Probably not the best way to pause a game, but for that I’d use a special task chain with frame budget of 0 anyway.

from direct.showbase.ShowBase import *
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import Point3, FrameRateMeter, ClockObjectfrom direct.showbase.ShowBase import *
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import Point3, FrameRateMeter, ClockObject
from direct.gui.DirectGui import *
from math import sin

ShowBase()

#globalClock.setMode(globalClock.MNonRealTime)
#globalClock.setDt(1.0/30)

smiley = loader.loadModel("smiley")
smiley.reparentTo(render)
smiley.setY(10)

i = LerpPosInterval(smiley, 10, Point3(0,10,3))
i.start()
i.loop()


def toggleClockMode():
	if globalClock.getMode() is globalClock.MNonRealTime:
		print "setting clock to realtime"
		globalClock.setMode(globalClock.MNormal)
		globalClock.setRealTime(globalClock.getFrameTime()) # option 1
	else:
		print "setting clock to non realtime"
		globalClock.setMode(globalClock.MNonRealTime)

slider = DirectSlider(range=(1.0/1, 1.0/300000), value=1.0/30, pageSize=3)
slider.setZ(-0.8)
button = DirectButton(command=toggleClockMode)
button.setScale(0.3)
button.setPos(-1.1, 0, -0.8)

def setFrameSpeed(task):
    globalClock.setDt(slider["value"])
    #globalClock.setRealTime(globalClock.getFrameTime()) # option 2
    return task.cont

def printIt(task):from direct.showbase.ShowBase import *
from direct.interval.IntervalGlobal import *
from pandac.PandaModules import Point3, FrameRateMeter, ClockObject
from direct.gui.DirectGui import *
from math import sin

ShowBase()

#globalClock.setMode(globalClock.MNonRealTime)
#globalClock.setDt(1.0/30)

smiley = loader.loadModel("smiley")
smiley.reparentTo(render)
smiley.setY(10)

i = LerpPosInterval(smiley, 10, Point3(0,10,3))
i.start()
i.loop()


def toggleClockMode():
	if globalClock.getMode() is globalClock.MNonRealTime:
		print "setting clock to realtime"
		globalClock.setMode(globalClock.MNormal)
		globalClock.setRealTime(globalClock.getFrameTime()) # option 1
	else:
		print "setting clock to non realtime"
		globalClock.setMode(globalClock.MNonRealTime)

slider = DirectSlider(range=(1.0/1, 1.0/300000), value=1.0/30, pageSize=3)
slider.setZ(-0.8)
button = DirectButton(command=toggleClockMode)
button.setScale(0.3)
button.setPos(-1.1, 0, -0.8)

def setFrameSpeed(task):
    globalClock.setDt(slider["value"])
    #globalClock.setRealTime(globalClock.getFrameTime()) # option 2
    return task.cont

def printIt(task):
	print "check"
	return task.again

taskMgr.doMethodLater(3, printIt, "periodical print")
taskMgr.add(setFrameSpeed, "set frame speed")
run()

	print "check"
	return task.again

taskMgr.doMethodLater(3, printIt, "periodical print")
taskMgr.add(setFrameSpeed, "set frame speed")
run()

from direct.gui.DirectGui import *
from math import sin

ShowBase()

#globalClock.setMode(globalClock.MNonRealTime)
#globalClock.setDt(1.0/30)

smiley = loader.loadModel("smiley")
smiley.reparentTo(render)
smiley.setY(10)

i = LerpPosInterval(smiley, 10, Point3(0,10,3))
i.start()
i.loop()


def toggleClockMode():
	if globalClock.getMode() is globalClock.MNonRealTime:
		print "setting clock to realtime"
		globalClock.setMode(globalClock.MNormal)
		globalClock.setRealTime(globalClock.getFrameTime()) # option 1
	else:
		print "setting clock to non realtime"
		globalClock.setMode(globalClock.MNonRealTime)

slider = DirectSlider(range=(1.0/1, 1.0/300000), value=1.0/30, pageSize=3)
slider.setZ(-0.8)
button = DirectButton(command=toggleClockMode)
button.setScale(0.3)
button.setPos(-1.1, 0, -0.8)

def setFrameSpeed(task):
    globalClock.setDt(slider["value"])
    #globalClock.setRealTime(globalClock.getFrameTime()) # option 2
    return task.cont

def printIt(task):
	print "check"
	return task.again

taskMgr.doMethodLater(3, printIt, "periodical print")
taskMgr.add(setFrameSpeed, "set frame speed")
run()

Press the button on the lower left to switch clock modes. The slider sets the framerate.
Notice that on speedup, timed tasks also are affected. So if you speed up the smiley-interval, the print comes more often, too.

The two options marked in code are for syncing the two clocks. This way, if you exit NonRealTime all animations are going on smoothly.

Only problem with this: No possibility to group affected tasks and not affected and the FPS meter is all wrong.