Collision is not detecting

I am trying to click on my enemy to attack it, but it is not being detected:
Castle Adventure 3D.zip (2.0 MB)

Again, would you mind please posting the relevant parts of your code–note, I don’t mean the whole thing!–rather than asking us to download and comb through everything?

Let me be more precise. I want my monster to be able to die. And to do so, I need to click on the monster. But when I try to do so, it is not working.
(I used a CollisionHandlerQueue earlier, but now I am using a CollisionHandlerPusher’s event system. If you want to see the former’s code, see it in the archive):

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 *
from time import sleep
loadPrcFile("config/config.prc")

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        
        self.disableMouse()
        
        self.cTrav = CollisionTraverser()
        self.pickerTraverser = CollisionTraverser()
        self.pusher = CollisionHandlerPusher()
        self.queue = CollisionHandlerQueue()
        self.pusher.addInPattern("%fn-into-%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 = BabyMonster(Point3(0.25, 0.25, 0.25))
        
        self.healthText = OnscreenText("Health: " + str(self.player.health), pos=(-1.1, 0.9), scale=0.07, mayChange=True)
        
        self.accept("monster-into-player", self.monsterToPlayer)
        
        self.taskMgr.add(self.checkGameOver, "Check Game Over")
        
        self.pickerNode = CollisionNode("picker")
        self.pickerNP = self.camera.attachNewNode(self.pickerNode)
        self.pickerRay = CollisionRay()
        self.pickerNode.setIntoCollideMask(0)
        self.pickerNode.addSolid(self.pickerRay)
        self.pickerTraverser.addCollider(self.pickerNP, self.queue)
        
        self.accept("mouse1", self.click)
        
        self.taskMgr.add(self.checkMonsterDead, "Check Monster Dead")
        
        #self.accept("p", self.printPos)
        
    """def printPos(self):
        print(self.camera.getPos())"""
    
    def monsterToPlayer(self, collisionEntry):
        self.player.health -= 1
        self.healthText.setText("Health: " + str(self.player.health))
    
    def playerToMonster(self, collisionEntry):
        self.monster.health -= 1
    
    def checkGameOver(self, task):
        if self.player.health <= 0:
            gameOverText = OnscreenText("GAME OVER", pos=(0, 0), scale=0.25)
             
        return Task.cont
    
    def checkMonsterDead(self, task):
        if self.monster.health <= 0:
            self.monster.actor.play("explode")
            self.monster.actor.removeNode()
            self.taskMgr.remove(self.checkMonsterDead)
        
        return Task.cont
    
    def click(self):
        if self.mouseWatcherNode.hasMouse():
            mpos = self.mouseWatcherNode.getMouse()
        self.pickerRay.setFromLens(self.camNode, mpos.x, mpos.y)
        
        self.pickerTraverser.traverse(self.render)
        
        self.accept("picker-into-monster", self.playerToMonster)
            
    def updateKeyMap(self, key, value):
        self.keyMap[key] = value
        
    def update(self, task):
        dt = globalClock.getDt()
        
        self.player.update(self.keyMap, dt)
        self.monster.actor.lookAt(self.player.player)
        self.monster.update(self.player, dt)
        
        return Task.cont
        
game = Game()
game.run()

```python
from direct.showbase.DirectObject import DirectObject
from direct.actor.Actor import Actor
from direct.gui.OnscreenText import OnscreenText
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 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)

class BabyMonster(DirectObject):
    def __init__(self, scale):
        self.actor = Actor("models/monster1.egg", {"attack" : "models/monster1-pincer-attack-both.egg", "explode" : "models/monster1-explode.egg"})
        self.actor.setScale(0.25, 0.25, 0.25)
        self.actor.reparentTo(base.render)
        self.actor.loop("attack")
        
        self.health = 4
        #self.health	
        
        monsterCenter = self.actor.getBounds().getCenter()
        monsterRad = 2
        monsterNode = CollisionNode("monster")
        monsterNode.addSolid(CollisionSphere(monsterCenter, monsterRad))
        monsterC = self.actor.attachNewNode(monsterNode)
        monsterC.show()
        
        base.cTrav.addCollider(monsterC, base.pusher)
        base.pusher.addCollider(monsterC, self.actor)
        
    def update(self, player, dt):
        self.actor.lookAt(player.player)
        self.actor.setY(self.actor, dt * 5)

I guess one of your problems is that you are setting your ray as “into” object.

1 Like

So should I just remove the self.pickerNode.setIntoCollideMask(0) line?

Greetings, Pignon! Welcome to the community! :slight_smile:

I don’t see anything setting the ray to be an “into” object–but then panda3dmastercoder posted quite a bit of code, and I didn’t go through all of it carefully.

panda3dmastercoder, please do post just the relevant sections: not only is it easier for those of us who might help, but that fact makes it more likely that you’ll be helped, I imagine.

That said, it looks like you are in fact still adding your ray to the queue-handler. Hence no event is generated, and thus your event-method isn’t being called.

No, I’d recommend keeping it: that line prevents the ray from acting as an “into” object (by giving it a zero-mask, with zero matching no pattern).

Oh. When I switched to event, I forgot I still left it on the queue. Also I set the into collide mask to 0 as panda3d raised an error to do so. Now I think it might work with the queue. I will try.

I am not quite sure where the problem was coming, so I pasted the whole thing. I put classes.py so you could see the monsters collision system but forgot to put only the monster class.

1 Like

What should I do for the pusher.addCollider method?

Try to add this

pickerNode.setFromCollideMask(GeomNode.getDefaultCollideMask())

Thats what I meant. You need to add “From” mask to the ray. Im just learning so I didnt express myself in proper terms.

That’s fair.

However, things like, say, the “update” methods, or the keymap stuff, for example, are very unlikely to be relevant. Those could have been removed and made looking through the code a little bit easier.

For a ray, you don’t actually want the ray to be “pushed”, so I think that you would skip teh call to “pusher.addCollider”, using only the “pickerTraverser.addCollider” call.

I don’t think that you need to manually add a “from” mask–the default one is likely fine for the moment.

(Now, it may later become useful to apply a “from” mask, such as to prevent the player’s collision from colliding with the ray.)

1 Like

Thaumaturge is right. What I said is not necessary. You need to use CollisionHandlerEvent or something with a pattern. Or maybe CollisionHanlerQueue if you look through its entries for collisions?

1 Like

I am using a queue but it isn’t being detected.

It is detecting, try to run this every frame:

print(self.queue.getEntries())

but you are not doing anything with the entries anywhere in your code.

By the way, note that CollisionHandlerQueue has a “sortEntries” method that will rearrange the entries such that they’re ordered from closest to furthest. This can be very useful when looking for only the closest hit, I do believe!

Just to be clear: if you’re using the queue, you likely shouldn’t be adding the ray to the pusher-handler, or passing in the pusher-handler when you add your ray to your traverser.

As to the main problem, you’re using a queue, so there are no events being generated.

Instead, just check the contents of queue as appropriate.

No. I made all the necessary changes.

I updated the code.

Thanks @Thaumaturge and @Pignon. For helping me solve the problem. It now works with the CollisionHandlerQueue. (You both helped solve the problem so I am putting your names here as a solution).

EDIT: Actually, it didn’t work when I posted this message. What I was using was pickedObj.getNetTag(“mytag”). I changed it to pickedObj.getNetPythonTag(“mytag”) as I was using actors. Thanks anyways.

1 Like