I’m building a basketball game with three.js and ammo.js. (Enable3d)
The hoop/rim and ball’s positions are constantly changing (AR) so the shots will have to be dynamic and relative.
I need to calculate the force vector to apply to the ball, for a successful shot. In the game play the user will swipe to shoot and this will effect the “perfect shot” force.
I’ve seen many examples of code and equations for calculations of trajectories, ballistics, etc, and I’ve been converting them to JavaScript from C# as a lot of the scripts I’m finding are on the Unity forums.
I need a function that calculates the initial force vector3 To apply to the ball using the position of the ball, position of the hoop, the ball’s mass, and gravity. The initial angle or max height (terminal velocity y) will also have to be passed to this function, as I’ve noticed in all the equations and calculators I’ve seen.
EDIT:
So I converted a script I found on the Unity forums (Below), to Javascript/Three.js:
function getBallVelocity( 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;
}
I'm calling the shot like this:
const velocity = getBallVelocity( ball.position, rim.position, 45 );
ball.body.applyForce( velocity.x, velocity.y, velocity.z )
It's shoots the wrong direction and very weak. I assume I'm not doing the rotation correctly at the end of the function, and the weakness could be due to not having mass multiplied. The ball's mass it 2, so I assume I should be multiplying some Y values by 2?? Have no idea :(
Here is the C# script I attempted a conversion of:
using UnityEngine;
using System.Collections;
public class ProjectileFire : MonoBehaviour {
[SerializeField]
Transform target;
[SerializeField]
float initialAngle;
void Start () {
var rigid = GetComponent<Rigidbody>();
Vector3 p = target.position;
float gravity = Physics.gravity.magnitude;
// Selected angle in radians
float angle = initialAngle * Mathf.Deg2Rad;
// Positions of this object and the target on the same plane
Vector3 planarTarget = new Vector3(p.x, 0, p.z);
Vector3 planarPostion = new Vector3(transform.position.x, 0, transform.position.z);
// Planar distance between objects
float distance = Vector3.Distance(planarTarget, planarPostion);
// Distance along the y axis between objects
float yOffset = transform.position.y - p.y;
float initialVelocity = (1 / Mathf.Cos(angle)) * Mathf.Sqrt((0.5f * gravity * Mathf.Pow(distance, 2)) / (distance * Mathf.Tan(angle) + yOffset));
Vector3 velocity = new Vector3(0, initialVelocity * Mathf.Sin(angle), initialVelocity * Mathf.Cos(angle));
// Rotate our velocity to match the direction between the two objects
float angleBetweenObjects = Vector3.Angle(Vector3.forward, planarTarget - planarPostion);
Vector3 finalVelocity = Quaternion.AngleAxis(angleBetweenObjects, Vector3.up) * velocity;
// Fire!
rigid.velocity = finalVelocity;
// Alternative way:
// rigid.AddForce(finalVelocity * rigid.mass, ForceMode.Impulse);
}
}
Thanks!
question from:
https://stackoverflow.com/questions/65713249/ammo-js-three-js-calculate-force-vector-needed-to-make-a-basketball-shot