As you probably know, updating a text node every frame is a huge performance drag. This is most annoying in counters (points, time, distance, etc.), which have to be updated quickly.
Since there are only 10 digits, it would be possible to load the geoms for each digit once, and show/hide them as necessary to avoid generating a new text node with each update. It seems like someone must done this already, but I’m not sure exactly what to search for. Does anyone have a snippet for this? If not, I’ll hack something together and post it.
How about generating all the text (or a big part of it) and putting it on a small DirectScrolledFrame that shows just one line at a time. To update the text you’d just to scroll to the line you need.
For very rapid changes like a milisecond timer for a sport/race game you could make a hoax timer. Make a animated texture with some numbers and play it really fast, the player will only see a timer no matter what it shows, it’s just too fast.
OK, here’s my solution. I create all the text nodes in advance, and show or hide them as necessary to represent a given value.
In this case, I have a node with 50 children, 5 decimal places × 10 possible values. I can increment it every frame with negligible CPU usage.
import sys
from direct.showbase.DirectObject import DirectObject
from direct.directbase import DirectStart
from direct.task import Task
from panda3d.core import *
import assets
class Counter():
def __init__(self, nodePath):
self.nodePath=nodePath.attachNewNode('counter')
self.nodePath.setScale(.1)
self.value=0 #Number stored by the counter
numPlaces=5 #Decimal places (Up to a value of 99999 in this case)
self.places=[]
#For each decimal place, add 10 text nodes, one for each digit.
for i in range(numPlaces):
digits=[]
self.places.append(digits)
for j in range(10):
node=TextNode(str(j))
node.setText(str(j))
nodePath=self.nodePath.attachNewNode(node)
nodePath.setX(-i) #Place nodes backwards, because decimal places go from right to left
digits.append(nodePath)
def setValue(self, value):
#Don't update if there's no change in value
if self.value != value:
self.value=value
#Loop through each decimal place. Find value of that place, show the node corresponding
#to it, and hide the others.
for i in range(len(self.places)):
placeValue=(value/(10**i)) % 10
digits=self.places[i]
for j in range(len(digits)):
digit = digits[j]
if j != placeValue: digit.hide()
else: digit.show()
if __name__=='__main__':
counter=Counter(aspect2d)
#Test the counter by incrementing its value every frame
def testCounter(task):
counter.setValue(counter.value+1)
return task.cont
base.taskMgr.add(testCounter, 'update value')
base.accept('escape', sys.exit)
run()