Hi all,
Hope my questions make some sort of sense. New to game dev (Some friends and I decided to make an RTS game).
From reading around most RTS games seems to use some sort of fixed-step game logic update (e.g. 15 fps) to be perfectly deterministic while allowing the rendering to run as fast as possible (smoothly interpolate from one logic state to the next). Here is a link to an algorithm: http://www.flipcode.com/cgi-bin/fcarticles.cgi?show=63823
I was thinking of setting this up in panda by using 2 Task.TaskManager, splitting the tasks (panda tasks and my tasks) between them and calling step on them separately. Here is some code:
FRAMES_PER_SECOND = 15
TICK_TIME = 1.0 / FRAMES_PER_SECOND
percentWithinTick = 0.0
time0 = globalClock.getFrameTime()
indTickTaskMgr = Task.TaskManager()
indTickTaskMgr.add(base.igLoop, "igLoop")
indTickTaskMgr.add(IndependentTickRun, "IndependentTickRun")
taskMgr = taskMgr
taskMgr.remove("igLoop")
indTickTaskMgr.add(GameTickRun, " GameTickRun")
while(True):
time1 = globalClock.getFrameTime()
while (time1 - time0) > TICK_TIME:
taskMgr.step()
time0 += TICK_TIME
percentWithinTick = min(1.0,(time1 - time0)/TICK_TIME)
indTickTaskMgr.step()
- Is using two TaskManager an OK way of doing this type of thing?
- Is this a reasonable way to smoothly interpolate from one logic state to the next (could do it myself with percentWithinTick if needed)?
This is some what similar to https://discourse.panda3d.org/viewtopic.php?t=346&highlight=orig. I add the ivalLoop to run at render fps.
indTickTaskMgr.add(base.ivalLoop, "ivalLoop")
taskMgr.remove("ivalLoop")
At the beginning of logic update (taskMgr.step). I first store the entity original position. Than run a task (e.g. Interpolate) after the collisionLoop to get the new position, than use posInterval with TICK_TIME (1.0 / FRAMES_PER_SECOND).
-
My thinking is that all the internals of panda systems (collision detection) should run the same, well the same for 15 fps. Is this corrected? Will resetPrevTransform be ok running at a different speed that render?
-
Any deterministic issues with this?
Any help or opinion on any of these would be much appreciated. By the way panda is great.
Thanks your time,
Niall
Heard a hack together example of this with interpolation:
from pandac.PandaModules import *
from direct.task import Task
from direct.actor import Actor
from direct.interval.IntervalGlobal import *
import direct.directbase.DirectStart
import sys
FRAMES_PER_SECOND = 15
TICK_TIME = 1.0 / FRAMES_PER_SECOND
class World(DirectObject):
def __init__(self):
self.smiley_posInterval = None
self.orig = None
base.disableMouse()
camera.setPosHpr(50, -150, 0, 0, 0, 0)
self.smiley = loader.loadModel("smiley")
self.smiley.reparentTo(render)
#logic update
def gameTickRun(self, task):
#stop the interval if still playing
if self.smiley_posInterval != None and self.smiley_posInterval.isPlaying():
self.smiley_posInterval.finish()
#move the entity
self.orig = self.smiley.getPos()
self.smiley.setX(self.smiley.getX() + (TICK_TIME * 10))
return Task.cont
#smoothly interpolate from one logic state to the next
def Interpolate(self, task):
newPos = self.smiley.getPos()
self.smiley.setPos(self.orig)
self.smiley_posInterval = self.smiley.posInterval(TICK_TIME, newPos, startPos = self.orig)
self.smiley_posInterval.start()
return Task.cont
#run every frame
def independentTickRun(self, task):
return Task.cont
w = World()
indTickTaskMgr = Task.TaskManager()
indTickTaskMgr.add(base.igLoop, "igLoop")
indTickTaskMgr.add(base.ivalLoop, "ivalLoop")
indTickTaskMgr.add(w.independentTickRun, "independentTickRun")
taskMgr = taskMgr
taskMgr.add(w.gameTickRun,"gameTickRun")
#setup posInterval after collisionLoop
taskMgr.add(w.Interpolate,"Interpolate", 47)
taskMgr.remove("igLoop")
#run interval system every frame
taskMgr.remove("ivalLoop")
time0 = globalClock.getFrameTime()
while(True):
time1 = globalClock.getFrameTime()
while (time1 - time0) > TICK_TIME:
taskMgr.step()
time0 += TICK_TIME
indTickTaskMgr.step()