Is there another way to access "render" attribute in sub object?

Now, when I need to access render or render2d,
I did it by passing self of main object into sub-object argument
and I think it’s quite complicated and hard to manipulate it.

Could I ask that there are other ways to directly access render attribute (like main object does) in sub-object ?

Thank you.

Well, noting first that “render” is defined in “ShowBase”, there are two ways, that I see:

One approach (that I’ve been somewhat moving towards using myself) is to have a “common” Python-file that holds references to various things that are, well, commonly wanted. This would then include your “ShowBase” object, and from that, “render”.

Something like this, perhaps:

The “common” file–let’s call it “Common.py”:

# I like to make this a class that contains class-variables,
# and static methods, but other designs may be implemented, I daresay.
class Common():
    # A reference to our "game" class (which will
    # inherit from "ShowBase")
    #
    # Initially this holds nothing
    myGame = None
    # However, see the next section...

The file that implements your “ShowBase” object

from direct.showbase.ShowBase import ShowBase

# Here we import the "Common" file in order to gain access to the things that it stores
from Common import Common

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

        # Now, store this (ShowBase-derived) object in "Common"
        Common.myGame = self

        # Other initialisation here, as normal...

And finally, in some other file, elsewhere…

# Again, we import "Common" in order to access its contents
from Common import Common

# Somewhere in the code, make use of "render"...
someNodePath.reparentTo(Common.myGame.render)

~

Another way is to simply rely on the fact that ShowBase makes certain variables–including “render”–globally available. Thus you should be able to just access “render” anywhere once ShowBase has been initialised.

However, this is not advised: I seem to recall that there are plans to deprecate this practice of making globals, meaning that code that relies upon it may break with some future update.

2 Likes

Thank you, It works as I expect.
Does it means I can access anything of ShowBase from everywhere ?

1 Like

Hmm… I’m not sure offhand about anything. I know that it makes a number of things globally available, but I wouldn’t like to swear to whether it does so with all.

Still, as I said, that approach is not recommended.

1 Like

You can just opt out of inheriting from the ShowBase class. This will be the same thing that the @Thaumaturge offers. I’m not sure about the import approach, so a new scope is currently being created.

from direct.showbase.ShowBase import ShowBase

base = ShowBase()

# Your code.

base.run()

Now you can pass a reference to a ShowBase instance to any class. Where necessary. However, some objects will still be added built-in global variables.

https://docs.panda3d.org/1.10/python/reference/direct.showbase.ShowBase#direct-showbase-showbase
https://docs.panda3d.org/1.10/python/reference/builtins#module-builtins

2 Likes

When a ShowBase object is instantiated, it puts a reference to itself in the builtins called base. Since it’s setup as a builtin you can access it from anywhere. This is a better than accessing the other automatic builtins since you only have to register one extra builtin with linters/IDEs.

2 Likes

Look into the programming pattern called a ‘service locator’

I think Thaumaturge hinted at this idea…

2 Likes

https://gameprogrammingpatterns.com/service-locator.html

Probably a better explanation. I have the book Game Programming Patterns by Robert Nystrom. Very helpful

1 Like