physics impulse don't follow node rotation

I’m studying the engine simple physics and I’m actually facing something I’m simply unable to see what’s wrong with it: I just want to shoot bullets I produce with a function that return the topmost nodepath of a woking node structure to live in physics environment with a gravity force applied, and all works fine until I decide to rotate one of these nodes - the problem is that the impulse force I use to shoot’em still shoot in the same direction even after I rotated the topmost nodpath. The following is a working (not) excerpt of what I’m talking about - use arrow keys to rotate the smiley and enter to shoot.

import math, random, sys
from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.gui.OnscreenText import OnscreenText

import direct.directbase.DirectStart

DO=DirectObject()

#=========================================================================
# Scenographic stuff

base.cam.setPos(25,-10,20)
base.cam.lookAt((0,0,0))

infotext={}
infotext['hint']=OnscreenText(text = 'ARROWKEYS to aim\nENTER to shoot', pos = (-1.3, .0), scale = 0.05,
  mayChange=True, fg=(1,1,1,1), align=TextNode.ALeft, bg=(1, .3, 0, .6),
  wordwrap=15
)
infotext['message']=OnscreenText(text = '', pos = (0, -0.85), scale = 0.07, mayChange=True, fg=(1,1,1,1), bg=(1,0,0,.65))

#=========================================================================

base.cTrav=CollisionTraverser()
base.cTrav.setRespectPrevTransform(True)
base.enableParticles()
collisionHandler = PhysicsCollisionHandler()

cp = CollisionPlane(Plane(Vec3(0, 0, 1), Point3(0, 0, 0)))
planeNP = render.attachNewNode(CollisionNode('planecnode'))
planeNP.node().addSolid(cp)
planeNP.show()

globalforcesFN=ForceNode('world-forces')
globalforcesFNP=render.attachNewNode(globalforcesFN)
globalforcesGravity=LinearVectorForce(0,0,-9.81)
globalforcesFN.addForce(globalforcesGravity)
base.physicsMgr.addLinearForce(globalforcesGravity)

#** a visual shooting nozzle representation
nozzlemodel=loader.loadModel('zup-axis')
nozzlemodel.setScale(.3)
nozzlemodel.setCollideMask(BitMask32.allOff())

#** this is the function that make the physics balls
def phyball_dispenser(modelname, scale=1.):
  ballAN=ActorNode("ball_actnode")
  ballANP=render.attachNewNode(ballAN)
  ballmodel=loader.loadModel(modelname)
  ballmodel.reparentTo(ballANP)
  ballmodel.setScale(scale)

  ballCollider = ballANP.attachNewNode(CollisionNode('ballcnode'))
  ballCollider.node().addSolid(CollisionSphere(0,0,0, 1*scale))
  base.physicsMgr.attachPhysicalNode(ballAN)
  collisionHandler.addCollider(ballCollider, ballANP)
  base.cTrav.addCollider(ballCollider, collisionHandler)
  # now the physic ball is ready to exit off the dispenser
  return ballANP

#** let's create a physics smiley and stick it the gun
smiley=phyball_dispenser('smiley')
nozzlemodel.reparentTo(smiley)
nozzlemodel.setH(180)
nozzlemodel.setPos(-1,.5,0)
smiley.setH(180)

#** just an helper function - never mind
def acce(k,h,p):
  DO.accept(k, h, p)
  DO.accept(k+'-repeat', h, p)

def shoot():
  """ first off create a physics ball via the dispenser above,then place it at the nozzle origin and at last pun an Y inpulse to it
  """
  bullet=phyball_dispenser('frowney', .2)
  bullet.setPos(nozzlemodel.getPos(base.render)+Point3(0,2,0))
  bullet.setHpr(nozzlemodel.getHpr(base.render))
  bullet.node().getPhysicsObject().addImpulse(Vec3(0, 50, 0))
  infotext["message"].setText("BulletHpr :%r"%bullet.getHpr())
DO.accept('enter', shoot)

def smileyaim(hpr):
  smiley.setHpr(smiley.getHpr()+hpr)
  infotext["message"].setText("SmileyHPR:%r"%smiley.getHpr())
  
aimspd=.4
acce('arrow_up', smileyaim, [Point3(0,-aimspd,0)])
acce('arrow_down', smileyaim, [Point3(0,aimspd,0)])
acce('arrow_left', smileyaim, [Point3(aimspd,0,0)])
acce('arrow_right', smileyaim, [Point3(-aimspd,0,0)])
DO.accept('escape',sys.exit)

run()

well after a good supper I made it
was just that I thought to simplify the structure cutting the topmost pandanode thinking unnecessary:

changing this;

ballAN=ActorNode("ball_actnode")
  ballANP=render.attachNewNode(ballAN)
  ballmodel=loader.loadModel(modelname)
  ballmodel.reparentTo(ballANP)
  ballmodel.setScale(scale) 

to this:

  ballNP=NodePath(PandaNode("physicsball"))
  ballAN=ActorNode("ball_actnode")
  ballANP=ballNP.attachNewNode(ballAN)
  ballmodel=loader.loadModel(modelname)
  ballmodel.reparentTo(ballANP)
  ballmodel.setScale(scale)
  ballNP.reparentTo(render)

now it’s allright

Unless I’m missing something I think you just misused a function. The addImpulse function appears to use world coordinates. I looked up the api and they have an addLocalImpulse function.

Just go to your shoot function, line 82 specifically, and change addImpulse to addLocalImpulse and see if it behaves as you expected.

Edit: One more little problem in the shoot function here

bullet.setPos(nozzlemodel.getPos(base.render)+Point3(0,2,0))

The way you add the Point3 that’s also going to be in world coordinates, not local. Try this.

  bullet.setPos(nozzlemodel.getPos(base.render))
  bullet.setHpr(nozzlemodel.getHpr(base.render))
  #offset from origin to barrel here
  bullet.setPos(bullet, -1,2,0)

actually the solution I used above solved this particular issue but the problem is elsewhere - looks like there really is something weird happening using this stuff. Look at the followup cited above to see by yourself.