Using loadModel from external files

I am making a game in which I generate some models and add it to the scene. The problem is that I made a class for making the world. In this, I have a list of all items for the render, but I can’t load these models as loadModel only belongs to ShowBase. If I create an instance of ShowBase in my world class file, it raises an error about multiple spawn instances. So how can I load a model from another file when I have made a ShowBase instance in another file?

I believe that the current recommended solution is to establish a “common” script that holds references to anything that you want to be globally available–like your ShowBase instance. This can then be imported into whatever script you want to have use such references, thus providing access to them.

One way of doing this might be something like as follows:

The “common” script:

class Common:
    showBaseInstance = None
    # And any other such variables

In the file that defines your ShowBase instance:

# All the usual importations here

from Common import Common

class MyGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        Common.showBaseInstance = self

In some other script that you want to have access the ShowBase instance:

from Common import Common

newModel = Common.showBaseInstance.loadModel("someModelFile")

Aside from this, there is also an older, now-deprecated approach. As things stand, ShowBase establishes a variety of globally-available variables, including one that holds a reference to the current ShowBase object. This variable is called “base”, and being global, should be available from pretty much anywhere. Thus you can do something like this:

In your file that defines your ShowBase instance:

class MyGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

In some other script that you want to have access the ShowBase instance:


newModel = base.loader.loadModel("someModelFile")

(And you should also find that “loader” itself is one of those globally-available variables, meaning that you should be able to leave off the use of “base” above, if I recall correctly.)

But again, this approach is now deprecated, and the first approach given above is the recommended one.

1 Like

I was experimenting with this and I tried this: instead of a class with a variable, I just made a variable in the globals.py file. Then in the main file I assigned this variable to the ShowBase class. I then accessed this variable from another file but it gave an error. Why do you have to put the ShowBase variable is a class? Why doesn’t it work with only variable?

1 Like

It’s hard to answer that without seeing your implementation. In and of itself, it should work, I believe.

Something like this:

In the “CommonVars” file:

myShowBase = None

In the “main” file:

# Note that here I'm just importing the entire module.
# Previously I imported the class, but we have no class to import.
import CommonVars

class MyGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        # In this case, "CommonVars" is a module
        CommonVars.myShowBase = self

Alternatively:
(With the same “CommonVars” file.)

In the “main” file:

# Note that here I'm specifically importing "myShowBase" from the module
from CommonVars import myShowBase

class MyGame(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        # In this case, "CommonVars" is a module
        myShowBase = self

This should work, but might be less “clean”, as it leaves the ownership of “myShowBase” unclear to a reader of the code. Further, while “myShowBase” might be a safe variable to do this with, if you were to have some such variable that shares a name with another then the two might conflict–if not disambiguated by specification of their module or class.

The main thing, I suspect, is that one way or another you have to tell Python where to look for the variable.

Unfortunately, it doesn’t seem to work for me.
When I call it from another file I get:

    self.worldNP.reparentTo(showBase.render)
AttributeError: 'NoneType' object has no attribute 'render'

EDIT:
One thing I did is from global.py import showbase
When I changed it to import global.py it worked.

Hmm… If not for that edit, I would suspect that you hadn’t assigned the “showBase” variable–or perhaps have mistakenly assigned it to a local variable of the same name.

This is the sort of thing that prepending the module- or class- name can perhaps help with. It clarifies that you mean to work with that specific variable, and not a local variable, or a variable of the same name provided by some other module.