LookAt in Unity 2D is not working correctly - c#

I've seen a lot of solutions to this issue and I've tried a lot with no success with any of them. LookAt is not working in Unity 2d and Ive been trying for a while.
public Transform target;
// ...
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.name.Contains("Anti"))
{
Quaternion rot = transform.rotation;
transform.rotation = rot;
float z = rot.eulerAngles.z;
Vector3 pos = transform.position;
Vector3 velocity = new Vector3(0, -3, 0);
z += Random.Range(-15.0f, 15.0f);
rot = Quaternion.Euler( 0, 0, z );
transform.position = pos;
transform.rotation = rot;
maxSpeed = Random.Range(5.0f, 15.0f);
}
}
I am struggling getting anything to work regarding LookAt toward my Center doesn't seem to work.
All my other code works (although it has a lot of unnecessary parts I can trim down), its just right before I set Z to a random range, I need it to look at the Origin or Center Object. I cant get that to work at all.
I found a Solution to my issue, I just cleaned out my code and add in
Vector3 diff = Vector3.zero - transform.position;
diff.Normalize();
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rot_z - 90);
I think my issue was the rest of my code,

Related

Enemy bot moves away from the player Unity3D

I'm making top down shooting game. I wrote the code where enemies spawn randomly on map and they're trying to catch you. I made them do that and also I wrote a code to make them look at you. Basically rotate towards you only on Z axis. But problem is that when they are spawned on players' right, enemy is moving away from player. but if I rotate and start to move they are trying to fix themselves. Here's my script:
void FixedUpdate () {
Vector3 difference = player.position - transform.position;
float rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0.0f, 0.0f, rotationZ);
Vector2 toTarget = player.transform.position - transform.position;
float speed = 1.5f;
transform.Translate(toTarget * speed * Time.deltaTime);
}
Consider that Translate is a relative modifier. For this reason, when you specify the direction in the Translate itself, the movement becomes confused. Use Vector3.MoveTowards to solve the problem. If your game is 2D, you can also use Vector2 like below:
Vector2.MoveTowards(currentPosition, targetPosition, step);
Preferably you can fix this code like this and set the return value of MoveTowards equal to transform.Position.
void FixedUpdate () {
Vector3 difference = player.position - transform.position;
float rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0.0f, 0.0f, rotationZ);
float speed = 1.5f;
// replace Translate to MoveTowards
transform.position = Vector3.MoveTowards(transform.position, player.position, Time.deltaTime * speed);
}

Rotating raycast2D back and forth with object

I made a circle and attach a lazer box on top of it.
The lazer will fire a raycast to its upper y axis (straight up). I also add a line renderer to view it.
I want the raycast to rotate 90 degrees back and forth. Sort of like its scanning everything on top. My problem is that its not working properly. It does rotate back and forth but If I move the x position of the lazer object, the raycast will rotate in a weird angle.
Script for lazer object
public LineRenderer lineRenderer;
public LayerMask layerMask;
public float laserSpeed;
Vector3 pointA;
Vector3 pointB;
Vector3 castPosition;
RaycastHit2D rayCast;
float time;
void Start()
{
pointA = transform.eulerAngles + new Vector3(0f, 0f, 90f);
pointB = transform.eulerAngles + new Vector3(0f, 0f, -90f);
}
void Update()
{
time = Mathf.PingPong(Time.time * laserSpeed, 1);
transform.eulerAngles = Vector3.Lerp(pointA, pointB, time);
castPosition = new Vector3(transform.position.x, transform.position.y, transform.position.z);
rayCast = Physics2D.Raycast(castPosition, transform.TransformDirection(Vector2.up), 10f, layerMask);
lineRenderer.SetPosition(0, castPosition);
lineRenderer.SetPosition(1, transform.TransformDirection(Vector2.up) * 10f);
}
Using eulerAngles for continuous animations is quite "dangerous". Unity stores the rotations as Quaternion and there are multiple ways of how to represent these in euler space!
When you read the .eulerAngles property, Unity converts the Quaternion's internal representation of the rotation to Euler angles. Because, there is more than one way to represent any given rotation using Euler angles, the values you read back out may be quite different from the values you assigned. This can cause confusion if you are trying to gradually increment the values to produce animation.
To avoid these kinds of problems, the recommended way to work with rotations is to avoid relying on consistent results when reading .eulerAngles particularly when attempting to gradually increment a rotation to produce animation. For better ways to achieve this, see the Quaternion * operator.
so you should rather go for Quaternion and do e.g.
And then you are using transform.TransformDirection(Vector2.up) which is a direction and pass it to your line renderer as a position.
What you want there is rather the position combined from
transform.position + transform.up
So together it should probably rather be
public LineRenderer lineRenderer;
public LayerMask layerMask;
public float laserSpeed;
private Quaternion originalRotation;
private Quaternion minRotation;
private Quaternion maxRotation;
void Start()
{
originalRotation = transform.rotation;
minRotation = originalRotation * Quaternion.Euler(0, 0, -90);
maxRotation = originalRotation * Quaternion.Euler(0, 0, 90);
}
void Update()
{
// Note that Vector3 is a "struct" -> there is no need to manually use "new Vector3(transform.position.x, ...)"
var startPosition = transform.position;
lineRenderer.SetPosition(0, startPosition);
var factor = Mathf.PingPong(Time.time * laserSpeed, 1);
// instead of the eulers rather use Quaternion
transform.rotation = Quaternion.Lerp(minRotation, maxRotation, factor);
// "transform.up" basically equals using "transform.TransformDirection(Vector3.up)"
var rayCast = Physics2D.Raycast(startPosition, transform.up, 10f, layerMask);
if(rayCast.collider)
{
// when you hit something actually use this hit position as the end point for the line
lineRenderer.SetPosition(1, rayCast.point);
}
else
{
// otherwise from the start position go 10 units in the up direction of your rotated object
lineRenderer.SetPosition(1, startPosition + transform.up * 10f);
}
}

I have problem with rotation; rotatetoToTarget;

I want to 2dgameobject turns toward to target 2dgameobject
I have a Method - rotate to target.
Code:
Quaternion rawRoation = Quaternion.Slerp(transform.rotation,
Quaternion.LookRotation(Player.GetComponent<Transform>().position - transform.position),
10*Time.deltaTime);
transform.rotation = new Quaternion (0, 0, rawRoation.z, rawRoation.w);
Problem - WHen target's position.x < this.object.transform.position.x(1) - rotation breaks..
else(2) - all right.
1 -
enter image description here
2 - enter image description here
The problem is this line of code: transform.rotation = new Quaternion (0, 0, rawRoation.z, rawRoation.w);
I don't know what you want to achieve, but if you want to nullify the x and y rotation use:
transform.rotation = Quaternion.Euler(0.0f, 0.0f, rawRoation.eulerAngles.z);
Example of what your code does:
// Start is called before the first frame update
void Start()
{
Quaternion q1 = new Quaternion(0.3f, 0.7f, 0.4f, 0.5f);
Quaternion q2 = new Quaternion(0.0f, 0.0f, 0.4f, 0.5f);
Debug.Log(q1.eulerAngles);
Debug.Log(q2.eulerAngles);
}
And here the output:
q1: (344.8, 100.3, 59.1)
q2: (0.0, 0.0, 77.3)
Please have a look at the math of quaternions
Edit - 2D LookAt:
Your code does not work like you want because you are in 2D. If you want to look at a target with an x-position less than your object's in 3D you have to do a rotation around the y-axis by 180deg which in 2D is not a valid rotation. You cannot. You do this y-rotation to prevent that the object is upside down. but in 2D you cannot do such a rotation.
You have to choices:
If your camera looks from the side and your object can be upside down use your modified code and also set the x-scale to -1 if the targets x-position is less.
If your camera looks from top down use the following
code:
Code for upside down view:
// Update is called once per frame
void Update() {
Vector3 targetDir = target.position - transform.position;
float angle = Mathf.Atan2(targetDir.y, targetDir.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * 10);
}

Unity 3d, point object towards mouse (3d space)

I searched around for a while but I couldn't figure out how to solve this nasty bug. I am using a top down view (pointing towards -z), basically 2d with 3d objects and camera in perspective mode.
I need to orient an object towards the mouse , ignoring the z aspect, as everything moves on the same plane.
I am using the following code:
Vector3 mouseToWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition + new Vector3(0, 0, 1f));
mouseToWorld.z = 0f;
Vector3 difference = mouseToWorld - transform.position;
difference.Normalize();
float angle = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, angle - 90);
Unfortunately it only works when the object is still, and breaks as soon as the velocity is > 0;
Any hint would be appreciated :)
p.s. I am adding 1 to the z and then resetting it, because otherwise the mouseToWorld is constantly 0 wherever I move the pointer.
Perhaps it breaks because the velocity vector and the mouse direction aren't the same.
the following script will make an arrow follow the mouse, It's basically the same as yours except it updates the position as well:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowMouse : MonoBehaviour {
public float moveSpeed = 0.01f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.position = Vector2.Lerp(transform.position, Camera.main.ScreenToWorldPoint(Input.mousePosition), moveSpeed);
Vector3 difference = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
difference.Normalize();
float rotation_z = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotation_z);
}
}
Thanks for the answer! I figured out you need to subtract the distance between the player and the camera to the initial mouse position:
Vector3 mouseToWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition - new Vector3(0, 0, Camera.main.transform.position.z));
Here the working script:
Vector3 mouseToWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition - new Vector3(0, 0, Camera.main.transform.position.z));
//Debug.DrawLine(transform.position, mouseToWorld);
mouseToWorld.z = 0f;
Vector3 difference = mouseToWorld - transform.position;
difference.Normalize();
float angle = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, angle - 90);

Unity Camera Quaternion.RotateTowards without rolling/banking

I have a camera facing the ground and I want to pan up to look at a target object in the distance.
Currently, I achieve this with the following:
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
The camera performs the rotation and ends up pointing at the target object correctly, but as the camera pans up it tilts to one side making my game world set at an angle to the viewer, which is pretty disorienting:
How can I constrain the camera angle some way so that the horizon is always flat to the camera?
Thanks!
Update
Adding the line suggested by #Isaac below produces the correct rotation in relation to the horizon, but it snaps abruptly to z=0 at the start which is still not what I'm looking for.
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
There is an excellent Q/A on gamedev.stackexchange on this subject. You should try the pitch/yaw system suggested there.
Another suggestion is to correct for the roll of your camera during the rotation.
public float rollCorrectionSpeed;
public void Update()
{
float roll = Vector3.Dot(transform.right, Vector3.up);
transform.Rotate(0, 0, -roll * rollCorrectionSpeed);
Vector3 dir = targetPoint.position - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
}
Edit:
There is an easier solution: Just keep the z rotation of the Quaternion you are rotating from to 0.
public void Update()
{
Vector3 angles = transform.rotation.eulerAngles;
Quaternion from = Quaternion.Euler(angles.x, angles.y, 0);
Vector3 dir = targetPoint.position - transform.position;
Quaternion to = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.RotateTowards(from, to, rotationDamping * Time.deltaTime);
}
Upon experimentation, I found 2 possible solutions depending on what you want.
If you are just trying to follow the target I would recommend using LookAt, which automatically aligns to the world up. In your code that would be (in Update) transform.LookAt(dir);.
If you need/want the pan effect set the localEulerAngles after updating the rotation. This is what I did which worked:
//this is your code
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
transform.rotation = newRotation;
//this is what I added
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
The addition simply takes the way the camera is facing after updating the rotation using the quaternion and sets the z rotation to zero.
Let me know if you have any questions :)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
new information/edits:
I believe I have found a solution, but it is ugly and I would appreciate feedback as to whether it stutters, etc.
This code is essentially the same as before, but now it checks to see the z angle and edits it more manually using a variable I called zDamping which affects the speed at which the camera rotates around the z access only.
I added outside of update:
public float zDamping; //public only for testing, it's convenient for finding an optimal value
private bool rotationCheck = false;
And then inside update():
//This is your code (unchanged)
Vector3 targetPoint = target.transform.position;
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation (dir);
Quaternion newRotation = Quaternion.RotateTowards (transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
//This is what is new (remove my addition from before edits or it won't work)
if (transform.localEulerAngles.z >= 180f && transform.localEulerAngles.z <= 359f && !rotationCheck) {
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, transform.localEulerAngles.z + (rotationDamping * zDamping));
transform.rotation = newRotation;
}
else if (transform.localEulerAngles.z <= -180f && transform.localEulerAngles.z >= 1f && !rotationCheck) {
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, transform.localEulerAngles.z - (rotationDamping * zDamping));
transform.rotation = newRotation;
}
else {
transform.rotation = newRotation;
transform.localEulerAngles = new Vector3 (transform.localEulerAngles.x, transform.localEulerAngles.y, 0);
rotationCheck = true;
}
As I said, this solution is pretty ugly but it might work. You'll have to see what zDamping values work for your speeds to look natural (I recommend starting with .01). There will also be a small "jump" once you get close to the value, but the closer you make 359f to 360 and 1f to 0 the smaller that jump will be. The danger with making it too small is if you overshoot, but it should work even if it overshoots, but it will take a small amount of time.
Test it out and let me know what you think, sorry I couldn't find something more elegant right now. I also experimented with adding a separate Quaternion to exclusively rotate the z axis, but it did not work; feel free to experiment with that and if you want I can give more details about what I did.
Good luck and again, sorry for the sloppy solution.
Added a code in your line, hopefully it'll solve the problem.
Vector3 dir = targetPoint - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Quaternion newRotation = Quaternion.RotateTowards(transform.rotation, lookRotation, rotationDamping * Time.deltaTime);
newRotation.eulerAngles = new Vector3(newRotation.eulerAngles.x,newRotation.eulerAngles.y,transform.rotation.eulerAngles.z);
transform.rotation = newRotation;

Categories