- Home /
[MATH] Vectors, magnitudes, and bears; Oh My! -Solved
Project
Im doing a little space ship project that is a 2.5D game and the space ship stays on the flat plane. IE: it only travels in the X and Z axis.
And I am looking to find a Mathematical Function for this problem:
Part 1:
Okay, so now that you know that. When the player chooses to orbit around a planet or sun, this particular code will run. As you can see; it simply clears a couple of variables and it creates an imaginary circle, a radius that I will use to help with the ship's orbitting distance. Obviously I would orbit a small ship alot closer than if the object I was orbitting was a SUN or PLANET.
if (systemStatus == 2) // [ -----------------------[ORBIT]----------------------------------------------------------------------
{
tempDirection = new Vector3(0f,0f,0f);
distanceToTarget = 0f;
//we need to RETURN the orbiting targetDirection <-- A Vector3
// IF TAG = "ENVIRONMENT", = SPHERE COLLIDER
// IF TAG = PLAYER OR ENEMY OR DRONE = MESH COLLIDER
if (myTarget.tag == ("Environment"))
{
myTargetsRadius = myTarget.GetComponent <SphereCollider> ().radius;
}
Part 2:
Now we calculate the distance ( in float ) between the ship & that radius we just obtained.
////////////// NOW WE CALCULATE THE DISTANCE ///////////////////////
//xd = x2-x1
//yd = y2-y1
//zd = z2-z1
//Distance = SquareRoot(xd*xd + yd*yd + zd*zd)
float calcX = (this.transform.position.x - myTarget.transform.position.x) - myTargetsRadius;
float calcY = (this.transform.position.y - myTarget.transform.position.y) - myTargetsRadius;
float calcZ = (this.transform.position.z - myTarget.transform.position.z) - myTargetsRadius;
distanceToTarget = Mathf.Sqrt (calcX*calcX + calcY*calcY + calcZ*calcZ);
Part 3:
If we are not our underneath our optimal range, then we need to increase our distance until we go to it. However, if we are above our optimal range, then we need to decrease our distance.
if (distanceToTarget < optimalRange)
{
//tempDirection = AwayFromTarget
tempDirection = this.transform.position - myTarget.transform.position;
}
if (distanceToTarget > optimalRange)
{
//tempdirection = TowardsTarget
tempDirection = myTarget.transform.position - this.transform.position;
}
Then: Add this Vector to our tangentVector which is a vector perpendicular to the the radius of a point in space... of our (planet,sun,whatever)
if (orbitDirection == 1) //clockwise
{
// *** WARNING *** Unity uses the LEFT HAND RULE: http://docs.unity3d.com/ScriptReference/Vector3.Cross.html
Vector3 a = myTarget.transform.position - this.transform.position;
Vector3 b = this.transform.up;
Vector3 c = Vector3.Cross (a,b);
float tempStrength;
float cStrength;
tempStrength = Mathf.Abs (optimalRange - distanceToTarget);
float ratio = 100/ (optimalRange - lowerEndRange); // so here is how we got that ratio multiplyer number... By basically putting it in an aspect in terms of percentage. /100
tempStrength = tempStrength * ratio; // .4166 ONLY if the upper end is 20% of 400 and lower end is 20% of 400, how did we get this number though...Explained one line up..
cStrength = 100 - tempStrength;
tempDirection = tempDirection.normalized;
tempDirection = tempDirection * tempStrength;
c = c.normalized;
c = c * cStrength;
tempDirection = tempDirection + c;
}
THE PROBLEM, That I do not understand is:
When I get this final tempDirection at the end and I send it back to my Ships Navigation computer to head towards it.... IT DOES NOT take into account the magnitudes of the two vectors. Or it does not appear to do this.
What I want to see happen is: As the ship begins to approach it's optimalrange. It is being affected by two vectors:
--(example1)The vector pointing (towards) or (awayFrom) the target.
--(example2)The vector that is a perfect perpendicular tangent to the sun/planet.
I want the vector in example1 to get weaker as we get closer to the optimalrange. And as a direct-inverse-result the example2 vector should get stronger (because i set it that way in part3). I DID prove that my math is correct for finding the strength values for these 2 vectors. But I do not know the mathematical function I need to apply to them.
Whenever I run this code and return this Vector3 back to my shipsNavigationComputer, it's always dead in the middle between the 2 Vectors. It is not scewed by the weight of their magnitude:
tempDirection = tempDirection + c;
So what Mathematical Function am I needing to perform?
--It seems that adding vectors won't do it -- I have thought about DotProduct, but I have no Idea how to apply that to my configuration -- something Im missing?
Try to Debug.Log the tempStrength and cStrength, and see how they evolve as you move the ship closer and further from the point of orbit.
I recently did something very similar to this (wolves circling some prey, but the maths should be similar), and I can post how I did that as an answer if you're interested. It's a completely different idea, though - it's based on rotating the vector from the point of orbit to the orbiter around the point of orbit, and then simply following that.
It would be more beneficial if you provided me with the mathematical logic, or at a $$anonymous$$imum the name of the mathematical function I need to use. I don't $$anonymous$$d doing the work, I would rather understand this stuff.
To second Baste, this sort of thing always comes down to some number you think you should get, and what you're really getting, are different; or realizing your math was just wrong.
If you have to, make tiny red, green, blue balls/lines and position them to represent each thing you're computing. Hand-compute #'s for one case. Then, in code, snap the object there and print those numbers.
At the very least, you'll get down to a command not doing what you think it should, and being able to ask about that one thing.
Thanks to both, I did as both of you suggested and changed around some of the variables so they stay separated. And the (firstVector) in part3, does correctly point awayfrom OR towards the target... and the (secondvector) does correctly point in the LEFT-HAND RUL$$anonymous$$...
but, the resulting addition vector seems to be erratic. I will continue to research.
But since you both decided to reply to a $$anonymous$$ATH question; I would assume you may know what your talking about. Does a resulting addition between two Vector3s keep in $$anonymous$$d the $$anonymous$$agnitude? Furthermore, would that result vector be scewed/ or weighted by the magnitude of the other vector in this addition scenario?
"addition between two Vector3s keep in $$anonymous$$d the $$anonymous$$agnitude"?
No. It's simple pairwise addition. (0,0,1) + (0,1,1) is (0,1,2). $$anonymous$$athematically, it's simply starting the 2nd vector at the tip of the first. The result is purposely not normalized (but you can do it yourself, if needed.)
Answer by tanoshimi · Feb 07, 2015 at 07:32 AM
Haven't studied in detail, but at first glance this looks wrong to me:
float calcX = (this.transform.position.x - myTarget.transform.position.x) - myTargetsRadius;
float calcY = (this.transform.position.y - myTarget.transform.position.y) - myTargetsRadius;
float calcZ = (this.transform.position.z - myTarget.transform.position.z) - myTargetsRadius;
distanceToTarget = Mathf.Sqrt (calcX*calcX + calcY*calcY + calcZ*calcZ);
Did you not mean:
Vector3 calc = (this.transform.position - myTarget.transform.position).normalized * myTargetsRadius;
distanceToTarget = Vector3.Distance(this.transform.position, calc);
? But agree with the other commenters - use Debug.Log and OnDrawGizmos to test what values your code is producing/plot them visually in the scene view.
Thank you for the time to reply. These mathematical problems scare alot of helpers away :)
I actually went through and reviewed my formuation. The solution you provide will return a DIRECTION with $$anonymous$$agnitude between 2 points. I actually want to find only a FLOAT distance. According to this website: $$anonymous$$ATH IS FUN
To obtain the difference between two points in 3d space (Vector3s):
//xd = x2-x1
//yd = y2-y1
//zd = z2-z1
//Distance = SquareRoot(xd*xd + yd*yd + zd*zd)
I simply add in a radius prior to the calculation so that it weighted with the radius. In other words; because my planets and sun already have a collider on them with a "radius"... I just take that radius amount = 0.5 and I weight this distance with that.
Thanks for taking a look, let me know if I missed something else.
EDIT: Actually upon closer inspection of your code. I realized that Unity already has a distance function between two 3D points in space. But, I think you meant this in your code, right?:
Vector3 targetPos = myTarget.transform.position;
Vector3 result = Vector3.Distance(this.transform.position, targetPos);
No, I'm assu$$anonymous$$g that you wanted to calculate the distance from your current point to your ideal orbit position, not to the centre of the planet.
Answer by karma0413 · Feb 07, 2015 at 02:45 PM
The Solution:
While I was testing the variables, I was working in the wrong section of code. This helped contribute to the problem because I was always in a case where I wouldn't see the changes. /BONK
Additionally, the other folks replying to my problem were in fact correct about the Debug.DrawRay. While, I thought I had enough drawRays on the screen; I actually was not showing the resulting drawRay each time I did a calculation and therefore was not completely understanding the processes taking place.
My calculations were in fact correct, and I haven't changed them. Well except for one minor problem. When I originally did the COUNTER-CLOCKWISE script. I did the inverse calculation of the result after all the changes. More correctly, when I do counter-clockwise I simply needed the INVERSE of the (LeftHand Rule) resulting vector. Now the mathematical inverse is done in the right location.
And to finally answer my own original question:YES,: When you do an addition between two different Vector3 directions. Their magnitudes will automatically weight it's direction. So we can see here in the updated code I provide now:
We can see to obtain, the left-hand rule calculation ( this is called Cross Product multiplication ) we do the following:
if (orbitDirection == 1) // NORMAL CLOCK-WISE
{
// *** WARNING *** Unity uses the LEFT HAND RULE: http://docs.unity3d.com/ScriptReference/Vector3.Cross.html
Vector3 a = myTarget.transform.position - this.transform.position;
Vector3 b = this.transform.up;
Vector3 c = Vector3.Cross (a,b);
vectorTwo = c;
We already had VectorOne - which was simply go ( towards) or ( awayfrom ) depending if we were shallow of the orbiting optimal range, or if we had exceeded. And now we just found vectorTwo above.
The next thing to do was to define the strengths of each of these Vectors. For example if my optimal orbitting range is 400meters. Then I stated that if the ship was within 80% of that, then lets use this smoothed-navigation-guidance code as below:
float upperEndRange = optimalRange + (optimalRange * 0.80f);
float lowerEndRange = optimalRange - (optimalRange * 0.80f);
And Now we just simply find out the strengths. And to find out how much strength each vector gets; we define it in terms of 100% of how close or far we are from our optimal range. A float number that is between 0-100. [EDIT NOTE:] I could have simply divided the final result by/100 to get a number between 0-1.0. But I found it wasn't needed when computing the final destination direction.
tempStrength : is how much strength to go (towards) or (awayfrom) the target we are orbitting. Obviously is we are closer to the 80% limit on this. then tempStrength will be very near 100
cStrength : is the strength of the tangent Vector that is perpendicular to the object we are orbitting. And as a DIRECT-INVERSE-RELATIONSHIP ; whatever % of 100% is left from tempstrength. we can give it to cStrength. So the closer we are to our optimal range ; then the more cStrength = 100, and our tempStrength becomes close to 0.0
tempStrength = Mathf.Abs (optimalRange - distanceToTarget);
float ratio = 100/ (optimalRange - lowerEndRange); // so here is how we got that ratio multiplyer number... By basically putting it in an aspect in terms of percentage. /100
tempStrength = tempStrength * ratio; // .4166 ONLY if the upper end is 20% of 400 and lower end is 20% of 400, how did we get this number though...Explained one line up..
cStrength = 100 - tempStrength;
//vectorOne = vectorOne.normalized;
vectorOne = vectorOne * tempStrength;
//vectorTwo = vectorTwo.normalized;
vectorTwo = vectorTwo * cStrength;
tempDirection = vectorOne + vectorTwo;
Very Lastly: To find the COUNTER-CLOSEWISE... As I mentioned we just plug in the Inverse of Vector C; which was (looking back), the RESULT of a CrossProduct between Vector a and Vector b. So Now instead of facing LEFT-HAND... we actually turn right and go counter-clockwise (IF WE ARE FACING THE OBJECT)
if (orbitDirection == -1) //ACTUALLY COUNTER-CLOCKWISE
{
Vector3 a = myTarget.transform.position - this.transform.position;
Vector3 b = this.transform.up;
Vector3 c = Vector3.Cross (a,b);
vectorTwo = -c;
float tempStrength;
float cStrength;
tempStrength = Mathf.Abs (optimalRange - distanceToTarget);
float ratio = 100/ (optimalRange - lowerEndRange); // so here is how we got that ratio multiplyer number... By basically putting it in an aspect in terms of percentage. /100
tempStrength = tempStrength * ratio; // .4166 ONLY if the upper end is 20% of 400 and lower end is 20% of 400, how did we get this number though...Explained one line up..
cStrength = 100 - tempStrength;
//vectorOne = vectorOne.normalized;
vectorOne = vectorOne * tempStrength;
//vectorTwo = vectorTwo.normalized;
vectorTwo = vectorTwo * cStrength;
tempDirection = vectorOne + vectorTwo;
//tempDirection = tempDirection;
}
Oooh, it's fancy, huh?
I figured you all might appreciate a screenshot of the result:
Do: Control+MouseWheel to zoom into all of its fine glory!
Your answer
Follow this Question
Related Questions
Check if position is inside area? 2 Answers
Vector Math Question 2 Answers
How to get up vector of rotation? 1 Answer
More simple vector math... 2 Answers
Math Optimization: Normalize 2 Answers