Mysteriously defined symbols, e.g. "render"

Going through the Panda3D Minecraft tutorial, I find that there are a number of symbols in the code that VS code can’t trace. Its linter reports them as undefined. And yet they work. Among them:

render
loader
camera
taskMgr
globalClock

There are no

from [anything] import *

statements in the code. What part of Python don’t I understand, that allows these symbols to be defined without having been explicitly imported? And where are they actually defined? Here are the actual imports:

from math import pi, sin, cos
from direct.showbase.ShowBase import ShowBase
from panda3d.core import loadPrcFile
from panda3d.core import DirectionalLight, AmbientLight
from panda3d.core import TransparencyAttrib
from panda3d.core import WindowProperties
from panda3d.core import CollisionTraverser, CollisionNode, CollisionBox, CollisionRay, CollisionHandlerQueue

from direct.gui.OnscreenImage import OnscreenImage

I believe that they’re defined in ShowBase.

(You should find them if you search the code of ShowBase.py, which should be available at this link.)

It should perhaps be noted that they are, I believe, somewhat deprecated these days–although I’ll admit that my own code uses them.

Two further questions:

  1. How did those symbols get into my namespace without an “import *” ?
  2. What do you recommend I use instead?

I think you have already been answered, this happens when creating an instance of ShowBase. At the same time, the symbols are added as built-in objects.

You can just ignore it, it won’t affect your code.

1 Like

Essentially the same things, but not as globals.

So, let’s say that you have a class named “MyGame” that inherits from ShowBase:

Within that class, you could access these objects as “self.<object-name>”–e.g. “self.render”.

Outside of the class, you could make sure that you have access to the instance of your “MyGame” class, and then access the objects from that.

(There are a few ways of giving yourself access to your ShowBase-derived class-instance, such as passing it in as a parameter (and perhaps storing it in a variable), or–my usual choice these days–creating a “common” file that stores a reference to it, and which is then imported by those scripts that want it.)

To illustrate with code:
“common.py”:

myGame = None

The “main game script”:

# ... Normal importations here ...

# Import the common-file
import common

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

        common.myGame = self

    def someMethod(self):
        # What we're doing here is arbitrary; the important
        # thing is how we're accessing "render"
        self.render.setColorScale(0, 1, 0, 1)

Some other script-file:

import common

# Somewhere in the code...
    common.myGame.render.setColorScale(0, 1, 0, 1)

(Note that the above is untested, and just a sketch. Hopefully, however, it serves to indicate what I’m describing.)

You can initiate ShowBase in a different way, and use full object references inside the class.

from direct.showbase.ShowBase import ShowBase

class MyApp():
    def __init__(self):
        self.base = ShowBase()

        self.base.render
        self.base.loader
        self.base.camera
        self.base.taskMgr
        self.base.clock

     

app = MyApp()
app.base.run()
1 Like

Thanks. I had no idea one could add to the “built-in” set! That’s weird, but good to know.

1 Like