Gravity and Projectiles

Hello there,

I’m using the Projectile class to fire an arrow but have problems with the gravity multiplier. The arrow’s parent, the bow, rotates in all three axes sporadically depending on the Hpr of the arm. The arrow is reparented to the render to fire correctly when the Proj class is called. This works fine except for the gravity multiplier. Depending on the rotation of the bow, gravity will be applied in different directions (swerve the arrow right/left) rather than a global Z position.

I tried to set gravity at 0 and then apply my own gravity task but there was still a small swerve effect, plus I got flickering issues.

Is there anything I can alter in the Projectile class so that the Z acc is applied against the render Z pos rather than the nodepath’s? Or any other ways round this?

I reckon this could be solved using clever parenting relationships but can’t get it to work. I ignored the roll of the bow (arrow.setR(render,0)) when calculating the arrow’s HPR but that also didn’t work, it seems as though when the bow moves around an overall Roll effect is determined by changes in H,P & R.

could you show some piece of code?

OK so I have my bow which is parented to my leftHand that is driven by mocap data which is stored in an array:

#Left Hand

Then array is attached to a dummyNode (cross) which is parented to the bow:

self.cross = self.bow.attachNewNode('aimer')
self.arrow = loader.loadModel("Eggs/arrow")

If the arrow was directly attached to the bow, the arrow would not fire in the direction the bow was facing when fired. It appeared necessary to use the dummy node.

When ‘fire’ command is issued:

self.arrowFlight = ProjectileInterval(self.arrow,startPos = self.arrow.getPos(), startVel = Point3(100*speed,0,0), duration = 5, gravityMult = 2)

If your leftHand is in a default bow holding position the gravity effect works perfectly. If you rotate your hand 90degrees so your holding the bow in the crossbow type orientation the arrow swerves off to the right.


yes it is a common practice - looks like a similar problem I had - you just got to reorient the cross dummy nodepath to the correct orientation and voila’

Yeah- cross is staying fixed in space and the arrow is staying in cross’ coordinate space, meaning gravity is applied in cross’ coordinate space rather than in render space. You’ll either need to reorient cross and manually account for scale differences, or just fire the arrow straight from render using cross’ position to determine your startVel.

nono I misunderstood your issue sorry
so looks like seeing your parented chain at last all is parented to the hand therefore you must to place your cross dummy according to the position of the hand (use getPos(render) to know where it is in global space) while is parented to render and not to the bow

Cool but I’m having a bit of difficulty getting this node orientated. I want to keep both the heading and pitch intact as they are responsible for the direction and altitude of the arrow - its the roll that I want to get rid of. I try using:

self.cross.setR(render, 0)

But then my arrow cos bonkers and flies in a completely different direction to my bow.

I set up some predefined animation where by the hand rotates around the roll axes only. I printed out the global hpr values for the cross dummyNode and they all change by a large amount. Is there some other way to get the dummy back to his default P!? Thanks for your help.

I’ve given these methods a quick go but still no luck. Here is what I have:

self.cross = render.attachNewNode('aimer')
self.cross.setHpr(render, self.bow.getHpr())
self.arrowFlight = ProjectileInterval(self.arrow,startPos = self.arrow.getPos(), startVel = Point3(100*speed,0,0), duration = 5, gravityMult = 2)

…and no luck, arrow = bonkers again. I think it stems from the fact that the bow is orientated so that a roll isn’t necessary a straight roll but a combination of H,P & R, seems that way when I print self.bow.getHpr(render).
The method I had in place fired the arrow perfectly but it was just the gravity thing so I thought maybe the ProjInt class could be modified so the gravity variable effects global space?

  1. Your cross node complicates everything. Do you really need it ?
  2. Your startVel = Point3(100*speed,0,0) means you want to launch it toward X+ axis. Is that true ?

Assuming the arrow head is toward Y+, without cross node, I’d do it this way (A is arrow):

  1. A.wrtReparentTo(render)
  2. startPos = A.getPos()
  3. startVel = render.getRelativeVector(A, Vec3(0,1,0))

The important point is CONSISTENCY of coordinate space, calculate everything in your node’s parent space, otherwise you’re wasting your time.

Using a dummy node can still be a quick and easy way to get an object to move the way it’s facing. But yeah- make sure you know your coordinate space. As I said before, I might suggest something like

[arrow starts parented to bow, cross is parented to bow]
dir = cross.getPos(render) - hand.getPos(render)
dir = dir*(1.0/dir.length) # or dir.normalize(), I may be mixing languages/syntaxes on the fly...
flight = self.arrow.ProjectileInterval(startVel = dir*100, duration = 5, gravityMult = 2) 

Thanks for all your help, this solved my problem:

        self.arrowFlight = ProjectileInterval(self.arrow,startPos = self.arrow.getPos(), startVel = render.getRelativeVector(self.arrow, Vec3(100*speed,0,0)), duration = 5, gravityMult = 2)

I believe I had to apply in X-direction due to the nature of the bow’s parents (leftHand->leftArm->leftShoulder etc) default positions. Anyhow it works perfect AND with gravity applied correctly. Many thanks, going to try and play around with the rope class to get a GOW Torque Bow type effect!

gee you like to complicate things indeed :slight_smile:
hope you’ll share some demo when you finished cos I’m interested in this stuff