Weird Error

So I have just returned to coding with a smaller project to gain experience with panda3d. I dropped my last project :frowning: it was too hard…

from direct.task import Task
import math
from direct.showbase.ShowBase import ShowBase
from panda3d.core import *
from direct.actor.Actor import Actor
from direct.interval.IntervalGlobal import *

from direct.gui.OnscreenText import OnscreenText
from pandac.PandaModules import loadPrcFileData
from panda3d.core import Vec3
from direct.gui.OnscreenImage import OnscreenImage

class Application(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        self.cam.setPos(0,  -30,  25)
        self.dude = mainDude()
        self.cam.setP(-25)
        self.initialGround = self.loader.loadModel("block")
        self.initialGround.setSy(5)
        self.initialGround.reparentTo(render)
        self.initialGround.setZ(-15)
        
        
        self.taskMgr.add(self.moveDude,  "move dude", extraArgs = [self.dude],  appendTask = True)
        
        self.block = None
        
    def isWhole(self,  x):
        if(x%1 == 0):
            return True
        else:
            return False
        
    def addGround(self,  task):
        self.frame = task.frame
        if self.isWhole(self.frames/4) and (self.frames/4) != 0:
            self.block.removeNode()
            self.block = loader.loadModel("block")
            self.block.reparentTo(render)
        return task.cont
        
    def moveDude(self,  dude,  task):                          
        dude.setY(dude.getY()+3)                <----- ERROR IS HERE
          
class mainDude(object):
        def __init__(self):
            self.load()
            
        def load(self):
            self.dude = Actor("char")
            self.dude.reparentTo(render)
            self.dude.loop("Run")
            self.dude.setPos(Vec3(0,  5,  0))
            self.dude.setH(180)

But this gives me attribute Error mainDude has no attribute setY. I know I need to return self.dude back to the thing that initiates the mainDude class, but I don’t know how!

Thanks.

You’re confusing which class is the pandanode and which class is your wrapper class around it. You can only call setY on pandanodes.

The easiest way to solve this is to add self.setY = self.dude.setY at the end of your mainDude.load(). That way when you call setY on maindude, it will automatically call the setY on your model.

To prevent this (and other naming shenannigans) in the future, you should avoid giving something in a class the same name as that class. The error would be plainly obvious if you renamed mainDude.dude to mainDude.actor instead.

Tober is essentially correct, but your confusion seems to be about handling classes and instances of those classes. In order for your current setup to work you would have rewrite the offending line to:

dude.dude.setY(dude.dude.getY()+3)

When you are writing code inside the class definition it’s “self.dude”, but any time you are passing around an instance of that class it has to be <name_of_instance>.dude, in your case “dude.dude”. A better solution would be to change:

self.dude = Actor("char")

# to:
self.actor = Actor("char")

# then the line would be much clearer:
dude.actor.setY(dude.actor.getY()+3)

For myself I name panda objects like nodes and nodepaths explicitly (with caps usually) so that it’s clear when I’m dealing with my own logic or a panda object:

class MainDude(object):

    def __init__(self):
        self.name = "myName"
        self.NODE = PandaNode("node")
        self.NP = NodePath(self.NODE)
        # or
        self.ACTOR_NP = Actor("char")

dude = MainDude()
dude.NP.reparentTo(render)
print(dude.NP.getPos())
>>>(0, 0, 0)
print(dude.name)
>>>myName