Hello im having some problems creating a somewhat simple fps counter that would change colors when its running on x amount of frames (144 <= green, 60 <= yellow, 30<= red) and it should print it to the OnscreenText. my code:
import direct.directbase.DirectStart
import time
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
class FPScounter(DirectObject):
def __init__(self,):
print("Fps Counter starting....")
base.setBackgroundColor(1, 1, 1)
#while True:
self.fpscounter1 = OnscreenText(text=" framerate: "+ str(fps) + " fps", pos=(-0.81, 0.90), scale=0.07, fg = (63,191,63))
# setFont = (fpscounter1, "AlbertusMediumRegular.ttf")
self.fps = 1.0 / (time.time() - start_time)
font = "AlbertusMediumRegular.ttf"
#print("FPS: ", 1.0 / (time.time() - start_time))
start_time = time.time() # start time of the loop
fpscounter = FPScounter()
run()
Also this is my first time posting here so any help to actually make this work would be great!
Well, one way to do this might be to start a task that will run every frame (see the manual here), and in that task use the âglobal clockâ (see the manual here) to get the frame-rate.
(The latter manual page doesnât show the method used to get the frame-rate, but it does link to the API page, which does show that method, I believe.)
Thanks for that, im really noob here so i tried that and
import direct.directbase.DirectStart
import time
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
class FPScounter(DirectObject):
def __init__(self,):
print("Fps Counter starting....")
base.setBackgroundColor(1, 1, 1)
#while True:
# setFont = (fpscounter1, "AlbertusMediumRegular.ttf")
font = "AlbertusMediumRegular.ttf"
#self.fps = 1.0 / (time.time() - start_time)
def fpscounterTask(fps):
frameTime = globalClock.getFrameTime()
return fps.cont
print('fpscounterTask is Done')
return fps.done
self.fpscounter1 = OnscreenText(text=" framerate: " + str(FrameTime) + " fps", pos=(-0.81, 0.90), scale=0.07,fg=(63, 191, 63))
def exampleTask(task):
if task.time < 2.0:
return task.cont
print('Done')
return task.done
#print("FPS: ", 1.0 / (time.time() - start_time))
start_time = time.time() # start time of the loop
fpscounter = FPScounter()
run()
i tried the example code aswell and it would not print to consoleâŚ
Looking at your code, you donât seem to be adding the task to the task-manager. (On the manual page for âtasksâ that I linked to above, check the section on the âtask managerâ for more information.)
so like
taskMgr.add(fpscounterTask, 'fps')
i put that above the fpscounterTask function and i get error: NameError: name âfpscounterTaskâ is not defined
The âfpscounterTaskâ method is defined in your âFPScounterâ class. Thus, it doesnât stand alone, but would be related to an âFPScounterâ object. In this case, that would presumably be the one that youâre working in, and thus you would likely reference it via the âselfâ parameter.
That is, you would reference it not as âfpscounterTaskâ, but as âself.fpscounterTaskâ.
By the way, I have a âbeginnerâs tutorialâ that takes one through the basics of using Panda3D, all the way through to building a distributable version. If youâre interested in trying it, you should find it here:
okay i will look at that, though can you just quickly tell me what i need to change here to actually run this?
import direct.directbase.DirectStart
import time
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
class FPScounter(DirectObject):
def __init__(self,):
print("Fps Counter starting....")
base.setBackgroundColor(1, 1, 1)
#while True:
taskMgr.add(self.fpscounterTask, 'fps')
self.fpscounter1 = OnscreenText(text=" framerate: " + str(self.FrameTime) + " fps", pos=(-0.81, 0.90), scale=0.07,fg=(63, 191, 63))
# setFont = (fpscounter1, "AlbertusMediumRegular.ttf")
font = "AlbertusMediumRegular.ttf"
#self.fps = 1.0 / (time.time() - start_time)
def fpscounterTask(fps,self):
frameTime = globalClock.getFrameTime()
return fps.cont
print('fpscounterTask is Done')
return fps.done
def exampleTask(task):
if task.time < 2.0:
return task.cont
print('Done')
return task.done
#print("FPS: ", 1.0 / (time.time() - start_time))
start_time = time.time() # start time of the loop
fpscounter = FPScounter()
run()
A few issues that I see:
- In your â__init__â method, youâre passing âself.FrameTimeâ to your OnscreenText objectâbut you donât have a âFrameTimeâ variable in your âFPScounterâ class.
- If you just want the program to run, and return to making it do what you want, you can just remove this part from the string that youâre building there.
- In the same place, youâre specifying a foreground colour (the âfgâ keyword-parameter) with only three values (presumably red, green, and blue). However, it should have four values (red, green, blue, and alpha).
- By the way, I think that those colours should be in the range 0 to 1, not 0 to 255.
- When you define your âfpscounterTaskâ method, youâre specifying the âfpsâ parameter first, which means that it contains the reference to the âFPScounterâ object. (Which would usually be in the âselfâ parameter.) Youâre then trying to return âfps.contâ, and the âFPScounterâ class doesnât contain a âcontâ variable.
- Instead, I think that the second parameter in your method (which youâre currently calling âselfâ) will contain the âtaskâ object, which has the âcontâ-value that youâre trying to return.
Fix all of that, and it seems to run! 
Well it was suppose to get the Frametime from the fpscounterTask function and then print it to the self.fpscounter1 onscreentext object but i have no idea how i would get it from the fpscounterTask functionâŚ
Perhaps it might be better to start your OnscreenText object with some stand-in text, and then set its text appropriately in the task.
However, you might be able to get some data from the task-object thatâs returned by âtaskMgr.addâ, if you want the OnscreenText to start off with something relevant.
Okay so now i checked the Onscreentext_function
and i noticed the setFg() function that i could use to change the color of the onscreentext object, but when i tried to run the code like this:
import direct.directbase.DirectStart
import time
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
red = (1,0.0,1)
yellow = (1,0.9,0,1)
green = (0,0.9,0,1)
class FPScounter(DirectObject):
def __init__(self,):
print("Fps Counter starting....")
base.setBackgroundColor(1, 1, 1)
self.fpsTextobject = OnscreenText(text=" framerate: " + " fps", pos=(-0.81, 0.90), scale=0.07,bg = (0.3,0.3,0.4,1))
#self.updateCounter = taskMgr.add(self.fpscounterTask, 'fps')
self.fpsTextobject1 = setFg(green)
# setFont = (fpscounter1, "AlbertusMediumRegular.ttf")
#font = "AlbertusMediumRegular.ttf"
#self.fps = 1.0 / (time.time() - start_time)
# def fpscounterTask(self):
#self.frameTime = globalClock.getFrameTime()
# print('fpscounterTask is Done')
# return fps.done
#print("FPS: ", 1.0 / (time.time() - start_time))
start_time = time.time() # start time of the loop
fpscounter = FPScounter()
run()
it just says NameError: name âsetFgâ is not defined and i f i try add
self.setFg(green)
instead i just get AttributeError: âFPScounterâ object has no attribute âsetFgâ and yes the onscreentext has been imported to the py file.
When you call just âsetFGâ alone, youâre not specifying an object or class that it should called from; youâre treating it as though it were a function defined outside of any class. When you call âself.setFGâ, youâre treating it as though it were a method of your FPScounter classâor more specifically, of the instance of that class that youâre constructing at that point (since this happens in an â__init__â method).
Do I gather correctly that youâre not terribly familiar with object-oriented programming? If I am correct, then I recommend that you look up some tutorials for object-oriented programming in Python, as you may otherwise keep stumbling over such issues.
Yeah im not too familiar with python but im more familiar with C# and im trying to get used to the python.
though is it possible to create the code with c++ and then convert that code to python and then get it to run with the panda3D? not too sure if panda3D has any tools to convert one language to another?
I donât think that there are such conversion tools. However! They may not be called for: if youâre familiar with object-oriented programming in C++, and have a C++ compiler available, you can just develop in C++. You donât have to use Python, I believe.
import direct.directbase.DirectStart
import time
from direct.gui.OnscreenText import OnscreenText
from direct.showbase.DirectObject import DirectObject
from direct.task import Task
red = (1,0,0,1)
yellow = (1,0.9,0,1)
green = (0,0.9,0,1)
class FPScounter(DirectObject):
def __init__(self,):
self.frameTime = 0
print("Fps Counter starting....")
base.setBackgroundColor(1, 1, 1)
self.fpsTextobject = OnscreenText(text=" framerate: " + str(round(self.frameTime))+ " fps", pos=(0.80, 0.90), scale=0.07,bg = (0.3,0.3,0.4,1)) # placeholder
taskMgr.add(self.fpscounterTask, 'fps1')
self.fpsTextobject.setFg(green)
self.maxfps = 144
def fpscounterTask(self,task):
self.frameTime = globalClock.getAverageFrameRate()
#self.frameTime = 30
color = green
if self.frameTime <= 144:
color = green
if self.frameTime <= 60:
color = yellow
if self.frameTime <= 30:
color = red
self.fpsTextobject.destroy()
self.fpsTextobject = OnscreenText(text=" framerate: " + str(round(self.frameTime)) + " fps", pos=(1.03, 0.90),scale=0.07, bg=(0.3, 0.3, 0.4, 1), fg=(color))
#self.fpsTextobject.setFg(color)
return task.cont
fpscounter = FPScounter()
run()
solved the issue. Thanks for the help. also how do i set text alignment?
1 Like
Congratulations on getting it working! And Iâm glad if Iâve been of service. 
As to text-alignment, see the manual here for that information!