Unity - Using RayCast to orient object to terrain (C#) - c#

I am currently making a flight simulator. Right now, I am trying to get the plane to fly on its own, but I am having some problems with trying to rotate the plane such that it is parallel to the ground.
This is my code:
heightDetect = new Ray (transform.position, Vector3.down);
if (Physics.Raycast (heightDetect, out hit, Mathf.Infinity)) {
Debug.Log (hit.distance);
transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
Debug.DrawRay (heightDetect.origin, heightDetect.direction*1000);
}
The code works and all, but the problem is it is way too bumpy. The camera on the plane keeps jerking about on my screen, and is completely unplayable. Is there a way to smoothen this process? Thank you!

Presumably you are doing this in your Update function, and therefore changing the rotation of your plane many times per second. Instead of directly setting the rotation, you could use spherical linear interpolation:
public float speed = 0.1f;
void Update() {
...
var targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * speed);
}
This effectively smoothes the rotation over time. It works by taking the current rotation and the eventual desired rotation, but only returning a rotation somewhere in between (controlled by speed).

If I understand correctly, you're looking for the Quaternion.Lerp to smooth your rotation for Quaternions, or Mathf.LerpAngle for Vector3 rotation.
Usage example:
Vector3 currentRotation = transform.rotation;
Vector3 newRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
newRotation = new Vector3(
Mathf.LerpAngle(currentRotation.x, newRotation.x, Time.deltaTime),
Mathf.LerpAngle(currentRotation.y, newRotation.y, Time.deltaTime),
Mathf.LerpAngle(currentRotation.z, newRotation.z, Time.deltaTime));
transform.rotation = newRotation;
Multiply Time.deltaTime by any value to change lerp's "speed".

Related

Smooth rotating in the direction player is moving towards (in 2D)

So I tried to use a script from tutorial that Makes a 3d object rotates smoothly to the direction the object is moving towards and when I tried to use it to my 2d sprite it started to rotate really weird 3D rotating, I am really new to unity so please expect any stupid mistakes and here is the script I used:
float horizontalInput = Input.GetAxisRaw("Horizontal");
float verticalInput = Input.GetAxisRaw("Vertical");
Vector3 movementDirection = new Vector3(horizontalInput, 0, verticalInput).normalized;
if (movementDirection != Vector3.zero)
{
Quaternion toRotation = Quaternion.FromToRotation(movementDirection, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation,
rotationSpeed * Time.deltaTime);
}
I tried to replace it with Vector3.right but still the same issue, I also tried to replace it with Vector3.up but this weird 3D rotation still exist.

AI follow and rotate towards the player

I've got a problem with my script, I want the enemy of mine, follow and rotate towards the player. while he's moving around.
It seem to work nice, but when my player turning rotating 180 on y, my enemy seems to go back a lot(his position), and only when my player returning to his normal rotation , the enemy seem to come back.
What did I do wrong?
public class EnemyTesting : MonoBehaviour
{
public GameObject player;
public float speed = 1.5f;
public float turnRate;
private void Update()
{
Vector3 toTarget = player.transform.position - transform.position;
float angleToTarget = Vector3.Angle(transform.forward, toTarget);
Vector3 turnAxis = Vector3.Cross(transform.forward, toTarget);
transform.RotateAround(transform.position, turnAxis, Time.deltaTime * turnRate * angleToTarget);
transform.Translate(toTarget * speed * Time.deltaTime);
}
By "goes back" I understand rotation, not position.
I think that your problem is with Vector3.Angle. Check in the docs that the function returns the smaller of the two possible angles between the two vectors. In the case the angle is bigger than 180 you need to handle that in the code to make your enemy rotate accordingly.
Edit: I think that is produced by the rotation space of the translate function.
Set Space.World in the transform.Translate arguments
Try this:
private void Update() {
Vector3 toTarget = player.transform.position - transform.position;
transform.LookAt(player.transform.position);
transform.Translate(toTarget * speed * Time.deltaTime, Space.World);
}
You could use Quaternion.RotateTowards to slowly rotate the direction of the enemy towards the player.
This behavior also makes the enemy walk towards its forward vector, instead of directly at the player.
var towardsPlayer = player.transform.position - transform.position;
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
Quaternion.LookRotation(towardsPlayer),
Time.deltaTime * turnRate
);
transform.position += transform.forward * speed * Time.deltaTime;

Unity 3D - rotating gameobject without rotating axis

Hope my title summarises my problem. I have a rocket on a 2d game that only moves horizontally across the screen. I want it to rotate towards the players finger (the direction of movement), but cannot find a way to rotate the object without rotating the whole axis it moves on. I simply need it to seem like it has turned, but it should keep moving along the x. How can I go about this?
void Start () {
//scoreT = GetComponent<TextMeshProUGUI> ();
gameSpeed = 1;
score = 0;
Rigidbody2D rb2d = GetComponent<Rigidbody2D> ();
}
// Update is called once per frame
void Update () {
float MoveHorizontal = Input.GetAxis ("Horizontal");
Vector2 Movement = new Vector2 (MoveHorizontal, 0.0f);
rb2d.rotation = Quaternion.Euler (0.0f, 0, 0f, rb2d.velocity.x * -tilt);
transform.Translate (MoveHorizontal * speed, 0, 0);
One thing you can do is to modify rigidbody.rotation of your rocket rocket to make it tilt, when it moves, to one direction or to another. For example:
float tilt - 0.3f;
//In case you prefer the rotation in another axis you just need to modify the position of the rigidbody.velocity.x * -tilt
rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
Since you didn't add any code I am not sure how you are moving your rocket, so I will post a generic code you will need to adapt depending on your own project:
public class PlayerController : MonoBehaviour
{
public float speed;
//The tild factor
public float tilt;
//The limit within the spaceship can move
public Boundary boundary;
void FixedUpdate ()
{
//You will need to capture the screen touchs of the user for the inputs
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
//Applying the movement to the GameObject
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rigidbody.velocity = movement * speed;
//To ensure the GameObject doesnt move outside of the game boundary
rigidbody.position = new Vector3
(
Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax),
0.0f,
Mathf.Clamp (rigidbody.position.z, boundary.zMin, boundary.zMax)
);
//Here is where you apply the rotation
rigidbody.rotation = Quaternion.Euler (0.0f, 0.0f, rigidbody.velocity.x * -tilt);
}
}
As an aside, you are doing a space 2D game you may be interested in checking this tutorial:
https://unity3d.com/learn/tutorials/s/space-shooter-tutorial
What you want is to move your object in global/world space. As it seems the movement of your rocket is currently happening within local space. So when you rotate the rocket it's local coordinates are rotated as well. The world space coordinates are fixed and will never rotate when you change your rocket.
Here is another explanation at that.
You can also have a look at Transform.localPosition and Transform.position and see how your rocket behaves when using one or the other.
You could make the sprite/renderer a child of the GameObject that is your rocket.
Then you can freely rotate the sprite/renderer around without changing the rotation you move the parent GameObject.
This is a hacky solution but it achieves the desired result.
You must move your object relative to the world and rotate locally.
So use Transform.position to move your object and Transform.LocalRotation to rotate it.
Or you can put the part that must rotate as a children of the object that translate, and rotate the children.

Rotating Child Object in Unity 2D with C#

I have a moving object (the ship) with several child objects (its turrets). The turrets are to rotate towards the player object regardless of the direction the ship is facing. The problem is, unless the ship is rotated straight up, the turrets just spin around wildly.
The code to rotate the turrets is as follows:
//Rotate towards player
dir = PlayerScript.GlobalVariables.playerPosition - myPosition;
angleToTarget = Vector2.Angle(dir, transform.up);
angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90;
transform.localRotation = Quaternion.RotateTowards(transform.rotation, Quaternion.AngleAxis(angle, Vector3.forward), turnSpeed);
The ship is instantiated with this code. Changing rotation changes the intitial rotation. At rotation = 180 it is rotated vertically up:
newEnemyShip = Object.Instantiate(enemyShip2, new Vector3(mousePosition.x, mousePosition.y, 0), Quaternion.Euler(210, 0, rotation));
The ship has an initial rotation which never changes. It's movement code is:
//moves in straight line at constant speed
transform.Translate(Vector3.up * currentSpeed * Time.deltaTime, Space.Self);
It also has this to lock it onto the 2d plane:
//Lock rotation on 2d plane
Quaternion q = transform.rotation;
q.eulerAngles = new Vector3(0, 0, q.eulerAngles.z);
transform.rotation = q;
Any help would be great appreciated!
I figured it out! I'm not sure what the problem was with the original code, but the following code for the turret worked:
//Rotate towards player
dir = PlayerScript.GlobalVariables.playerPosition - myPosition;
angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90;
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.AngleAxis(angle, Vector3.forward), turnSpeed);
Bijan, thanks for taking the time to look and respond
Why you just don't use transform.LookAt(playerPosition) ?

Unity C# Quaternion Rotation Correcting orientation

IHi I've been working on a camera rotation method.
I'm trying to rotate a camera using the mouse inputs.
I need the horizontal rotation to be parallel to a x,y plane(my board) and the vertical rotation to be limited to certain angle(something like 40 degree to -40).
I use quaternions to rotate the camera.
Here my code so far
float angle = (mouseX_Current - mouseX_ActionStart) * 0.25f;
Quaternion horizontalRotationQuat = Quaternion.AngleAxis(angle, Vector3.up);
angle = (mouseY_Current - mouseY_ActionStart) * 0.25f;
Quaternion verticalRotationQuat = Quaternion.AngleAxis(angle, Vector3.right);
Camera.main.transform.rotation *= (horizontalRotationQuat * verticalRotationQuat);
My problem is that by adding those mouse related rotations to my current camera orientation quaternion the camera is no more parallel to the plane(x,y) which it s looking at.
I' ve been trying to create a correction quaternion to add to the camera quaternion after adding those mouse related rotations but I can't seem to find the right one.
Quaternion currentOrientationQuat = Camera.main.transform.rotation;
Quaternion corretionQuat = new Quaternion(0.0f, 0.0f, - currentOrientationQuat.z, currentOrientationQuat.w);
Camera.main.transform.rotation *= corretionQuat;
If someone could help me out on this I would be very grateful.
Thanks.
Sorry for the English, not my primary language.
Solved this using another method
float angle = (mouseX_Current - mouseX_ActionStart) * 0.25f;
Camera.main.transform.Rotate(0.0f, 0.0f, angle, Space.World);
angle = (mouseY_Current - mouseY_ActionStart) * 0.25f;
Camera.main.transform.Rotate(angle, 0.0f, 0.0f, Space.Self);
Feeling dumb after seeing how easy it was to do it.
Did'nt even needed the quaternions for this one.

Categories