I've gone through Unity's documentation for Quaternion.LookRotation, but I didn't get the full understanding of how it works.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
public Transform target;
void Update()
{
Vector3 relativePos = target.position - transform.position;
// the second argument, upwards, defaults to Vector3.up
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
transform.rotation = rotation;
}
}
A way to visualize a rotation is with three perpendicular axis-ex. A quaternion is a more compact representation, but you can still view it as having three axis-es.
LookRotation will align one of the rotation axes to the given direction, but with only one direction there is one degree of freedom left, the other two rotation axes.
That is what the 'up' vector is for, it locks in one of the other axes and forces it to be perpendicular to both the direction and up-vector. The third rotation axis is always perpendicular to both, so we have three perpendicular axes, i.e. a complete rotation.
You can do something similar yourself with a cross product, since that produces a perpendicular vector to two others. Pseudocode:
var xDir = direction;
var zDir= xDir.CrossProduct(upVector)
var yDir = zDir.CrossProduct(xDir)
var matrix = CreateARotationMatrixFromAxises(xDir, yDir, zDir)
var quaternion = CreateQuaternionFromRotationMatrix(matrix)
Note that the direction and up-vector cannot be parallel, or you will get some kind of error.
There is absolutely no reason for beginners and hobbyist programmers to touch Quaternions. Unity should remove it from the documentation.
What you want is simply the LookAt command. Fortunately, it's incredibly easy to use.
Say you have a tree that you want your character to look at, it's this simple:
transform.LookAt(tree);
Related
i want to rotate player body according to the rotation of the camera. like FPS game.
STEPS >>
When the camera is facing down, i can see my body under the camera.
My body has to follow the location of the camera.
My body has to also follow the rotation of the camera.
So i can see my body anywhere when i facing down camera.
here is my code. It is attached to body(the object i have to rotate).
private void Update()
{
transform.position = arCamera.transform.position;
transform.rotation = arCamera.transform.rotation;
}
I want to see my body when the camera facing down but body rotates according with camera so i never see the body. How can i see it? ;(
Please help!
Sounds like you want your body only copy the rotation around the Y axis.
It is way easier to calculate with vectors than with quaternion rotations ;)
private void Update()
{
transform.position = arCamera.transform.position;
// Take your camera forward vector
var camForward = arCamera.transform.forward;
// erase the Y component
camForward.y = 0;
// and now make your body look into this flattened direction
transform.rotation = Quaternion.LookDirection(camForward, Vector3.up);
}
See also Quaternion.LookDirection.
This has of course one little flaw: The moment the camera looks up or down more than 90° the body is flipping to the opposite direction. So you either want to limit the camera rotation or come up with a different approach.
E.g. assuming that it is way harder for a human being to rotate (tilt) the head more then 90° on the Z axis, you could instead also do
private void Update()
{
transform.position = arCamera.transform.position;
// Take your camera forward vector
var camRight = arCamera.transform.right;
// erase the Y component
camRight.y = 0;
// and now align the body's right axis with this flattened direction
// Since we never touch the object's up vector this works without problems
transform.right = camRight;
}
I tried this code but it doesn't work correctly.
Edit: LookAt makes the GameObject invisible
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyPoint : MonoBehaviour {
public float offset;
public Transform target;
private void Update()
{
Vector2 difference = target.position - transform.position;
float rotZ = Mathf.Atan(difference.y) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotZ + offset);
}
}
You can use LookAt.
Rotates the transform so the forward vector points at target's current position.
transform.LookAt(target);
Simply place this on your objectA and in the target field drag&drop any other objectB → objectA's forward vector will always point towards objectB.
An alternative overwrite also takes a world position as Vector3 instead so you can also use
transform.LookAt(target.position);
which will basically do exactly the same thing.
If you need another axis pointing towards the target you can still use LookAt and afterwards Rotate. E.g. in order to not make the forward but rather the up Vector of the object point towards the target you can use
transform.LookAt(target);
transform.Rotate(Vector3.right * 90);
this thread is pretty old, but nonetheless i thought i might just pitch in. In line 13 you're using the wrong trig function. Using Mathf.Atan2(y, x) yields the arctangent y/x in the range of -π to +π, instead, you're using Mathf.Atan(y) which just does calculations based on y only and doesn't take into account the x value as well.
float rotZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg //Get arctangential of x and y and turn it into degrees with 180/π
So I am trying to make a game where you are rquired to set the angle and speed of a ball that has to bounce on specific platforms in order to get to the destination.
Now, how do I find the direction from where the finger touches, to the ball, in order to make it move "away from the finger".
I have tried to use the subtraction of vectors in order to get the direction but It does not work since the vectors are relative to the world origin...it always gives me a wrong direction...
How do I solve this problem, I need a direction vector relative to touch and player(the ball), not to world, so I can launch the ball.
You will see that in the next picture I am simulating a touch with the mouse arrow(let say the mouse arrow is the finger of the player.I want to launch the ball based on the distance and position of the finger relative to the ball. It works well in the code BUT ONLY if the ball is placed on the origin of the scene, so i think it's a mathematical problem with vectors that I don't know how to resolve...
Below is the code that I have by now. It is attached to the ball's gameobject:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
[SerializeField]
Camera playerCamera;
Rigidbody rb;
Vector3 touchPostion;
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
if (Input.GetMouseButton(0))
{
LounchPlayer();
}
}
void LounchPlayer()
{
Vector2 mousePos = Input.mousePosition;
touchPostion = (transform.position - playerCamera.ScreenToWorldPoint(
new Vector3(mousePos.x,
mousePos.y,
playerCamera.transform.position.z))).normalized;
rb.AddForce(touchPostion.normalized, ForceMode.Impulse);
}
}
When finding your touch position, the z component of ScreenToWorldPoint's parameter should be an appropriate distance along the camera's forward vector, definitely not the camera's world z position. playerCamera.nearClipPlane is appropriate here, but really any small constant (such as 0) would suffice.
Also, there is no need to normalize the launch direction twice.
Vector2 mousePos = Input.mousePosition;
touchPostion = (transform.position - playerCamera.ScreenToWorldPoint(
new Vector3(
mousePos.x,
mousePos.y,
playerCamera.nearClipPlane))
).normalized; // This isn't a position vector; it's a direction vector.
// The var name "touchPosition" is misleading and should be changed.
float launchMagnitude = 1f; // change this to adjust the power of the launch
rb.AddForce(touchPostion * launchMagnitude , ForceMode.Impulse);
I'm currently making a small platformer 3D game, but unfortunately I can't make the player to rotate properly when it is riding the platform, the thing here is that I don't want to make the player child of the platform, so far I've managed to make him move smoothly along with the platform, but the rotation is still going nowhere, here is the code I'm using for the rotation:
player.transform.rotation *= platform.rotation;
and here is the effect I got:
Rotation Error
not very nice :(
I guess the solution is something simple, some formula, but unfortunately I'm not very good with math :( So, thank you guys, I hope you can help me.
I'll show you a simple script example which makes a cube rotate by input while reacting to the rotation of the platform on which it stands:
using UnityEngine;
public class CubeRotation : MonoBehaviour {
public GameObject Platform;
Quaternion PreviousPlatformRotation;
public float rotationSpeed = 50;
private void Start() {
PreviousPlatformRotation = Platform.transform.rotation;
}
private void Update() {
//Rotate the cube by input
if (Input.GetKey(KeyCode.A)) {
transform.Rotate(Vector3.up, Time.deltaTime * rotationSpeed);
}
if (Input.GetKey(KeyCode.D)) {
transform.Rotate(Vector3.up, -Time.deltaTime * rotationSpeed);
}
//Adjust rotation due to platform rotating
if (Platform.transform.rotation != PreviousPlatformRotation) {
var platformRotatedBy = Platform.transform.rotation * Quaternion.Inverse(PreviousPlatformRotation);
transform.rotation *= platformRotatedBy;
PreviousPlatformRotation = Platform.transform.rotation;
}
}
}
The logic of the adjustment to the platform rotation is this:
Get at start the rotation quaternion of the platform (in your case, get it when the cube object climbs on the platform)
With A and D rotate the cube normally around the local Y axis.
Afterwards check if the platform's rotation has changed, if yes:
3.a Get how much the platform rotated since the previous frame, with the operation Actual rotation * Inverse(Previous Rotation); this operation it's akin to a difference between two quaternions
3.b Add that quaternion to the cube's rotation with the *= operator
3.c Set the platform's previous rotation value to the new one.
That's pretty much it.
I'm trying to implement centripetal force in a programming language.
I saw some videos teaching the theory. But I dont know how to apply that in a programming language.
If I understand I have to apply centripetal force ac = v²/r to the velocity vector. But I dont know exactly how to proceed.
I have two game objects, one depicting Earth, other depicting Moon. What I wanted is to translate the moon around earth and using a button to "cut/cancel" the centripetal force in order to the moon get out to the earth's orbit.
I have no clue how to start that.
All I know is to rotate like this:
velocity.x = Mathf.Cos(Time.time) * earth_moon_radius;
velocity.z = Mathf.Sin(Time.time) * earth_moon_radius;
moon.transform.position = velocity;
But how to apply centripetal force as described above?
If you just want to have the moon rotating around earth and some trigger to release the moon, it's easier to use rotation around a center instead of forces. Given the following GameObject hierarchy:
Center (MoonRotator attached)
-- Moon
-- Earth
public class MoonRotator : MonoBehaviour
{
public bool cancelCentripetalForce = false;
public Vector3 angularVelocity = new Vector3 (0f, 0f, 100f);
public GameObject moon;
void Update () {
if (cancelCentripetalForce) {
Vector3 radius = moon.transform.position - transform.position;
Vector3 angularVelocityRadians = Mathf.Deg2Rad * angularVelocity;
moon.rigidbody.velocity = Vector3.Cross (angularVelocityRadians, radius);
moon.transform.parent = null;
Destroy (this);
} else {
Vector3 rot = transform.rotation.eulerAngles + angularVelocity * Time.deltaTime;
transform.rotation = Quaternion.Euler (rot);
}
}
}
If cancelCentripetalForce is set true Moon stops travelling around earth but proceeds with its current tangential velocity. This is given as:
v = ω × r
Earth has localPosition (0, 0, 0) and Moon is in this example located in the x-y plane rotating around the z axis.
If you want to cancel the force, add an opposing force vector that is based on your object's linear velocity and current direction.
So I have an object pointing straight along the Z axis. The object's 'forward' vector is 0, 0, 1. Do 1 - Math.abs(forward.x), same for y and z to get 1, 1, 0 when you're pointing forward along the Z axis. You want the direction you're pointing in to be 0'd so that the inertia from that direction is not damped in any way. Now you can apply a cancellation force in any direction that you are NOT pointed in.
This means that if your object is moving in any direction in world space that it's not facing in you can easily apply a cancellation force that is multiplied by the object's linear velocity to get circular motion that uses forces instead of directly setting velocity.
Another way you can do it is solve for V by manually setting it, then find radius using V=RW. You should know V and R or W. Now you can find the force necessary to keep the orbit stable around a point, rather than adding inertia from every frame.