Error in program

Hi! I have yet another error in Castle Adventure 3D
Run the program, see the error, and tell me how to fix it.

Code (Spoiler)

Castle Adventure 3D.zip (2.0 MB)

Why not just paste the error-text here, along with a relevant excerpt from your code?

That’s rather more convenient for potential responders than downloading a zip file, unpacking it, running unknown code, and then trying to debug it.

main.py:

from direct.showbase.ShowBase import ShowBase
from direct.actor.Actor import Actor
from direct.task import Task
from panda3d.core import *
from classes import *
loadPrcFile("config/config.prc")

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.disableMouse()
        
        self.cTrav = CollisionTraverser()
        self.pusher = CollisionHandlerPusher()
        self.pusher.setHorizontal(True)
        
        self.room = self.loader.loadModel("models/room.egg")
        self.room.setH(270)
        self.room.reparentTo(self.render)
        
        self.player = Player(Point3(0, -20, 2))
        
        self.keyMap = {"w" : False, "a" : False, "s" : False, "d" : False, "arrow_left" : False, "arrow_right" : False}
        
        for key in self.keyMap:
            self.accept(key, self.updateKeyMap, [key, True])
            self.accept(key + "-up", self.updateKeyMap, [key, False])
        
        self.taskMgr.add(self.update, "update")
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionCapsule(-4, -6, 1, -1, -6, 1, 0.5)
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(1, 0, 0), Point3(-5, 0, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(0, 1, 0), Point3(6, -15, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(-1, 0, 0), Point3(5, -5, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(0, -1, 0), Point3(-3, 5, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        self.monster = Actor("models/monster1.egg", {"attack" : "models/monster1-pincer-attack-both.egg", "explode" : "models/monster1-explode.egg"})
        self.monster.setScale(0.25, 0.25, 0.25)
        self.monster.reparentTo(self.render)
        
        monsterCenter = self.monster.getBounds().getCenter()
        monsterRad = 2
        monsterNode = CollisionNode("monster")
        monsterNode.addSolid(CollisionSphere(monsterCenter, monsterRad))
        monsterC = self.monster.attachNewNode(monsterNode)
           
        self.cTrav.addCollider(monsterC, self.pusher)
        self.pusher.addCollider(monsterC, self.monster)
        
        #self.accept("p", self.printPos)
        
    """def printPos(self):
        print(self.camera.getPos())"""
            
    def updateKeyMap(self, key, value):
        self.keyMap[key] = value
        
    def update(self, task):
        dt = globalClock.getDt()
        
        self.player.update(self.keyMap, dt)
            
        self.monster.lookAt(NodePath(self.player))
        self.monster.setY(self.monster, dt * 10)
        
        return Task.cont
        
game = Game()
game.run()

classes.py

from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import Actor
from panda3d.core import *

class Player(DirectObject):
    def __init__(self, pos):
        self.player = base.camera
        self.player.setPos(pos)
        
        self.health = 10
            
        playerCenter = self.player.getBounds().getCenter()
        playerRad = 2
        cNode = CollisionNode("player")
        cNode.addSolid(CollisionSphere(playerCenter, playerRad))
        playerC = self.player.attachNewNode(cNode)
        
        base.cTrav.addCollider(playerC, base.pusher)
        base.pusher.addCollider(playerC, self.player)
        
    def __NodePath__(self):
        return self,player
        
    def update(self, keys, dt):
        if keys.get("w"):
            self.player.setY(self.player, dt * 10)
        elif keys.get("a"):
            self.player.setX(self.player, dt * -5)
        elif keys.get("s"):
            self.player.setY(self.player, dt * -10)
        elif keys.get("d"):
            self.player.setX(self.player, dt * 5)
        elif keys.get("arrow_left"):
            self.player.setH(self.player, dt * 100)
        elif keys.get("arrow_right"):
            self.player.setH(self.player, dt * -100)

Error:

Known pipe types: wglGraphicsPipe (all display modules loaded.) Traceback (most recent call last): File "main.py", line 83, in update self.monster.lookAt(NodePath(self.player)) TypeError: Arguments must match: NodePath() NodePath(PandaNode node) NodePath(str top_node_name) NodePath(const NodePath copy) NodePath(const NodePath parent, PandaNode child_node, Thread current_thread) NodePath(PandaNode node, Thread current_thread) NodePath(str top_node_name, Thread current_thread)

:task(error): Exception occurred in PythonTask update
Traceback (most recent call last):
File “main.py”, line 89, in
game.run()
File “C:\Panda3D-1.10.8-x64\direct\showbase\ShowBase.py”, line 3325, in run
self.taskMgr.run()
File “C:\Panda3D-1.10.8-x64\direct\task\Task.py”, line 541, in run
self.step()
File “C:\Panda3D-1.10.8-x64\direct\task\Task.py”, line 495, in step
self.mgr.poll()
File “main.py”, line 83, in update
self.monster.lookAt(NodePath(self.player))
TypeError: Arguments must match:
NodePath()
NodePath(PandaNode node)
NodePath(str top_node_name)
NodePath(const NodePath copy)
NodePath(const NodePath parent, PandaNode child_node, Thread current_thread)
NodePath(PandaNode node, Thread current_thread)
NodePath(str top_node_name, Thread current_thread)

In python, when we add the __int__ method, we can convert a class’s object to int. Now when I am trying to convert to NodePath, it isn’t working.

Okay, I suspect that you understand what the error is saying, but just in case, let me explain that before I get on to the cause and a solution:

Essentially, it seems to be saying that you’re attempting to construct a “NodePath” object, but that there’s no constructer for the “NodePath” class that takes the parameters that you’re trying to give it.

Looking at your code, this seems to be because the “player” object of the “Game” class is an object of type “Player”–and naturally NodePaths aren’t set up to construct themselves based on a “Player” object.

I’m guessing that you want the monster to look at the player-character’s stored NodePath. In that case, looking at your “Player” class, it seems that you store said NodePath in a variable called “player”. (Which seems like a potential source of confusion, but isn’t incorrect.)

So, what you perhaps want, then, is to instead look at the “player” object of the “player” object of the “game” object. Something like this:

self.monster.lookAt(self.player.player)

(There’s no need (that I see, at least) to construct a new NodePath in this case, since the object in question is already a NodePath.)

… I am not at all confident of what you mean here. Could you explain please? I’m concerned that you might have misapprehended something–although it’s also possible that I’m simply not managing to gather the intended meaning from your sentence, or that you’re referring to a feature that I’m not familiar with.

This is more about Python rather than Panda3D
It goes like this. For example I make a class, which has an int value, we can use this method.

class MyClass:
    def __int__(self):
        return 10

print(int(MyClass()))
# Outputs 10

EDIT: Same goes for strings and other data types like:

string __str__
bool __bool__

Ah, I see!

Okay, I’m familiar with what you mean.

However, it’s not something that can be done between just any two classes. You can convert freely to certain classes–“str”, for example–if I recall correctly, but not to most.

(And what you get when converting to things like “str” may depend on whether certain internal functions are implemented or not, and if so, what they do.)

For example, this doesn’t work:

# Make a list
mew = ["cat"]

#Try to cast it to a dictionary
meow = dict(mew)
# Crashes

Similarly:

from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectButton import DirectButton

# Make a button
mew = DirectButton(text = "mew")

# Try to cast it to an OnscreenText
meow = OnscreenText(mew)
# Crashes

OK. What you said earlier solved the problem anyway.

1 Like

Fair enough!

By the way, I don’t think that your “MyClass” example would work: the __init__ method isn’t supposed to return a value.

I tried it and it did output 10 without __init__. The __init__ method is not necessary. It is only used when you want to set default values. In this case, you will need the __init__ method:

class MyClass:
    def __init__(self):
        self.num = 10
    
    def __int__(self):
        return self.num

print(int(MyClass()))
# Outputs 10

Otherwise it works without __init__

The __init__ method may be used for general initialisation, not just default values, I believe.

But, ah, I see! I misread your “MyClass” example–I didn’t realise that you had “__int__” instead of “__init__”! Fair enough, and my mistake! ^^;

Of course, in that case, you’re not really casting the class–you’re just telling Python to use the value “10” when asked to cast the class.

Mistakes happen.

1 Like

Now I have another problem where “again” events are not generated.
Code:

from direct.showbase.ShowBase import ShowBase
from direct.actor.Actor import Actor
from direct.task import Task
from direct.gui.OnscreenText import OnscreenText
from panda3d.core import *
from classes import *
loadPrcFile("config/config.prc")

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.disableMouse()
        
        self.cTrav = CollisionTraverser()
        self.pusher = CollisionHandlerPusher()
        self.pusher.addInPattern("%fn-into-%in")
        self.pusher.addAgainPattern("%fn-again-%in")
        self.pusher.addOutPattern("%fn-outof-%in")
        self.pusher.setHorizontal(True)
        
        self.room = self.loader.loadModel("models/room.egg")
        self.room.setH(270)
        self.room.reparentTo(self.render)
        
        self.player = Player(Point3(0, -20, 2))
        
        self.keyMap = {"w" : False, "a" : False, "s" : False, "d" : False, "arrow_left" : False, "arrow_right" : False}
        
        for key in self.keyMap:
            self.accept(key, self.updateKeyMap, [key, True])
            self.accept(key + "-up", self.updateKeyMap, [key, False])
        
        self.taskMgr.add(self.update, "update")
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionCapsule(-4, -6, 1, -1, -6, 1, 0.5)
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(1, 0, 0), Point3(-5, 0, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(0, 1, 0), Point3(6, -15, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(-1, 0, 0), Point3(5, -5, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        wallNode = CollisionNode("wall")
        wallSolid = CollisionPlane(Plane(Vec3(0, -1, 0), Point3(-3, 5, 2)))
        wallNode.addSolid(wallSolid)
        wallC = render.attachNewNode(wallNode)
        
        self.monster = Actor("models/monster1.egg", {"attack" : "models/monster1-pincer-attack-both.egg", "explode" : "models/monster1-explode.egg"})
        self.monster.setScale(0.25, 0.25, 0.25)
        self.monster.reparentTo(self.render)
        
        monsterCenter = self.monster.getBounds().getCenter()
        monsterRad = 2
        monsterNode = CollisionNode("monster")
        monsterNode.addSolid(CollisionSphere(monsterCenter, monsterRad))
        monsterC = self.monster.attachNewNode(monsterNode)
           
        self.cTrav.addCollider(monsterC, self.pusher)
        self.pusher.addCollider(monsterC, self.monster)
        
        self.healthText = OnscreenText("Health: " + str(self.player.health), pos=(-1.1, 0.9), scale=0.07, mayChange=True)
        
        self.accept("monster-into-player", self.handleHealth, [True])
        self.accept("monster-into-player", self.handleHealth, [True])
        self.accept("monster-into-player", self.handleHealth, [False])
        
        self.taskMgr.add(self.checkGameOver, "Check Game Over")
        
        #self.accept("p", self.printPos)
        
    """def printPos(self):
        print(self.camera.getPos())"""
    
    def handleHealth(self, collisionEntry, param): # I don't know what to call the parameter
        if param:
            self.player.health -= 1
            self.healthText.setText("Health: " + str(self.player.health))
    
    def checkGameOver(self, task):
        if self.player.health <= 0:
            gameOverText = OnscreenText("GAME OVER", pos=(0, 0), scale=0.25)
             
        return Task.cont
            
    def updateKeyMap(self, key, value):
        self.keyMap[key] = value
        
    def update(self, task):
        dt = globalClock.getDt()
        
        self.player.update(self.keyMap, dt)
            
        self.monster.lookAt(self.player.player)
        self.monster.setY(self.monster, dt * 5)
        
        return Task.cont
        
game = Game()
game.run()

It is only decreasing health on the “into” event, not “again”.

EDIT: The again event is only recorded when the camera is colliding with the wall.

Could you please make a new thread for the new issue? That way other people with similar issues might be able to more-easily find solutions.

Here you go:

Thank you! :slight_smile: