Get model of children

Is there a way to get the model of a child? I’m trying to save child data to a list when they’re despawned, then use the list to respawn them later like this:

            for child in self.E9U.getChildren():
                self.items.append(child.getPos())
                self.items.append(child.getHpr())
                child.removeNode()

so that later I can respawn them like this:

            while self.items:
                self.spawner.setPos(self.items.pop(0))
                self.spawner.setHpr(self.items.pop(0))
                self.spawner.reparentTo(self.E9U)

but the issue is, I don’t know a way to tell it which models to respawn. Any advice would be greatly appreciated.

Well, a child is just a NodePath, like any other–anything that you can do with a parent NodePath you should be able to do with a child.

Now, I don’t know whether there’s any way to retrieve the file-name of a loaded model from the node that holds it. (If I’m understanding correctly what you’re trying to do.)

What I suggest instead is that you either create a class to encapsulate this information–holding the entity’s model-NodePath, a reference to its model file-name, and so on–or, if your entities are very simple, just store the filename in a Python-tag in the NodePath.

The former approach is likely to be more useful should your entities be (or become) somewhat complex–for one thing, it allows you to create custom methods to handle their behaviours.

The latter approach is simpler, but can I think become unwieldy if applied to a great many pieces of data, or to relatively-complex data.

Either way, that should allow you to store the relevant information somewhere accessible.

If that is indeed the issue, then the path to the file from which the model of a child was loaded (assuming all child models were loaded separately instead of from the same model file) can be retrieved from the ModelRoot node:

child1_model = base.loader.load_model("child1.egg")
path_to_child1_model = child1_model.node().fullpath
print("path_to_child1_model:", path_to_child1_model)

Assuming that you run the code above from the C/my_project/ directory, the path_to_child1_model should be "/c/my_project/child1.egg".
But I wonder how the child models are loaded without already knowing their model paths in the first place?

1 Like

I would guess that it’s a matter of having loaded in various models, put them in a list, and then later wanting to save them. The file-names were known at initial load-time, but not kept thereafter.

Thanks for the responses! I’ll try them out when I get back from work, but if it helps, items are parented to self.E9U sporratically based on gameplay, then also saved to various different lists based on gameplay, and reloaded when each different list becomes relevant (lists are saved to a numpy matrix).
The map loads sort of like minecraft chunks, so this function is used to spawn things in and put of the world when you move towards or away from them

1 Like

Alright, so I’m kind of new to classes, but I wrote this above the showbase class:

class Item:
    def __init__(self, name, model):
        self.name = name
        self.model = model

then, when I created objects I did it like this:

self.spawner = loader.loadModel("models/jack")
self.spawner.setPos(0, 0, 1)
self.spawner.reparentTo(self.E12U)
self.spawner = Item("ball", "models/jack")

then I tested it by printing self.spawner.model, and got “models/jack”. great :smiley: So then I tried this:

for child in self.E9U.getChildren():
        self.items.append(child.getPos())
        self.items.append(child.getHpr())
        print(child.model)
        child.removeNode()

and I got back this guy when the code ran:

'panda3d.core.NodePath' object has no attribute 'model'

Am I going about this right?

Not quite, I’m afraid. ^^;

You see, the “model” variable belongs to your your “Item” class. However, when you access the child of a node, you get a node–not an “Item”. And nodes indeed don’t have a variable named “model”.

Furthermore, in these two lines:

The effect of this is that you initially store a model in the variable “self.spawner”, and then shortly afterwards instead store an object of class “Item” in “self.spawner”–replacing the model. The model still exists in the Panda scene-graph, of course–but it’s not longer held in the “self.spawner” variable.

Note that if you were to leave out the lines that load the model, set its position, and reparent it to “self.E12U”, printing “self.spawner.model” would still output “models/jack”. The two things are separate, as currently implemented.

What I’d suggest is that, instead of iterating over the child-nodes of your level-node, you instead iterate over a list of “Item”-objects. That way you can access the data stored in those “Item”-objects.

Furthermore, so that you can work with the relevant model-nodes in the same way, I’d suggest storing your loaded models in the “Item” class, too: that way you can just iterate over your “Item”-objects and, for example, remove their nodes.

hey, I really appreciate the feedback, but I’m still having a hard time understanding. Could you give me an example of what that looks like?

1 Like

In short, something like this:

class Item():
    def __init__(self, modelFileName):
        # Load the model, and store it in our "Item"
        self.model = loader.loadModel(modelFileName)
        self.model.reparentTo(render)

        # Store the file-name for later use
        self.modelFileName = modelFileName

Elsewhere, in the class that manages your objects:

    # A list in which to keep our objects. This gives us
    # convenient access to them.
    self.objectList = []

    # For the sake of the example, we'll just fill the list
    # arbitrarily.
    for i in range(numberOfItems):
        itemObj = Item("models/jack")
        self.objectList.append(itemObj)

Now, when you want to get the model-files for your objects, you can do this:

# Iterate over the list of objects, and for each one
# access its file-name and remove it.
for itemObj in self.objectList:
    modelFile = itemObj.modelFileName
    itemObj.model.removeNode()

All that said, the above is a very bare-bones example. I have a “Beginner’s Tutorial” that goes through the process of making a game with Panda3D, starting with some of the fundamentals of using the engine, through implementation, and all the way to building a distributable version. While I don’t recall whether it covers in great detail the logic behind working as described above, the tutorial does show a fuller example of the approach at the least, and goes into detail on other topics.

If you’re interested, you should find the tutorial here:

1 Like

Thank you so much!! :smiley: It’s funny, I found your blog awhile ago and have it bookmarked. I’m definitely planning on using it down the road

1 Like

It’s my pleasure! :slight_smile:

Honestly, I’d suggest taking on the tutorial sooner rather than later: it may help with some of the foundational elements of making a game with Panda3D, and thus provide you with a solid base of knowledge from which to start working towards your own designs.