Ammo.js - basketball game, make a shot successfully - AKA motion trajectory

Hi, I’m really having trouble figuring out how to throw a ball to a point (hoop). I’ve read a ton on motion trajectory, but not figuring it out. I attempted to convert a C# Unity script that supposedly does what I need, but it’s not working for me, perhaps i didn’t convert it correctly. The function should recieve the ball and rim’s positions, and angle, and return force vector (velocity?). Then I will apply it to the ball to make a perfect shot:

getBallVelocity = function( ballPos, rimPos, angleDegrees, gravity ){
          
          const Vector3 = {
            forward: new THREE.Vector3( 0, 0, 1 ),
            up: new THREE.Vector3( 0, 1, 0 )
          };
          
          // Get angle in radians, from angleDegrees argument
          const angle = THREE.Math.degToRad( angleDegrees );
          
          gravity = gravity || 9.81;
   
          // Positions of this object and the target on the same plane
          const planarRimPos  = new THREE.Vector3( rimPos.x, 0, rimPos.z ),
                planarBallPos = new THREE.Vector3( ballPos.x, 0, ballPos.z );
   
          // Planar distance between objects
          const distance = planarRimPos.distanceTo( planarBallPos );
          
          // Distance along the y axis between objects
          const yOffset = rimPos.y - ballPos.y;
          
          // Calculate velocity 
          const initialVelocity = ( 1 / Math.cos( angle ) ) * Math.sqrt( ( 0.5 * gravity * Math.pow( distance, 2 ) ) / ( distance * Math.tan( angle ) + yOffset ) ),
                velocity = new THREE.Quaternion( 0, initialVelocity * Math.sin( angle ), initialVelocity * Math.cos( angle ) );
   
          // Rotate our velocity to match the direction between the two objects
          const planarPosDifferenceBetweenObjects = planarRimPos.sub( planarBallPos ),
                angleBetweenObjects = Vector3.forward.angleTo( planarPosDifferenceBetweenObjects ),
                angleUpRotated = new THREE.Quaternion().setFromAxisAngle( Vector3.up, angleBetweenObjects ),
                finalVelocity = angleUpRotated.multiply( velocity );
          
          return finalVelocity;
        }

The code I converted from is here: https://forum.unity.com/threads/how-to-calculate-force-needed-to-jump-towards-target-point.372288/#post-2415612

Also, doesn’t need mass?

Please help, I’m running out of time, and if someone wants me to hire them to solve this, I’m willing to pay. Just contact me.

NOTE: I’ve also posted this question on stack overflow: https://stackoverflow.com/questions/65713249/ammo-js-three-js-calculate-force-vector-needed-to-make-a-basketball-shot

Thanks!
-Joe

2 Likes

Solved it!

OK, three things:

  1. The rotation of the velocity wasn’t working. Used atan2 instead.
  2. I needed to switch the subtracting Y axes points getting the yOffset
  3. I needed to use .setVelocity(x, y, z) instead of .applyForce(x, y, z)

Here is the final script, hope it helps someone!

static getBallVelocity( ballPos, rimPos, angleDegrees, gravity ){
 
  // Get angle in radians, from angleDegrees argument
  const angle = THREE.Math.degToRad( angleDegrees );
 
  gravity = gravity || 9.81;
 
  // Positions of this object and the target on the same plane
  const planarRimPos  = new THREE.Vector3( rimPos.x, 0, rimPos.z ),
        planarBallPos = new THREE.Vector3( ballPos.x, 0, ballPos.z );
 
  // Planar distance between objects
  const distance = planarRimPos.distanceTo( planarBallPos );
 
  // Distance along the y axis between objects
  const yOffset = ballPos.y - rimPos.y;
 
  // Calculate velocity
  const initialVelocity = ( 1 / Math.cos( angle ) ) * Math.sqrt( ( 0.5 * gravity * Math.pow( distance, 2 ) ) / ( distance * Math.tan( angle ) + yOffset ) ),
        velocity = new THREE.Vector3( 0, initialVelocity * Math.sin( angle ), initialVelocity * Math.cos( angle ) );
   
  // Rotate our velocity to match the direction between the two objects
  const dy = planarRimPos.x - planarBallPos.x,
        dx = planarRimPos.z - planarBallPos.z,
        theta = Math.atan2( dy, dx ),
        finalVelocity = velocity.applyAxisAngle( PopAShotAR.Vector3.up, theta )
 
  return finalVelocity;
}
1 Like