Framerate problem

Hi guys

I’m working on a game where my character collects items. I want that every time it collects an item, the item will be gone and a new item will be created somewhere else in the world. My item has a collision sphere for collision. The thing is, when I begin collecting item after item, my framerate is starting to go down from 60 FPS to below 30 and sometimes below 20. It might have something to do with the class destructor, as I use removeNode() for the model, sphere, and particle effect. However, when I use detachNode() the same happens.

Any idea what’s causing it and how to fix it? Thanks in advance!

Are you sure they are getting removed? Place a print statement at the point where you remove it and see if it gets printed.

Yes, they are. I placed a print statement and it’s printed, plus everything disappears like it should. It’s working fine other than the fact that after a few items the framrate takes a serious hit.

Note that everytime an item is collected, it is deleted and a new instance of the class is created. Maybe that’s the problem?

As long as the old one gets removed.

Are you sure you didn’t create a circular dependency, using setPythonTag?

Well, I don’t even know what that is (I’m still new to both Panda and Python, thus I’m programming very carefully), so no, I have never used setPythonTag.

This is the Code for my class

class Choco(Food):
	def __init__(self, Coordinates):
		
		#This indicates how much health does this kind of food restores.
		self.healthPoints = 10
		
		Food.__init__(self)
		self.x = Coordinates[0];
		self.y = Coordinates[1];
		self.z = Coordinates[2];
		
		self.model = loader.loadModel("food_models/choco")
		self.model.reparentTo(render)
		self.model.setPos(self.x, self.y, self.z)
		self.model.setScale(0.23,0.23,0.23)
		self.model.setH(180)
		self.model.setTwoSided(True) #This prevents some textures from becoming invisible from one side.
		
		self.model.setColorScale(1,1,1,1)
		self.model.setP(50)
		self.model.setR(50)
		
		cs = CollisionSphere(0, 0, 0, 4)
		self.cnodePath = self.model.attachNewNode(CollisionNode('choco'))
		self.cnodePath.node().addSolid(cs)
		self.cnodePath.show()
		
		#A floater for the particle effect
		self.ParticleFloater = NodePath(PandaNode("Particle Floater"))
		self.ParticleFloater.setScale(0.03,0.03,0.03)
		self.ParticleFloater.reparentTo(render)
		self.ParticleFloater.setPos(self.x, self.y, self.z - 0.5)
		
		base.enableParticles()
		self.glower = ParticleEffect()
		self.loadConfig('Particles/glow.ptf')
		
   def __del__(self):
		self.model.removeNode()
		self.ParticleFloater.removeNode()
		self.cnodePath.removeNode()

possibly you don’t delete the collision sphere and if you stay with your actor on the place where the item was, it automatically computes new postion for the actor, but he always goes back so it makes a never-ending command flow for your CPU?

This is what happens:

1.)You move with your actor to the place where the item is.
2.)The collision node tells that your character touched the item to the main node.
3.)The item’s model is being deleted from the render node. but the collision sphere is not parented to it so it does not delete.
4.)The collision node tells the actor to move because it touched the collision sphere.
5.)But the actor stays on his place because it’s not having anything about collision.
6.)Points 4 and 5 are reapeated all the time so the CPU gets over-command-flown. The fps drops down.
7.)the character goes out of the collision sphere and the flow stops.

To fix that:

Don’t forget to reparent the col. sphere to the model so it gets removed and created WITH the model. This is ideal solution, belive me.

–Finger me if I am wrong.

—Your Mešča

^^ If you’re talking about the collision node, I am deleting it (look at my destructor code above). If that’s not what you mean, then I’m not sure I understand - how do you parent a collision solid to a model?

Don’t call base.enableParticles more than once.
Take it out from your Choco constructor.

Also, cleanup your particles, by
self.glower.cleanup()

Thanks, but even after doing those the problem remains. However, you are right that it’s a particle effect problem. I removed the particle effect and the framrate goes back to a steady 60, no matter how many items I collect.

If the problem remains, it is better to post the whole program for further investigation.

OK, here is the improved class. The problem is 100% in the particle effect, because as soon as I remove the code for it, the framerate is fine again.

class Choco(Food):
	def __init__(self, Coordinates):
		
		#This indicates how much health does this kind of food restores.
		self.healthPoints = 10
		
		Food.__init__(self)
		self.x = Coordinates[0];
		self.y = Coordinates[1];
		self.z = Coordinates[2];
		
		self.model = loader.loadModel("food_models/choco")
		self.model.reparentTo(render)
		self.model.setPos(self.x, self.y, self.z)
		self.model.setScale(0.23,0.23,0.23)
		self.model.setH(180)
		self.model.setTwoSided(True) #This prevents some textures from becoming invisible from one side.
		
		self.model.setColorScale(1,1,1,1)
		self.model.setP(50)
		self.model.setR(50)
		
		cs = CollisionSphere(0, 0, 0, 4)
		#cs.reparentTo(self.model)
		self.cnodePath = self.model.attachNewNode(CollisionNode('choco'))
		self.cnodePath.node().addSolid(cs)
		self.cnodePath.show()
		
		#A floater for the particle effect
		self.ParticleFloater = NodePath(PandaNode("Particle Floater"))
		self.ParticleFloater.setScale(0.03,0.03,0.03)
		self.ParticleFloater.reparentTo(render)
		self.ParticleFloater.setPos(self.x, self.y, self.z - 0.5)
		
	
		self.glower = ParticleEffect()
		self.loadConfig('Particles/glow.ptf')
		
	def __del__(self):
		self.model.removeNode()
		self.glower.removeNode()
		self.ParticleFloater.removeNode()
		self.cnodePath.removeNode()

	def loadConfig(self, file):
		self.glower.cleanup()
		self.glower = ParticleEffect()
		self.glower.loadConfig(Filename(file))        
        
		self.glower.start(self.ParticleFloater)
		self.glower.setPos(0.000, 0.000, 24.250)

I’ve started writing that before you posted it :wink:

Why you call self.glower.cleanup in loadConfig ? It shall be called in the destructor.
I believe you may have other bugs also in your main code. Make sure you have really destroy the object in your main code.

hmm…put a rander.analyze() before and after your call to delete each item, then go pickup a few items to see if there are any leaked nodes we should be looking for. Also, though I doubt this is a problem, but try a manual deconstructor like item.destroy()…it may be a case where the auto deconstructor isn’t doing it right (just a thought).

Another thing to look for are leaked “tasks”. Though you aren’t creating any yourself, and the cleanup code your using should do it, the performance symptoms sound alot like cpu overload not related to excess nodes. Run pstats to see where all your cpu time is being spent (or do a print on the taskMgr, base.cTrav (assuming you’re using it), and … the part of base that handles particles?syntax?).

Let us know what you get,
~Silver~

First of all, I’d like to thank all of you guys for taking the time and trying to help me. I really appreciate it.

I was not able to solve the problem. I’ve tried using the render.analyze() function but there was nothing wrong there in terms of numbers. I also made sure my destructor cleans everything up, but it still didn’t help. So instead of solving the problem, I went around it. I removed all the particle effects code from the items classes, and instead created a new class for the particle effect. I only create one instance of this class (sort of like a singleton) and I just update it’s coordinates according to the relevant item. So far this “solution” works fine, with 60 FPS a lock.

Thank you guys again!

Dont forget Panda has a monitor system where you can see what thing is causing fps downward.

This is the one of the big things of panda :smiley: