Unity quaternion lookrotation behaving oddly - unity3d

I am using unity to create an airline game. I made the takeoff code as the following:
`
Rigidbody m_Rigidbody;
float thrust_x = 2;
float thrust_y = 0;
float timeRemaining = 1.5f;
// Start is called before the first frame update
void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
}
void TakeOff()
{
m_Rigidbody.AddForce(thrust_x, thrust_y, 0, ForceMode.Impulse);
transform.rotation = Quaternion.LookRotation(new Vector3(thrust_x, thrust_y, 0));
if (timeRemaining > 0)
{
timeRemaining -= Time.deltaTime;
}
else if (timeRemaining < 0 && thrust_y < 1.5)
{
thrust_y += 0.1f;
}
}
`
The timeRemaining waits for 1.5 seconds and then add to the thrust_y. The lookrotation makes the plane point in the direction of the impulse vector. This works impeccably with the plane as a cube. When I replaced it for a model, the plane strangely adds 90deg to the y rotation for no apparent reason.
Before running:
While running:
How can I make the plane once again point to 0,0. Turning the plane 90 and -90 at the start does not work, which gives reason that the value is being set, not changed.
Any help will be greatly appreciated. Thanks!

Related

Smooth Angle Turning in Unity

So I was looking for ways to do smooth angle motion in Unity and I stumbled upon this clip of code:
IEnumerator SlideToPosition(Vector3 targetPos, float time)
{
// Use an animation curve to make it look sweet!
AnimationCurve smoothly = AnimationCurve.EaseInOut(0, 0, 1, 1);
Transform myTrans = transform; // cache the transform for extra efficiency!
float curTime = 0;
Vector3 startPosition = myTrans.position;
moving = true;
while (curTime < time)
{
myTrans.position = Vector3.Lerp(startPosition, targetPos, smoothly.Evaluate(curTime / time));
curTime += Time.deltaTime;
yield return null;
}
moving = false;
myTrans.position = targetPos;
}
This worked absolutely fantastically and I was looking for a way to do angled motion the same way as the poster of the original method (from 6 years ago) said it would be easy to do angular movement in the same way. I've tried everything and for the life of me can't seem to get it to rotate more than a degree or so. Can anyone help me out? Here is where I'm currently at:
IEnumerator rotateToPosition(Vector3 targetAngle, float time)
{
// Use an animation curve to make it look sweet!
AnimationCurve smoothly = AnimationCurve.EaseInOut(0, 0, 1, 1);
Transform myTrans = transform; // cache the transform for extra efficiency!
float curTime = 0;
Quaternion startAngle = myTrans.rotation;
moving = true;
while (curTime < time)
{
myTrans.rotation = Quaternion.Lerp(startAngle, Quaternion.Euler(targetAngle), smoothly.Evaluate(curTime / time));
curTime += Time.deltaTime;
yield return null;
}
moving = false;
myTrans.rotation = Quaternion.Euler(targetAngle);
}
Any help would be greatly appreciated. Thanks!
The last parameter of Lerp is the time component - this is a float value between 0 and 1 which you can think of as the percentage of movement between the start and finish. i.e. a value of 0.5f would be exactly half way between (in your example) startAngle and targetAngle.
So, just do curTimefor the last parameter, as you add to it each frame with curTime += Time.deltaTime this gradually moves between 0 and 1. If you want to vary the speed of the lerp then multiply this value e.g. to make it 50% faster use curTime += Time.deltaTime * 1.5f.

Unity | Get backward vector and play turn anim

Struggling with the implementation of character rotation animation by 180 degrees.
For clarity, I made a Pivot, which indicates the target of the direction, then compares the angle between the direction of the character and the direction of the target, calculates the difference in the nearest angles and, if the difference is greater than 179, plays the Turn180 animation.
Works, but crooked.
Screenshot
Problem:
Since the control of the character and the target are identical, the script does not have time to calculate the difference and gives out values at full turn are not always needed. Like: (-178.6661), (169.8465), (168.1936) and so on.
I'm sure there is an easier way. The only thing that comes to mind is to compare the TargetPisition with the -transform.forward and then play the reversal animation. But I can't figure out how to do it. I need help with Movement and Target.
UPDATE
I rewrote the code from scratch more carefully, but the issue with the turn remains relevant. The target and the Player are turning at the same time, how do I tell the program that I'm going to turn in the opposite direction and play the animation?
void Movement() {
// WASD
float Horizontal = Input.GetAxis("Horizontal");
float Vertical = Input.GetAxis("Vertical");
Vector3 move = Quaternion.Euler (0, playerCamera.transform.eulerAngles.y, 0) * new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
//Movement
controller.Move(move * Time.deltaTime * playerSpeed);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
//
//Pivot
Pivot.transform.position = gameObject.transform.position;
PivotDirection.transform.rotation = gameObject.transform.rotation;
PivotTarget.transform.position = gameObject.transform.position + move;
Vector3 PivotTargetDirection = Vector3.RotateTowards(PivotTarget.transform.forward, move, 10, 0);
PivotTarget.transform.rotation = Quaternion.LookRotation (PivotTargetDirection);
PivotArrow.transform.rotation = Quaternion.Euler (0, playerCamera.transform.eulerAngles.y, 0);
//
// ReceivedAngle
var PlayerDirection = new Vector3(0, transform.eulerAngles.y, 0);
var TargetDirection = new Vector3(0, PivotTarget.transform.eulerAngles.y, 0);
var ReceivedAngle = Mathf.DeltaAngle(PlayerDirection.y, TargetDirection.y);
print(Mathf.RoundToInt(ReceivedAngle));
//
if (ReceivedAngle >= 180)
{
animator.Play("Turn 180");
}
}
P.S. Sorry for my English.

How to prevent upward rigidbody velocity?

I have a group of objects that I allow my player to toss around the scene in zero gravity. However I want to create type of invisible bounds after a certain height. So far when the object reaches a certain upward bounds, I have been doing this in my FixedUpdate...
GetComponent<Rigidbody>().velocity = GetComponent<Rigidbody>().velocity - Vector3.Project(GetComponent<Rigidbody>().velocity, transform.up);
...which works in a sense, but because it is using transform.up, it is removing velocity from both upwards and downwards movement, and I need to restrict it to just upwards movement. Is this possible?
Maybe you can check the y component of the velocity and if it's positive (upwards) set it to 0? If it's negative (downwards) just keep it.
PS. I think you should get a variable referencing the rigidbody component to minimize the GetComponent calls.
Vector3 v = rb.velocity; //get the velocity
v.y = v.y > 0 ? 0 : v.y; //set to 0 if positive
rb.velocity = v; //apply the velocity
You could just check if position hits the threshold and if object is currently moving upwards
[SerializeField] private Rigidbody rb;
[SerializeField] private float maxY;
private void Awake()
{
if(!rb) rb = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
var velocity = rb.velocity;
if(rb.position.y >= maxY && velocity.y > 0)
{
velocity.y = 0;
rb.velocity = velocity;
}
}

Unity - following finger only works for one direction

I have made some code that should make my player move into the direction of the finger:
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.GetTouch(0).position.x, Input.GetTouch(0).position.y, 0));
if (pos.x < rb.position.x)
{
movehorizontal = -1;
}
if(pos.x > rb.position.x)
{
movehorizontal = 1;
}
if (pos.y < rb.position.z)
{
movevertical = -1;
}
if(pos.y > rb.position.z)
{
movevertical = 1;
}
}
Vector3 movement = new Vector3(movehorizontal, 0.00f, movevertical)*speed;
It's a 3D game, with a top-view, so my player starts at 0,0,0 and only moves along the x and z axis. My camera is positionated on 0,10,3. The following works on the x axis, so when my finger touches on the right side it goes to the right, if on the left to the left, but no matter where I touch it, it will only move to the front and not to the bottom of my screen.
I tried debugging, but the instructions werent working at the time.
screentoWorldPoint should be stored as a vector3. also since the camera is 10 units away from your plane the last parameter should be 10.
edit, that will only work for a cam pointing straight down. this code should work regardless of the camera angle.
Vector3 pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.GetTouch(0).position.x, Input.GetTouch(0).position.y, 1f));
Vector3 pointDelta = pos - Camera.main.transform.position;
float multiplier = -Camera.main.transform.position.y / pointDelta.y;
pos = Camera.main.transform.position + pointDelta * multiplier;
finally these lines should compare the z values to each other
if (pos.z < rb.position.z)
if(pos.z > rb.position.z)
make those changes and let us know if any other problems still exist

unity3d rotate back forth with limited angles

I'm want to rotate an object on an axis for specific angles over period of time.
And repeat that on the reverse direction once it reached the limit (of let's say 5 degree).
I could use Quaternion.Euler() to do the rotation towards 5 degree, but how do I check whether it has reached 5 degree and start reversing the direction towards -5 degree?
so in Update() I do:
int dir = 1; // somewhere global
Quaternion r = Quaternion.Euler(0, Timer.deltaTime * dir, 0);
transform.rotation *= r;
// I want to: if the "angle is >= 5f", i want to do dir *= -1 to reverse it
if (/* angle delta is >= 5f or <= -5f */)
{
dir *= -1;
}
Thanks
If you just want to rotate back and forth, you can use a sine wave to move back and forth smoothly.
public class rotator : MonoBehaviour {
public float _Angle;
public float _Period;
private float _Time;
// Update is called once per frame
void Update () {
_Time = _Time + Time.deltaTime;
float phase = Mathf.Sin(_Time / _Period);
transform.localRotation = Quaternion.Euler( new Vector3(0, phase * _Angle, 0));
}
}