Vector3 Help - Calculating velocity toward a point
I'm building a game with freefall mechanics as an integral part of it, leveraging Unity's physics engine. I'm stumped on how to solve for getting a velocity toward a particular Vector3 point.
As in, if you are free falling exactly toward an object, the speed toward that object is the same as the magnatude. However, if you are freefalling somewhat toward it, but will pass by it, there is only a portion of the velocity vector which applies as the magnitude toward that object, and that portion will diminish to zero as you reach a Y offset = 0. Continuing to fall away from it would have a negative magnitude, but for my purposes i'm only interested in knowing that there is no speed TOWARD the object. Zero, and all negative values are effectively the same as zero.
The use case is that I am trying to AddForce toward a point in space, but only up to a maximum velocity toward that object. AddForce without a restriction around it just keeps accelerating the transform toward that point.
A) I don't want to just set velocity toward it however, because if they are falling past it already, it should be a smooth reduction in falling speed as gravity is countered, a smooth acceleration to a max.
B) I can't just use a maximum speed, as it is normal for the avatar transform to already be in excess of that speed due to gravity, either falling toward it, flying past it, or falling away from it.
I know i'm really close to solving it using the direction/distance vector (transform.position - object.tranform.position. I have a feeling I need to add or subtract the velocity from/to the distance, but none of the combinations are getting the behavior i was expecting.
I could really use a pointer.
Thanks.
Edit:
Answer commentary for anyone else hunting for this same concept: Vector3.Project is certainly what I needed. I spent a few hours trying to wrap my head around how to use it, and what it meant, what vector to project onto what vector, etc...
Eventually what I decided to do is get it visually, and I wrote this script in a blank scene, ui element, FPRigidController, and just let the avatar fall perpetually, resetting position and velocity so i could watch what the numbers do, and what projections mean what. Very enlightening.
The solution ended up being that I need to Vector3.Project(position, velocity), and it gives me the velocity component that is toward the origin. The magnitude of this is absolute speed only, so it doesn't give me direction, however the Vector3.Dot(direction, velocity) does give me a positive number if at all closing with the origin, and a negative number if at all distancing from the origin, which can be converted easily enough. This all gives me what I need. I'm still working to get the results right, but i'm on the right track.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class VectorTest : MonoBehaviour {
public Text uiDebug;
Rigidbody rigid;
LineRenderer line;
Vector3 position = Vector3.zero;
Vector3 velocity = Vector3.zero;
Vector3 direction = Vector3.zero;
float distance = 0f;
Vector3 projectPositionVelocity = Vector3.zero;
Vector3 projectPositionDirection = Vector3.zero;
Vector3 projectVelocityPosition = Vector3.zero;
Vector3 projectVelocityDirection = Vector3.zero;
Vector3 projectDirectionPosition = Vector3.zero;
Vector3 projectDirectionVelocity = Vector3.zero;
// Use this for initialization
void Start () {
rigid = transform.GetComponent<Rigidbody> ();
line = transform.GetComponent<LineRenderer> ();
}
// Update is called once per frame
void Update () {
uiDebug.text = "";
uiDebug.text = string.Concat (uiDebug.text, "position: ", position.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "velocity: ", velocity.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "direction: ", direction.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "distance: ", distance.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "projectPositionVelocity: ", projectPositionVelocity.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "projectPositionDirection: ", projectPositionDirection.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "projectVelocityPosition: ", projectVelocityPosition.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "projectVelocityDirection: ", projectVelocityDirection.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "projectDirectionPosition: ", projectDirectionPosition.ToString (), "\n");
uiDebug.text = string.Concat (uiDebug.text, "projectDirectionVelocity: ", projectDirectionVelocity.ToString (), "\n");
}
void FixedUpdate() {
Recall ();
position = transform.position;
velocity = rigid.velocity;
direction = Vector3.zero - position;
distance = Vector3.Distance (position, Vector3.zero);
projectPositionVelocity = Vector3.Project (position, velocity);
projectPositionDirection = Vector3.Project (position, direction);
projectVelocityPosition = Vector3.Project (velocity, position);
projectVelocityDirection = Vector3.Project (velocity, direction);
projectDirectionPosition = Vector3.Project (direction, position);
projectDirectionVelocity = Vector3.Project (direction, velocity);
line.SetPosition (0, position);
}
void Recall() {
if (position.y < -30) {
transform.position = new Vector3 (10, 30, 10);
rigid.velocity = Vector3.zero;
}
}
}
2nd Edit:
And I got it. A falling (or other velocity) object can be made to begin to loop around a given point, as if by gravity.
rigid = transform.GetComponent<Rigidbody> ();
position = transform.position;
pivot = target.transform.position;
direction = pivot - position;
velocity = rigid.velocity;
movingAway = Vector3.Dot (direction, velocity) < 0;
if (movingAway) {
rigid.velocity = Vector3.ProjectOnPlane (velocity, direction);
}
Note that this does NOT create a perfect circle, especially if normal gravity is enabled, however it does give a very good impression swinging around a pivot point based on your speed, and allows other physics forces to still function.
And for my purposes, if you are moving toward the target at all, you can get the speed toward it, to use as a speed limiter for AddForce:
velocityTowardsPivot = Vector3.Project (position - pivot, velocity);
speedTowardPivot = velocityTowardsPivot.magnitude;
Answer by doublemax · Feb 01, 2017 at 10:48 PM
If i understand you correctly, Vector3.Project should do what you need. Project the velocity vector onto the vector that goes from the falling object towards the target.
https://docs.unity3d.com/550/Documentation/ScriptReference/Vector3.Project.html
That's also what i understand, so i converted your comment into an answer ^^.
Thanks, Project was indeed what I needed. I edited my question above with my solution and how I implemented it, as it may be useful for others hunting for the same type of solution.