In this example, we have only 2 things to remove, but it could be 30 or 40! There’s nothing worse then writing 40 lines of code like that. But… There’s a very simple way to avoid breaking your fingers:
In the top of code, write:
from panda3d.core import NodePath
def ModelSet(name="set1"):
return NodePath(name)
So, in the middle:
#when defining main class
class ABC(ShowBase):
def __init__(self):
(...)
self.set1 = Level("set1")
self.set1.reparentTo(self.render)
(...)
#now loading the man and the dog:
self.man = loader.loadModel("models/man")
self.man.setScale(2)
self.man.setPos(0,0,0)
self.man.reparentTo([b]self.set1[/b])
self.dog = loader.loadModel("models/dog")
self.dog.setScale(.2)
self.dog.setPos(0,4,0)
self.dog.reparentTo([b]self.set1[/b])
#they're reparented to the level!
#so, to remove them:
self.set1.removeNode() #I need only 1 line to remove 2 (or 40) models at once! (PS: it might also work with actors, but I haven't tried it on yet.)
That’s all!
Good luck
EDIT:
In the code, “Level” is wrong. It would be “ModelSet”, sorry.
People are complaining that removeNode won’t free memory. New code to solve it:
def destroy(self):
for m in self.set1.getChildren():
m.destroy()
self.set1.removeNode()
The dog model and man model won’t be destroyed, they will still be in memory.
You need to do self.dog = None and self.man = None before they can be garbage collected.
It is probably a good idea to wrap these members of your level into a class, so that you can simply get rid of the entire class when you have no more need for the level, and all of its members will automatically go out of scope too.
Now the scenegraph is holding the only true reference. Removal from the scenegraph should auto-remove the dictionary entry.
my_wkd["unique_name"].removeNode()
# test
assert "unique_name" not in my_wkd
I think. I can’t test this out right now but that seems right.
You could just as easily use a conventional dictionary, group nodes together into lists, or as members of a class, etc. As long as ALL access is done the same way (ie. though the dictionary lookup), without assigning any outside references, then it’s just one extra line to remove the entry after you remove the node. You see with the above weak dictionary there is still nothing stopping you from doing…
model1 = my_wkd["unique_name"]
…at which point you’d have gone back to with the original problem. model1 is a true reference and will keep the object alive even if the dictionary entry is explicitely removed.
This concept is called “ownership semantics” and is an important part of encapsulation in object-oriented programming. It’s about defining what part of your program “owns” the object(s) in question. The owner shouldn’t let any other part of the program get it’s hands on a true reference; all outside access goes through the owner and the owner handles the final destruction. Without adhering to this principle it can become very hard to keep track of where and what all of your living references are.
Dictionary keys must be immutable. I don’t know if that’s what you’re referring to.
How would one delete this Singleton?
In the Environment class I could go and delete all attributes by hand. Problem is that there are a lot of attributes going around as you said bundeling them in a class seems like the right idea.
That makes no difference. Setting an instance to None is the cleanest way to reduce the reference count of a class instance and all its members. Clearing the class’ dictionary explicitly won’t make a difference at all.
There is no added benefit to using “del”, it just makes it more confusing. (because “del” sounds like you’re deleting the instance, whereas in reality you’re just reducing its reference count).