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

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.

Related

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;
}

My object is moving too fast in Unity?

I am suppose to implement a CatMull Rom Spline, and I have it implemented, but the sphere moves to the points extremely fast. I thought if I used Time.DeltaTime it would slow it down, but it moves too rapidly.
Function to compute point on curve:
Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
// TODO - compute and return a point as a Vector3
// Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
// Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
// etc...
Vector3 point = new Vector3();
float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
float c3 = ((u - 1f) * u * u) * 0.5f;
Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];
point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);
return point;
}
**Update Function: **
void Update ()
{
// TODO - use time to determine values for u and segment_number in this function call
// 0.5 Can be used as u
time += DT;
segCounter++;
Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
transform.position = temp;
}
Variables:
const int NumberOfPoints = 8;
Vector3[] controlPoints;
const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;
const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;
float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;
EDIT: Sorry the calculations, and all of that is correct. It's straight from the slides, I just need help with the update function :(
Using Time.deltaTime allows you to be framerate independent. This means that if the framerate drops, or a frame takes longer than the others, your object will adapt the moving distance to keep a constant speed. This is generally a good idea.
Back to your case: Basically you want to pass a position to your function. You currently pass the time. If your catmull rom considers that 0 is the start and 1 is the destination, then after exactly 1 second, you will be at the end of the spline. (Note that this is where being framerate independent is interesting: Whatever the frame rate is. you reach the end in one second). Now, how to convert from time to position. Easy
position = time*speed;
Since time is in second, speed is in units per seconds. Say your catmullrom is one unit long. If speed is two, if will take one second to travel it twice. so half a second to travel it. Since you want to lower the speed, you might want to use values below 1. Try this:
void Update ()
{
time += Time.deltaTime;
var speed = 0.1f;
var splinePos = speed * time;
segCounter++;
Vector3 temp = ComputePointOnCatmullRomCurve(splinePos, segCounter);
transform.position = temp;
}

[Unity]How to draw a Ring Line in 3D

I'd like to draw the trajectory of an object that is moving circularly, but I do not know how to do it.
Could you tell me a good way?
I've not done a orbiting around something, but I am using Cos and Sin to generate static items around the object.
If you use TrailRenderer with the use of MathF cos and sin to rotate around an object.
var y = amplitude * MathF.cos(Time.timeSinceLevelLoaded * speed) + currentPosY
var x = amplitude * MathF.sin(Time.timeSinceLevelLoaded * speed) + currentPosX
I've not watched it, but "Board to bits" on youtube has a tutorial on the matter. of space orbiting for a planet playlist.
Hope this is the right direction for you.
Thank you for a lot of response.
I found it works with below...
void drawLine()
{
Vector3[] points = new Vector3[segments+1];
for (int i = 0; i< segments; i++)
{
float angle = ((float)i / (float)segments) * 360 * Mathf.Deg2Rad;
float x = Mathf.Sin(angle) * radius;
float z = Mathf.Cos(angle) * radius;
points[i] = new Vector3(x, 0f, z);
}
points[segments] = points[0];
lr.positionCount = segments + 1;
lr.SetPositions(points);
}

Unity3d Nontraditional snake game collision with rigid bodies

I am working on a twist to the classic nokia snake game with Unity3D. We decided we wanted to try and redo the way our snake works.
Videos here show a demo of what I have so far, with the new control setup
http://dl.dropbox.com/u/4306843/Unity%202012-10-08%2010-11-05-44.avi
http://dl.dropbox.com/u/4306843/Unity%202012-10-08%2017-51-40-42.avi
I am basically looking for a way to get this affect but collide with rigid bodies and self(or maybe just head).
code is based on info here.
http://processing.org/learning/topics/follow3.html
Any help or suggestions on how to get the snake to not penetrate through rigid bodies would be very much appreciated!
the bulk of the work is done here, Its called for each object in the chain.
void dragSegment(int i, float xin, float yin)
{
float dx = xin - x[i];
float dy = yin - y[i];
float angle1 = Mathf.Atan2(dy, dx);
x[i] = xin - Mathf.Cos(angle1)*segLength;
y[i] = yin - Mathf.Sin(angle1)*segLength;
//set object pos
obj[i].GetComponent<Rigidbody>().MovePosition(new Vector3(x[i],y[i],0));
}
Solution was actually really simple. I needed to get vector between dragobject and collider, normalize the vector and add it back to the x and y positions to get updated like normal.
Here is a the updated code,
void DragSegment(int i, float xin, float yin)
{
if (obj[i].Hit)
{
Vector2 objV = new Vector2(x[i] - obj[i].Obj.GetComponent<Body ().hitObjectPos.x, y[i] - obj[i].Obj.GetComponent<Body>().hitObjectPos.y);
objV = objV.normalized;
x[i] += objV.x*1.2f;
y[i] += objV.y*1.2f;
}
//Getting difference with last objects position
float dx = xin - x[i];
float dy = yin - y[i];
angle1 = Mathf.Atan2(dy, dx);
x[i] = xin - (Mathf.Cos(angle1) * segLength);
y[i] = yin - (Mathf.Sin(angle1) * segLength);
//simple gravity effect
if (gravity == 1) y[i] += 0.1f;
obj[i].Obj.transform.position = (new Vector3(x[i], y[i], 0));
}

reaching particular co-ordinate in projectile motion?

As I wanted to animate an image in projectile motion,
My code is as follows, but it did not reach the target and give projectile animation, any help please?
-(void)timeLine
{
dTime += 0.1;
.................
double s_x = inVel * cos(angle1) ; // the X speed
double s_y = inVel * sin(angle1) ; // the Y speed
NSLog(#"sx = %i",s_x);
NSLog(#"sy = %i",s_y);
x = oX + (s_x * dTime);
y = oY + ( ( s_y * dTime) - (0.5 * 9.8 * dTime * dTime));
NSLog(#"x = %i",x);
NSLog(#"y = %i",y);
imageViewForAnimation.x += x;
imageViewForAnimation.y -= y;
}
imageViewForAnimation.x += x;
imageViewForAnimation.y -= y;
These lines don't seem right to me. You are calculating the actual x and y each time, not the difference moved since the last time. I'm also uncertain why one was being added and one was being subtracted, but that's beside the point. Basically, try changing the lines to
imageViewForAnimation.x = x;
imageViewForAnimation.y = y;
Also, you're doing some calculations over and over which only need to be done once. v_x == s_x (or it should within floating point error) as well as v_y == s_y. You only need to calculate v_x and V_y once beforehand rather than calculating them every time you update the coordinates.