I’ve stumbled upon an odd behaviour, and I’m not sure of whether it’s a bug, or whether I’m doing something with an undefined result:
In broad strokes, I have two CollisionNodes, intended to collide with each other. However, instead of moving one into the other, I’m changing the radius of one of the solids in a task, until that solid’s CollisionNode thus engulfs the other CollisionNode.
(Note for clarity: I’m not scaling the node; I’m changing the radius of the solid.)
The problem is that… it doesn’t work.
Or rather, it works perfectly well as long as the expanding CollisionNode is the “from”-object. When the expanding CollisionNode is instead the “into”-object, I get neither “in” nor “again” events.
Here below is a short test-program that demonstrates the issue on my machine. It creates two CollisionNodes, and offers buttons to start a task that either changes the radius of or moves one of those nodes, sufficiently that it should collide with the other node. Two labels indicate whether an “in” or “again” event has fired.
You should find that when the “Position” button is pressed and one node moves to encounter the other, both labels “light up”. And that conversely, when the “Scale” button is pressed and one node changes radius to encounter the other, neither label “lights up”.
You should also find that if you change the call to “addCollider” to use the node that is altered instead of the other node, the labels should “light up” for both approaches.
from direct.showbase.ShowBase import ShowBase
from panda3d.core import CollisionNode, CollisionSphere, CollisionTraverser, CollisionHandlerEvent
from direct.gui.DirectGui import *
from panda3d import __version__ as pandaVersion
print (pandaVersion)
import sys
print (sys.version)
class Game(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.scale = False
self.timer = 0
self.speed = 0.5
self.resetting = False
node = CollisionNode("mew")
self.solid = CollisionSphere(-2, 10, 0, 1)
node.addSolid(self.solid)
self.np1 = render.attachNewNode(node)
self.np1.show()
node = CollisionNode("mew 2")
self.solid2 = CollisionSphere(2, 10, 0, 1)
node.addSolid(self.solid2)
self.np2 = render.attachNewNode(node)
self.np2.show()
self.cTrav = CollisionTraverser()
self.handler = CollisionHandlerEvent()
self.handler.addAgainPattern("again")
self.handler.addInPattern("into")
self.cTrav.addCollider(self.np2, self.handler)
self.accept("again", self.again)
self.accept("into", self.into)
self.label1 = DirectLabel(text = "INTO", scale = 0.25, frameColor = (0.1, 0.1, 0.1, 1), pos = (0, 0, -0.65))
self.label2 = DirectLabel(text = "AGAIN", scale = 0.25, frameColor = (0.1, 0.1, 0.1, 1), pos = (0, 0, -0.9))
self.btn1 = DirectButton(text = "Scale", scale = 0.2, command = self.startScaling, pos = (0, 0, 0.8))
self.btn2 = DirectButton(text = "Position", scale = 0.2, command = self.startPositioning, pos = (0, 0, 0.55))
def startScaling(self):
self.scale = True
self.taskMgr.add(self.update, "update")
self.btn1.hide()
self.btn2.hide()
def startPositioning(self):
self.scale = False
self.timer = 1
self.taskMgr.add(self.update, "update")
self.btn1.hide()
self.btn2.hide()
def again(self, entry):
self.label2["frameColor"] = (0.3, 0.7, 0.5, 1)
def into(self, entry):
self.label1["frameColor"] = (0.3, 0.7, 0.5, 1)
def update(self, task):
# Reset the demo
if self.resetting:
self.timer -= self.clock.getDt()
if self.timer <= 0:
self.resetting = False
self.btn1.show()
self.btn2.show()
self.solid.setRadius(1)
self.np1.setX(0)
self.label1["frameColor"] = (0.1, 0.1, 0.1, 1)
self.label2["frameColor"] = (0.1, 0.1, 0.1, 1)
return task.done
return task.cont
# The actual logic: either scale the solid,
# or move its node-path
if self.scale:
if self.solid.getRadius() < 5:
self.solid.setRadius(self.solid.getRadius() + self.speed * self.clock.getDt())
else:
self.resetting = True
self.timer = 1
else:
if self.np1.getX() < 3:
self.np1.setX(self.np1, self.speed * self.clock.getDt())
else:
self.resetting = True
self.timer = 1
return task.cont
app = Game()
app.run()
Thoughts…?