How Quaternion gets multiplied with a vector? - c#

I am working on a third person shooter. And I have found this code. But I cant make no sense with it. First it is multiplying Quaternion with "Vector3.forward" and compiler is showing nothing. And also can you make me clear about the main logic of this code. I know memorizing the code is not a good habit. So can you explain me the code. And what does that Quaternion.euler does, is that for changing euler to quaternion.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
[SerializeField]
Transform target;
[SerializeField]
float distance;
[SerializeField]
float targetheight;
private float x = 0;
private float y = 0;
void LateUpdate()
{
y = target.eulerAngles.y;
Quaternion rotation = Quaternion.Euler(x, y, 0);
Debug.Log(rotation);
transform.rotation = rotation;
var postion = target.position - (rotation *Vector3.forward* distance + new Vector3(0, -targetheight, 0));
transform.position = postion;
}
}

Let's break it down:
y = target.eulerAngles.y;
This is Transform.eulerAngles() and gives you the current rotation of the target as Quaternion.
Then that rotation is reapplied to the target, but with the rotation around the Z-axis removed.
Quaternion rotation = Quaternion.Euler(x, y, 0);
Debug.Log(rotation);
transform.rotation = rotation;
This is Quaternion.Euler(x,y,z) and gives you a rotation from three degree values.
Last is the following calculation:
var postion = target.position - (rotation *Vector3.forward* distance + new Vector3(0, -targetheight, 0));
transform.position = postion;
Multiplying a Vector3 by a Quaternion means to apply the rotation to the vector. So in this case you'd rotate the forward vector based on the rotation of the target (without the Z-axis rotation, since we set that to 0 earlier). Then that resulting forward vector is multiplied by a certain distance to give us a point somewhere in front of the target's current facing direction and lowered according to the targetheight variable.
Lastly that calculation is subtracted from our own current position, basically performing a point reflection with the target being the point. The result is that we actually end up with a position that has a positive height (originally we were using a negative targetheight) and are behind the target's facing direction.

Related

Unity - Virtual Joystick - Camera rotation

I have a virtual movement joystick that I'm using to control the movement of a player object which works fine, the code for this is below.
The problem I have is when I rotate the camera within game mode (or device) the direction is not adjusted according to the cameras rotation, exactly like is shown in this post here that I looked through to try and understand the problem.
I realise I need to rotate my movement around the forward direction the camera is facing which I tried to do with the bottom snippet of code however this yields really strange behavior when the player object moves incredibly fast and eventually unity becomes unresponsive, so something is being incorrectly multiplied I guess.
Could anybody point out where I'm going wrong please? ta !
Edit - Modified to potential answer
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EasyJoystick;
public class NewJoystick : MonoBehaviour
{
[SerializeField] private float speed;
[SerializeField] private Joystick1 joystick;
[SerializeField] Camera MainCam;
private Rigidbody RB;
private Transform cameraTransform;
// Start is called before the first frame update
void Start()
{
cameraTransform = MainCam.transform;
}
void Awake()
{
RB = gameObject.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
float xMovement = joystick.Horizontal();
float zMovement = joystick.Vertical();
Vector3 inputDirection = new Vector3(xMovement, 0, zMovement);
//Get the camera horizontal rotation
Vector3 faceDirection = new Vector3(cameraTransform.forward.x, 0, cameraTransform.forward.z);
//Get the angle between world forward and camera
float cameraAngle = Vector3.SignedAngle(Vector3.forward, faceDirection, Vector3.up);
//Finally rotate the input direction horizontally by the cameraAngle
Vector3 moveDirection = Quaternion.Euler(0, cameraAngle, 0) * inputDirection;
RB.velocity = moveDirection * speed;
}
}
I tried this in the update loop -
var Direction = transform.position += new Vector3(xMovement, 0f,zMovement); //* speed * Time.deltaTime;
Vector3 newDir = MainCam.transform.TransformDirection(Direction);
transform.position += new Vector3(newDir.x, 0f,newDir.z) * speed * Time.deltaTime;
Well, here is a simple idea for how to solve it. At least this is how I did it, and it seems to work ever since.
First, you need to get the joystick input, like you did. Both axis input value should be between -1 and 1. This actually determines the direction itself, since the horizontal axis gives you the X coordinate of a vector and the vertical gives you the Y coordinate of that vector. You can visualize it easily:
Mind, that I just put up some random values there, but you get the idea.
Now, your problem is, that this angle you get from your raw input is
static in direction, meaning that it doesn't rely on the camera's face
direction. You can solve this problem by "locking it to the camera",
or in other words, rotate the input direction based on the camera
rotation. Here's a quick example:
//Get the input direction
float inputX = joystick.Horizontal();
float inputY = joystick.Vertical();
Vector3 inputDirection = new Vector3(inputX, 0, inputY);
//Get the camera horizontal rotation
Vector3 faceDirection = new Vector3(cameraTransform.forward.x, 0, cameraTransform.forward.z);
//Get the angle between world forward and camera
float cameraAngle = Vector3.SignedAngle(Vector3.forward, faceDirection, Vector3.up);
//Finally rotate the input direction horizontally by the cameraAngle
Vector3 moveDirection = Quaternion.Euler(0, cameraAngle, 0) * inputDirection;
IMPORTANT: The code above should be called in the Update cycle, since that is where you get the input information.
After this, you can work with moveDirection to move your player. (I suggest using physics for moving, instead of modifying its position)
Simple moving example:
public RigidBody rigidbody;
public Vector3 moveDirection;
public float moveSpeed = 5f;
void FixedUpdate()
{
rigidbody.velocity = moveDirection * moveSpeed;
}

Not able to Clamp my camera rotation value

I made a camera that rotates around an object... Everything is working fine. But I was not able to clamp or restrict the camera rotation. Here's the code..
//First - Get the Initial Position
if (Input.GetMouseButtonDown(0))
{
mPreviousPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
}
//Second - the difference amount and change in x
if (Input.GetMouseButton(0))
{
Vector3 newPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
Vector3 direction = mPreviousPosition - newPosition;
float rotationAroundYAxis = -direction.x * 180;
mCamRef.transform.position = mTargetToRotateAround.position;
rotationAroundYAxis = Mathf.Clamp(rotationAroundYAxis, -60f,60f);
mCamRef.transform.rotation = Quaternion.Euler(Vector3.up * rotationAroundYAxis);
mCamRef.transform.Translate(new Vector3(mDistanceToTarget.x, mDistanceToTarget.y, -mDistanceToTarget.z));
mPreviousPosition = newPosition;
}
You are clamping
rotationAroundYAxis = Mathf.Clamp(rotationAroundYAxis, -0.6f, 0.6f);
but then use it for Transform.Rotate which rotates from the current rotation about the given amount => you always rotate something.
You would probably rather use e.g. Quaternion.Euler
mCamRef.transform.rotation = Quaternion.Euler(Vector3.up * rotationAroundYAxis);
However, note that clamping a rotation using +- 0.6° makes barely any sense ...
From you comments you want to clamp to +-60° so rather use
rotationAroundYAxis = Mathf.Clamp(rotationAroundYAxis, -60, 60);
Though I still don't understand how you want to get a rotation in angles from a direction vector ...

GetPoint() in Ray but with Padding and Angle

This might be an odd question, but as fairly new to Unity I don't know how to go about my problem, but I find the Ray() class as one of the most useful classes for all kinds of work. Anyhow, to compute a given point of a Ray it's easy to call .GetPoint(distance). - But is there a way to do a call like .GetPoint(distance, padding, angle)?
For instance, given the (3D) Ray from a to b
a--c----b
|
d
A call to .GetPoint(3) would return c, and a call to the wanted/new method .GetPoint(3, 2, 0) should return d. Further, calling .GetPoint(3, 2, 90) should return d when it's behind (or above) c.
I guess I should have paid more attention in math class...
If you don't mind Unity finding an arbitrary starting point, you can use Vector3.OrthoNormalize to get a starting point for you.
Then, you can use Quaternion.AngleAxis to rotate the point around the ray's direction (you have to offset the ray to/from the origin for the rotation operation).
Vector3 GetPaddedPoint(Ray ray, float distance, float padding, float angleInDegrees)
{
Vector3 rayDirection = ray.direction;
Vector3 startingOrtho;
Vector3.OrthoNormalize(ref rayDirection, ref startingOrtho);
// Find some point padding from ray at distance from origin
Vector3 axisPoint = ray.GetPoint(distance);
Vector3 startingPoint = padding * startingOrtho+ axisPoint;
// Find where startingPoint would be if the origin of the ray was at the origin
Vector offsetPoint = startingPoint - ray.origin;
// Rotate the offsetPoint around ray direction using Quaternion
Quaternion rotation = Quaternion.AngleAxis(angleInDegrees, rayDirection);
Vector3 rotatedOffsetPoint = rotation * offsetPoint;
// Add back in the ray's origin
return rotatedOffsetPoint + ray.origin;
}
If you find that you prefer a particular kind of direction for a starting point, you can pass in a startingOrtho. Keep the OrthoNormalize call to ensure that it startingOrtho becomes orthogonal to the ray and normalized if it isn't already.
Vector3 GetPaddedPoint(Ray ray, float distance, float padding, float angleInDegrees, Vector3 startingOrtho)
{
Vector3 rayDirection = ray.direction;
Vector3.OrthoNormalize(ref rayDirection, ref startingOrtho);
// Find some point padding from ray at distance from origin
Vector3 axisPoint = ray.GetPoint(distance);
Vector3 startingPoint = padding * startingOrtho+ axisPoint;
// Find where startingPoint would be if the origin of the ray was at the origin
Vector offsetPoint = startingPoint - ray.origin;
// Rotate the offsetPoint around ray direction using Quaternion
Quaternion rotation = Quaternion.AngleAxis(angleInDegrees, rayDirection);
Vector3 rotatedOffsetPoint = rotation * offsetPoint;
// Add back in the ray's origin
return rotatedOffsetPoint + ray.origin;
}

How can I make a GameObject point towards another GameObject in Unity?

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 &rightarrow; 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/π

How do I make an object rotate based on another object?

I have a cog that the user can turn to rotate a drawbridge. Currently I have the cog and the drawbridge rotating at the same rate, like so: https://gyazo.com/14426947599095c30ace94a046e9ca21
Here is my current code:
[SerializeField] private Rigidbody2D thingToRotate;
void OnMouseDrag()
{
Vector3 mousePosition = Input.mousePosition;
mousePosition = Camera.main.ScreenToWorldPoint(mousePosition);
Vector2 direction = new Vector2(
mousePosition.x - transform.position.x,
mousePosition.y - transform.position.y
);
transform.right = direction;
thingToRotate.transform.up = transform.right;
}
I want it so that when the user turns the cog it only turns the object a little bit, so the user can turn the cog a few times before the drawbridges closes.
I've tried adding to the drawbridges euler angle. I've tried setting the drawbridges rotation to the cog rotation and dividing that rotation by 2.
Don't set fixed orientations but use the proper methods instead.
Mathf.SignedAngle to determine the angle difference between current transform.right and the direction
If using RigidBody2D use Rigidbody2D.MoveRotation instead of setting the rotation through the Transform component.
Then I would store the totalAngle that was rotated in order to e.g. invoke some event when enough rotation was done.
The thingToRotate you simply rotate only to totalAngle / factor.
// Adjust in the Inspector how often the cog thing has to be turned
// in order to make the thingToRotate perform a full 360° rotation
public float factor = 5f;
private float totalAngle = 0f;
[SerializeField] private Rigidbody2D thingToRotate;
private void OnMouseDrag()
{
var mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
// this is shorter ;)
Vector2 direction = (mousePosition - transform.position).normalized;
// get the angle difference you will move
var angle = Vector2.SignedAngle(transform.right, direction);
// rotate yourselve correctly
transform.Rotate(Vector3.forward * angle);
// add the rotated amount to the totalangle
totalAngle += angle;
// for rigidBodies rather use MoveRotation instead of setting values through
// the Transform component
thingToRotate.MoveRotation(totalAngle / factor);
}

Categories