How to aim a projectile affected by wind for an Artificial Intelligence in 3D world? - unity3d

I'm trying to make a tank game where the player must destroy the enemy tank piloted by AI. As AI has to be able to attack the player's tank. Both shots are parabolic affected by air. So far I have been able to calculate the power and minimum tilt angle to hit the shot without the projectile is affected by the wind.
var Dx = target.position.x - transform.position.x;
var Dy = target.position.y - transform.position.y;
var P1 = Mathf.Sqrt(9.81f * (Dy + Mathf.Sqrt(Dx * Dx + Dy * Dy)));
var InclinationAngle = Mathf.Atan((Dy + Mathf.Sqrt(Dx * Dx + Dy * Dy)) / Dx) * Mathf.Rad2Deg;
transform.localRotation = Quaternion.Euler(new Vector3(-InclinationAngle,0, 0));
var fz = transform.forward.normalized * P1;
rig.AddForce(fz, ForceMode.Impulse);
The problem is when the projectile is affected by wind. The wind can be in one of four directions, forward, back, right or left. I have tried several approaches, but I have not got a good shot. How can the AI aim considering the starting position, target position and the strength and direction of the wind?

I found a solution:
Once calculated the initial rate and the minimum angle of inclination to make the trip
var Dx = target.position.x - transform.position.x;
var Dy = target.position.y - transform.position.y;
var Vmin = Mathf.Sqrt(9.81f * (Dy + Mathf.Sqrt(Dx * Dx + Dy * Dy)));
var InclinationAngle = Mathf.Atan((Dy + Mathf.Sqrt(Dx * Dx + Dy * Dy)) / Dx) * Mathf.Rad2Deg;
must be added opposite to the wind force by the time of flight of the projectile divided by 2 because wee just need the half of the time because there is where the two forces are equals.
var t = Dx/(Vmin * Mathf.Cos(InclinationAngle*Mathf.Deg2Rad));
var fyx = transform.forward.normalized * P1;
var fxz = wind.force*-t/2;
rig.AddForce((fyx+fxz), ForceMode.Impulse);

Related

Get angle to land ballistic arc on target with fixed velocity projectile

So I was trying to follow the code in this question to get a turret that can fire ballistic projectiles with a fixed starting velocity and no drag to a given point on a 3D surface.
Find an angle to launch the projectile at to reach a specific point
But It's not quite working. The turret ends up aiming too high when the target is close, and too low when the target is further away. There is of course a specific distance at which it does hit the target but that distance is arbitrary, so that's not at all helpful to me.
The way the error scales makes me think I have a multiplication mistake, or am missing some multiplication or division, but I can't for the life of me figure out where I am going wrong. Can anyone point me in the right direction?
Code Below:
float CalculateAngle(float velocity)
{
float gravity = -Physics.gravity.y;
Vector3 modPos = target.position;
if (modPos.x < 0) modPos.x -= 2 * modPos.x;
if (modPos.y < 0) modPos.y -= 2 * modPos.y;
if (modPos.z < 0) modPos.z -= 2 * modPos.z;
modPos.x /= 10;
modPos.y /= 10;
modPos.z /= 10;
float deltaX = modPos.x - FirePoint.position.x;
float deltaZ = modPos.z - FirePoint.position.z;
float deltaY = modPos.y - FirePoint.position.y;
float horzDelta = Mathf.Sqrt(deltaX * deltaX + deltaZ * deltaZ);
float RHSFirstPart = (velocity * velocity) / (gravity * horzDelta);
float RHSSecondPart = Mathf.Sqrt(((velocity * velocity) * ((velocity * velocity) - (2 * gravity * deltaY))/ (gravity * gravity * horzDelta * horzDelta)) - 1);
float tanθ = RHSFirstPart - RHSSecondPart;
float angle = Mathf.Atan2(tanθ, 1) * Mathf.Rad2Deg;
if (angle < 0) return angle;
return -angle;
}
Edit 1:
Still struggling heavily with this. I just can't get the math to work. I went back to the original root of the knowledge here https://physics.stackexchange.com/questions/56265/how-to-get-the-angle-needed-for-a-projectile-to-pass-through-a-given-point-for-t then wrote a function that did the exact equation given in the answers, copying the input values and everything. Except when I run it it fails, as one of the values that needs to be squared is negative which throws a NaN. I assume I am going wrong somewhere in my equation but I've gone over it a hundred times and I am not spotting the error. My code:
float CalculateAngle3(float velocity)
{
float deltaX = 500;
float deltaY = 20;
float v = 100;
float vSqr = v * v;
float g = 9.81f * 9.81f;
float a = vSqr * (vSqr - 2 * g * deltaY);
float b = (g * g) * (deltaX * deltaX);
float c = a / b - 1;
float d = Mathf.Sqrt(c); //c is negitive causing an NaN
float e = vSqr / g * deltaX;
float tanθ = e - d;
return tanθ;
}
Edit 2:
Gave up. This guy solved it so I am just going to use his logic instead
: P
https://www.forrestthewoods.com/blog/solving_ballistic_trajectories/
Using it like such:
Vector3 s0;
Vector3 s1;
if (fts.solve_ballistic_arc(FirePoint.position, bomb.StartingVelocity.z, target.position, -Physics.gravity.y, out s0, out s1) > 0)
{
targetPosition = transform.position + s1;
SafetyEnabled = false;
}
else
{
//Don't fire if we don't have a solution
SafetyEnabled = true;
}
I'm going to leave the question open for now since it's still technically not answered. I still don't know why the original implementation wasn't working.
It is possible your quadratic formula is incorrect (I do not know why you did not code a separate small function that solves the quadratic equation for any three given coefficients, to make your code more readable and less prone to errors)
float RHSFirstPart = velocity / (gravity * horzDelta);
float RHSSecondPart = Mathf.Sqrt(RHSFirstPart*RHSFirstPart - 2*RHSFirstPart*deltaY/horzDelta - 1);
float tanθ = RHSFirstPart - RHSSecondPart;
A comment: In most applications we do not really need the actual angle but the values of cos(angle) and sin(angle) because these are the components of the unit vector which usually is sought (just like in your case). So no need to use inverse trigonometry to find an actual number, which slows down calculations and is may introduce unnecessary round-off errors.

Calculate initial velocity to set to rigid body so it reaches a target position with angle of launch, start position and target position as given

I need to shoot a ball from any height and make it bounce on a target position defined by the user. The angle of launch is also given. I've tried a couple of solutions so far:
Vector3 calcBallisticVelocityVector(Vector3 source, Vector3 target, float angle) {
Vector3 direction = target - source;
float h = direction.y;
direction.y = 0;
float distance = direction.magnitude;
float a = angle * Mathf.Deg2Rad;
direction.y = distance * Mathf.Tan(a);
distance += h/Mathf.Tan(a);
// calculate velocity
float velocity = Mathf.Sqrt(distance * Physics.gravity.magnitude / Mathf.Sin(2*a));
return velocity * direction.normalized;
}
Vector3 calcBallisticVelocityVector2(Vector3 source, Vector3 target, float angle) {
float distance = (target.Planar() - source.Planar()).magnitude;
float a = target.y - source.y - distance;
float halfGravity = -Physics.gravity.magnitude * 0.5f;
float distanceSquared = distance * distance;
float theta = Mathf.Deg2Rad * angle;
float cosSquared = Mathf.Cos(theta) * Mathf.Cos(theta);
float b = distanceSquared / cosSquared;
float speed = Mathf.Sqrt((halfGravity * b) / a);
Vector3 velocity = (target.Planar() - source.Planar()).normalized * Mathf.Cos(theta);
velocity.y = Mathf.Sin(theta);
return velocity * speed;
}
The results I'm getting is that even the ball does go into the direction is expected, it falls earlier than it should be so the speed calculated by these methods seems to be lower than what is actually required to hit the target position.
Rigidbody's mass is set to 1, Gravity is (0, -98, 0), rigid body's drag and angular drag is set to 0. What other variables could be affecting this behavior?
EDIT: One thing I forgot to mention is that I'm setting the resulting vector as rigid body's velocity, so I'm not using via the apply force method.
I adapted code gotten from here: https://answers.unity.com/questions/1131176/projectile-motion.html and now I'm getting the results I was expecting. I can always hit the target position at whatever angle I input.
private Vector3 calcBallisticVelocityVector(Vector3 initialPos, Vector3 finalPos, float angle)
{
var toPos = initialPos - finalPos;
var h = toPos.y;
toPos.y = 0;
var r = toPos.magnitude;
var g = -Physics.gravity.y;
var a = Mathf.Deg2Rad * angle;
var vI = Mathf.Sqrt (((Mathf.Pow (r, 2f) * g)) / (r * Mathf.Sin (2f * a) + 2f * h * Mathf.Pow (Mathf.Cos (a), 2f)));
Vector3 velocity = (finalPos.Planar() - initialPos.Planar()).normalized * Mathf.Cos(a);
velocity.y = Mathf.Sin(a);
return velocity * vI;
}

The first speed calculated ball does not go to the target it should go

In the function below, The distance between ball and target is
known(R). Also, the angle between the resultant vector and the x-axis is
known(LaunchAngle). Thanks to these parameters(R, LaunchAngle), I
calculate the initial velocity of a ball. I checked all the values.
According to physics, they are all correct. Although all calculations
are correct, the ball does not hit the target.
void LaunchFromTargetPositionWithoutFrictionForce()
{
Vector3 projectileXZPos = new Vector3(transform.position.x, 0.0f, transform.position.z);
Vector3 targetXZPos = new Vector3(TargetObjectTF.position.x, 0.0f, TargetObjectTF.position.z);
transform.LookAt(targetXZPos);
float R = Vector3.Distance(projectileXZPos, targetXZPos);
float G = -Physics.gravity.y;
float Vz = Mathf.Sqrt(G * R / Mathf.Sin((2.0f * LaunchAngle) * Mathf.Deg2Rad));
float Vy = Vz * Mathf.Sin(LaunchAngle * Mathf.Deg2Rad);
float Vx = Vz * Mathf.Cos(LaunchAngle * Mathf.Deg2Rad);
text2.text = "vz: " + Vz.ToString() + " vy: " + Vy.ToString() + " vx: " + Vx.ToString();
Vector3 localVelocity = new Vector3(0f, Vy, Vx);
Vector3 globalVelocity = transform.TransformDirection(localVelocity);
rigid.velocity = globalVelocity;
bTargetReady = true;
if (isSlowMotion) timeManager.slowMotion();
}
First location of the ball
And after 2-dimensional motion it is hit before target
I changed first 3 line with below codes. And problem solved.
Vector3 projectileXZPos = transform.position;
Vector3 targetXZPos = TargetObjectTF.position;
float dist = Vector3.Distance(projectileXZPos, targetXZPos);
transform.LookAt(targetXZPos);

Trajectory Prediction in Sprite Kit

I'm trying to predict where an object (ball) will move using the following formula
Calculations for t = 1 second
y = VelocityY * t + 0.5*Gravity*t2
x = VelocityX * t
code below:
+(CGVector) getTrajectoryPointWithInitialPosition:(CGVector) initialPosition andInitialVelocity:(CGVector) initialVelocity andSteps: (CGFloat)n andSceneLayer: (SKScene*) sceneLayer
{
// Put data into correct units
CGFloat t = 1.0 / 60.0;
// m/s
CGVector stepVelocity = CGVectorMake(t * initialVelocity.dx, t * initialVelocity.dy);
// m/s^2
CGVector stepGravity = CGVectorMake(t * t * sceneLayer.physicsWorld.gravity.dx, t * t * sceneLayer.physicsWorld.gravity.dy);
initialPosition = CGVectorMake(initialPosition.dx + n * stepVelocity.dx,
initialPosition.dy + n * stepVelocity.dy + 0.5 * (n*n+n) * stepGravity.dy);
return CGVectorMake(initialPosition.dx + n * stepVelocity.dx,
initialPosition.dy + n * stepVelocity.dy + 0.5 * (n*n) * stepGravity.dy);
}
I then launch the ball (stationary/non-dynamic) using the following
CGVector aVelocity = CGVectorMake(initialVelocity.dx*17.5, initialVelocity.dy*17.5);
[ball.physicsBody setVelocity:aVelocity];
What I can't figure out is:
initialVelocity for the ball and the trajectory prediction is the same. If it's the same, why does multiplying initialVelocity for the ball by 17.5 gets the ball movement and the predicted trajectory obtained from above to match up. It looks like it's following the predicted path but I don't understand why multiplying the balls velocity by 17.5 makes the ball
![Before multiplying by 17.5] http://i.imgur.com/bKkPGmh.png - Before multiplying by 17.5
![After multiplying velocity by 17.5] http://i.imgur.com/Ae7sY4i.png - After multiplying by 17.5

Projectile motion for box 2d body

How to implement the projectile motion for a box2d body in cocs2dx....
newX = b4->GetPosition().x + cos(60.0);
newY = b4->GetPosition().y + sin(60.0);
is this a right way?
You can do like that initial Velocity of object, angle, gravity= 9.81 and time should be start from zero.
while(count < 10)
{
// this is formula for trajectory
// http://en.wikipedia.org/wiki/Projectile_motion
x = initialVelocity * time * Math.Cos(angle);
y = initialVelocity * time * Math.Sin(angle) - 0.5f * gravity * time * time;
count++;
time += 0.1f;
}