- Home /
Trying to create a '2D 8 Ball Pool' game - Trajectory Prediction
I am trying to create a game similar to (Pocket Run Pool) https://www.youtube.com/watch?v=ewlAE6NQnsI&t=215s a 2D pool game that is much simpler than a 3D one I need help with creating code for trajectory prediction something similar to this https://docs.unity3d.com/Manual/physics-multi-scene.html
How do I go about doing this?
you need to use trigonometry and line renderer. Will have to do some research.
I reccomend using an alternate physics scene. Its simpler than using math and can give you much more accurate results.
This link should get you started. https://youtu.be/4VUmhuhkELk
Answer by jackmw94 · Jan 26, 2021 at 12:47 PM
To find the ball/wall that you're going to hit, use the "CircleCast" method in Physics2D. Make sure the radius is the same as your white ball. For this to work, all your balls and cushion sides should have colliders on.
This will give you your collision point. The raycast hit that this returns will have a "normal" vector - this is the vector stating the direction perpendicular to the collider edge at the point where you hit it. So in your image, you can visualise the normal if you draw an arrow from the centre of the 8-ball to the centre of the dashed ball, this will point straight out from the 8-ball surface at the point where the collision occurs.
This normal will be the opposite to the direction in which you'll move the ball you just hit, i.e. -normal will be the white arrow you circled, coming out the 8-ball.
You can find the next trajectory of the white ball by reflecting your initial white ball movement across this normal.
Vector2 bouncedWhiteBallDirection = Vector2.Reflect(initialWhiteBallDirection, hit.normal);
When writing behaviour with vectors, I strongly recommend using gizmos to show you the directions and positions you're using visually in the scene view. In your monobehaviours you can implement the function OnDrawGizmos then inside that you have access to all the Gizmos methods. For example:
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawLine(whiteBallTransform.position, whiteBallTransform.position + initialWhiteBallDirection);
}
This would draw a red line in the direction of "initialWhiteBallDirection" out from the white ball position.
Let me know if you have any questions about this!
Will the white arrow (circled in red) change it's angle as the direction of the cue is changed?
That’s the idea :) The circle cast will either detect a ball and then you can check the collision normal to find this angle or it will hit a wall in which case there’s no other ball to move, just the next cue ball direction. The white arrow changes as the collision point changes
Problems: 1.radius of the circle and white ball not matching values being used in inspector = 0.52 (also represents DrawSphere radius) 2. How can I change the length of the normal dynamically as shown in the gameplay video?
Solution so far (Image Attached) Code:
public class PhysicsTest : $$anonymous$$onoBehaviour
{
GameObject currentHitObject;
float maxDistance = float.PositiveInfinity;
public float radius;
public Layer$$anonymous$$ask layer$$anonymous$$ask;
private Vector3 origin, direction;
private Vector2 hitdistance;
private float currentHitDistance;
private void Update()
{
origin = transform.position;
direction = transform.up;
RaycastHit2D hit = Physics2D.CircleCast(origin, radius, direction, float.PositiveInfinity, layer$$anonymous$$ask, float.NegativeInfinity, float.PositiveInfinity);
if(hit)
{
currentHitObject = hit.transform.gameObject;
currentHitDistance = hit.distance;
hitdistance = hit.normal * -1;
}
else
{
currentHitObject = null;
currentHitDistance = maxDistance;
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Debug.DrawLine(origin, origin + direction * currentHitDistance);
Debug.DrawLine(currentHitObject.transform.position, hitdistance * 5);
Gizmos.DrawSphere(origin + direction * currentHitDistance, radius);
}
}
I'm not too sure what you mean with your first point - where did you find the 0.52 value? :)
Your second point is an interesting one:
What we want here is to scale the line in accordance with how "in line" the initial cue ball direction and the inverse of the normal are - this can be found using the dot product of the two. Here is the dot product in action: https://miro.medium.com/max/984/1*GiXSS_fhvPLsKI50ofdrnA.gif
It's a scalar value, so only a single number, unlike the vectors we use to create it. It's the magnitude of the vector created by the projection of one vector onto another.
float normalScale = Vector2.Dot( direction.normalized, -hit.normal );
This code will find you the dot product for your initial direction and the hit ball's direction. You can then use this to scale your hitDistance.
I am facing weird behaviour -> https://gph.is/g/Z8oOXbb any reason this is happening? am adding force in -> direction = transform.up;
if(hit)
{
currentHitObject = hit.transform.gameObject;
currentHitDistance = hit.distance;
hitdistance = hit.normal * -1;
GetComponent<Rigidbody2D>().AddForce(0.1f * direction, Force$$anonymous$$ode2D.Impulse);
}