Is there a reason why my collision polygons (Into) despite having collision solids still fail to use pusher, even if collision is detected?

So while trying to get better at panda3d i tried to forge some script. and met an issue when trying to make my collisions work. It does detect it, but no effect of Pusher is visible and even though when calling show on cnode path the meshes are correct it never does anything. The error i get is

(all display modules loaded.)
:collide(error): Invalid attempt to detect collision from CollisionPolygon!

This means that a CollisionPolygon object was added to a
CollisionTraverser as if it were a colliding object.  However,
no implementation for this kind of object has yet been defined
to collide with other objects.

My actual code is composed of multiple scripts, but that’s where i define the cNodes and append them to traverser and pusher

from panda3d.core import CollisionNode, CollisionPolygon, CollisionHandlerPusher, CollideMask
from reference import REFERENCE


class cone():
    CONES = {}
    speed = 1
    NAMEID = 'cone'

    @classmethod
    def getInstances(cls,id):
        if id == -1:
            return cls.CONES
        else:
            try:
                return cls.CONES[id]
            except Exception as e:
                REFERENCE.ReturnExceptionPretty(e)


    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls)
        cls.CONES[len(cls.CONES)] = obj
        return obj



    def __init__(self,where,ctrav,pusher):
        self.id = self.getId()
        self.model = loader.loadModel(REFERENCE.loadTexturePath('cone_phy.bam'))
        self.node = render.attachNewNode(f'{self.NAMEID}{self.id}')
        x, y, z = where
        self.model.setPos(x, y, z)
        self.node.setPos(x, y, z)
        self.model.reparentTo(self.node)
        self.cNodeP = self.model.find("**/+CollisionNode")
        self.cNodeP.node().setIntoCollideMask(CollideMask.bit(0))
        self.cNodeP.show()

        pusher.horizontal = True
        pusher.addCollider(self.cNodeP, self.model)
        ctrav.addCollider(self.cNodeP, pusher)






    def getId(self):
        for k,v in self.CONES.items():
            if v == self:
                return k



I did assume that all colliding things which use pusher handler should share same instance of pusher, but I’m not sure that’s correct.

Just to clarify I used blend2bam python module to get my collision meshes from blender rb


That’s the meshes if it be helpful in any way.

a lot of this is ‘stolen’ from roaming ralph example so i might’ve done some really weird errors combining stuff i picked here and there, so forgive me if its something obvious

thought adding the main script where i “generate” cTrav and Pusher, would be useful

from panda3d.core import Vec3, CollisionHandlerPusher, CollisionHandlerQueue
from panda3d.bullet import BulletWorld
from direct.showbase.ShowBase import ShowBase, CollisionTraverser
from panda3d.core import MouseWatcher
from panda3d.core import WindowProperties
from Char import Char
from dafollowcam import FollowCam
from cone import cone
from map import Map

import cv2
winder = cv2.namedWindow('oooooooooo')

def noting(nut):
    pass
cv2.createTrackbar('x','oooooooooo',0,50,noting)
cv2.createTrackbar('y','oooooooooo',0,50,noting)
cv2.createTrackbar('z','oooooooooo',0,50,noting)






class MyApp(ShowBase):

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

        # Showbase augmentations
        self.disable_mouse()
        self.taskMgr.add(self.update, 'update')


        #Usefull objects monitor etc
        self.cTrav = CollisionTraverser()
        self.pusher = CollisionHandlerPusher()
        self.queue = CollisionHandlerQueue()
        self.rat = MouseWatcher()
        self.winder = WindowProperties()
        self.winder.setCursorHidden(True)
        self.winder.setMouseMode(WindowProperties.M_relative)
        self.win.requestProperties(self.winder)
        self.pusher = CollisionHandlerPusher()


        # events listeners
        self.accept("a", self.UpdateKeyMap, ["left", True])
        self.accept("a-up", self.UpdateKeyMap, ["left", False])
        self.accept("d", self.UpdateKeyMap, ["right", True])
        self.accept("d-up", self.UpdateKeyMap, ["right", False])
        self.accept("w", self.UpdateKeyMap, ["up", True])
        self.accept("w-up", self.UpdateKeyMap, ["up", False])
        self.accept("s", self.UpdateKeyMap, ["down", True])
        self.accept("s-up", self.UpdateKeyMap, ["down", False])
        self.accept("q", self.UpdateKeyMap, ["shoot", True])
        self.accept("q-up", self.UpdateKeyMap, ["shoot", False])
        self.accept("e", self.UpdateKeyMap, ["not shoot", True])
        self.accept("e-up", self.UpdateKeyMap, ["not shoot", False])
        self.MsX,self.MsY = None,None

        #keymap
        self.keyMap = {
            "up": False,
            "down": False,
            "left": False,
            "right": False,
            "shoot": False,
            'not shoot': False
        }


        # object instanciation
        #self.map = Map((0,0,0),self.cTrav,self.queue)
        self.cones = []

        a,b,c = 0,0,0
        for i in range(5):
            a = a + 4
            placeholder = cone((a,b,c),self.cTrav,self.pusher)
            self.cones.append(placeholder)

        self.character = Char(self.cTrav,self.pusher)

        self.FCAM = FollowCam(self.cam,self.character.node)


        #print(render.ls())


    def UpdateKeyMap(self, key, state):
        self.keyMap[key] = state




    def update(self,task):


        dt = globalClock.getDt()


        if self.mouseWatcherNode.hasMouse():
            self.MsX = ((base.mouseWatcherNode.get_mouse_x() + 1) / 2) * base.win.get_x_size()
            self.MsY = self.mouseWatcherNode.getMouseY()
            self.size = self.get_size()
            dx,dy = int(self.size[0]/2) - self.MsX, int(self.size[1]/2) - self.MsY


        self.character.Update_state(self.keyMap,dt)
        x,y,z = cv2.getTrackbarPos('x','oooooooooo'),cv2.getTrackbarPos('y','oooooooooo'),cv2.getTrackbarPos('z','oooooooooo')
        self.FCAM.update((x,y,z))










        if self.keyMap['shoot']:
            pass
        return task.cont



app = MyApp()
app.run()

and mb a script for second collision thingy as well

from panda3d.bullet import BulletTriangleMeshShape, BulletTriangleMesh
from panda3d.bullet import BulletRigidBodyNode
from panda3d.core import CollisionHandlerPusher, CollideMask
from reference import REFERENCE


class Char():
    speed = 20
    NAMEID = 'apple_char'
    ORIGIN = (0,0,1)
    def __init__(self,ctrav,pusher):
        x,y,z = self.ORIGIN
        self.model = loader.loadModel(REFERENCE.loadTexturePath('hatteblob.bam'))
        self.node = render.attachNewNode(self.NAMEID)
        self.model.setPos(x,y,z)
        self.node.setPos(x,y,z)
        self.model.reparentTo(self.node)
        self.futurepos = self.node.getPos()

        self.cNodeP = self.model.find("**/+CollisionNode")
        self.cNodeP.node().setIntoCollideMask(CollideMask.bit(0))
        self.cNodeP.show()


        pusher.horizontal = True
        pusher.addCollider(self.cNodeP, self.model)
        ctrav.addCollider(self.cNodeP, pusher)


        self.cmddict = {
            "up": self.Up,
            "down": self.Down,
            "left": self.Left,
            "right": self.Right,
            "shoot": self.beep,
            'not shoot': self.beep}

    def Update_state(self, keypass, dt):
        self.futurepos = self.node.getPos()

        for k, v in keypass.items():

            if v:
                self.cmddict[k](dt)

        self.node.setPos(self.futurepos)

    def Up(self, dt):
        self.futurepos.y += self.speed * dt

    def Down(self, dt):
        self.futurepos.y -= self.speed * dt

    def Left(self, dt):
        self.futurepos.x -= self.speed * dt

    def Right(self, dt):
        self.futurepos.x += self.speed * dt

    def beep(self, fff):
        pass











I see two potential issues, I believe:

First, since you’re adding both your “cones” and your “char” to the collision traverser, you’re indicating that both should be “from”-objects, not just “into”-objects. Thus the collision system will attempt to collide from both types of object into other collision objects.

And second, and more seriously, it’s as the error indicates: Panda doesn’t handle collisions from polygonal collision objects into other objects. You can, however, collide (certain) non-polygonal collision objects into polygonal ones. Thus a polygonal collision object can be an “into”-object, but not a “from”-object, I believe.

(In case you haven’t yet done so, see this manual page for more information.)

Thanks, Thaumaturge, I did indeed looked through documentation but I thought into and from refered to collision inside and outside the visible geometry. How would you recommend doing collision with terrain? I saw the roaming Ralph example and understand the ray system but instead of spheres I would like to use something more exact as I aim at eventually make a 3ed person whack and slash game

Ah, I see. It looks like you have the idea now, but to be on the safe side let me be explicit:

In Panda’s collision system, “into” and “from” refer to which object is colliding with which–or, looked at another way, which objects are “active” (i.e. they generate collision-responses when they collide with things) and which are “static” (i.e. they’re “background” objects; things that can be collided with, but that don’t generate responses themselves).

I would suggest that the terrain be composed of “into”-only objects. For one thing, you can likely use polygonal collision objects for such a terrain. (And I suspect that you’ll have better performance if large-scale, ubiquitous, and potentially-overlapping objects like terrain are “into”-only objects.)

How exact do you want it to be in the case of your character? And what sort of form will your character have?

In general, you might be surprised at how inexact you can be. For most third-person whack-and-slash games I’d likely use spheres, or perhaps a capsule if really called for. (Although using a capsule as your “from”-object may require either representing your terrain via other collision-objects or using Bullet, as capsule collision-objects can’t collide with polygonal collision objects, I think.)

If you really want a very exact representation of your player-character, I might suggest attaching various basic collider-shapes (spheres, etc.) to the skeleton of your character, and building an approximation of the character’s shape that way.

Thanks Thaumaturge once again, my characters eventually would be elliptical slimes, like maple story ones. And by terrain I actually mean trees and stuff as I will have a plane acting as my floor

1 Like

For your characters, if they’re elliptical, and if they don’t stretch too much, then I’d suggest just using spheres.

For your trees, I think that polygonal collision is likely fine.

I would suggest that you design the shapes for the types of interactions you’ll have, rather than just trying to match the geometry as well as possible. For a tree, if your characters are always staying near the ground and never flying up into the branches, a capsule solid (or even a sphere) around the trunk may well be sufficient and will be far more efficient than testing collisions against every triangle of every leaf of the tree. Solid shapes tend to behave much more stably and predictably than a random assortment of infinitely-thin polygons, so you can avoid a lot of potential physics glitches in your game that way.

1 Like