Unity RotateAround() in combination with a specific direction - c#

I'm trying to rotate my camera around a character, with a certain direction it needs to face. For example, I want my camera to rotate around my character, and stop the rotation when it faces another objects forward axis.
So I figured I needed a combination between RotateAround() and LookRotation().
RotateAround() to rotate the camera around the character, and LookRotation() to make the camera face that object aswell.
The problem is: I don't want my camera to move or rotate away from my character.
I tried a couple of things, the most thought out being this:
private void RotateCamera()
{
Quaternion currentCameraRotation = _camera.transform.rotation;
Quaternion futureCameraRotation = Quaternion.LookRotation(_hitObstacleStartingPoint.transform.forward);
float rotationAngle;
Vector3 rotationAxis;
Quaternion.FromToRotation(currentCameraRotation.eulerAngles, futureCameraRotation.eulerAngles).ToAngleAxis(out rotationAngle, out rotationAxis);
_camera.transform.RotateAround(_character.transform.position, _camera.transform.up, rotationAngle);
}
But that ended up in my camera rotating all over the place..
Thanks in advance!
EDIT: I'm sorry for my terrible explanation.
Here's a little drawing.

If you calculate the distance between the current rotation angle, and the target rotation angle, and you can rotate around the pivot over time.
See below:
private void RotateCamera()
{
Quaternion currentCameraRotation = _camera.transform.rotation;
Quaternion futureCameraRotation = Quaternion.LookRotation(obstacleObject.transform.forward, obstacleObject.transform.up);
float angleDelta = Quaternion.Angle(currentCameraRotation, futureCameraRotation);
_camera.transform.RotateAround(this._character.transform.position, _camera.transform.up, angleDelta * rotationSpeed * Time.deltaTime);
}
To help visualize what's going on:
void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawLine(_camera.transform.position, _camera.transform.forward * 20 + _camera.transform.position);
Gizmos.color = Color.red;
Gizmos.DrawLine(obstacleObject.transform.position, obstacleObject.transform.forward * 20 + obstacleObject.transform.position);
}
This doesn't work if your obstacle is rotated around x,z; it's always assuming a identity forward vector.

I ended up using fixed camera points in my scene. It avoids the problem, so I don't consider this one solved, but I have a deadline on this project and I can't afford to spend too much time on this problem anymore. Thanks to those of you who have helped me.

Related

How to make a 2D real-time Strategy camera controller in unity?

I have been looking around for ages about how to do a Real-time Strategy camera for Unity in 2D. What I mean is that you should be controlling the camera with W, A, S, D and where ever I look its only 3D. I have been trying to write my own scripts but the camera never works and I am in dire need for help. I have tried so much but as a beginner on Unity, I really need help with this. If you can give me anything about how to get started in this matter I will be so happy.
Do you think I should use the Force method or that I should use another one that unity already has installed? I also tried using vectors but when I looked around everyone was using Vector 3 which only is for 3D unity.
You can attach a single script to your camera.
public float speed =10.0f;
void Update()
{
Vector3 a = transform.position
if(Input.GetKeyDown("W"))
{
a.position.y += speed *Time.deltaTime
}
if(Input.GetKeyDown("S"))
{
a.position.y -= speed *Time.deltaTime
}
transform.position =a;
}
You can adjust the speed to your needs. You can do this for other keys. Note GetKeyDown is called when a key is being held down. Hope this helps.
Make a direction vector with Vector3 direction = new Vector3();
Manipulate the vector in the directions you want, based on the key:
if (Input.GetKey(KeyCode.A))
direction += Vector3.left;
Adding the "built-in" Vector3.left will point the direction of the vector to the left, and you can add the other keys on top of that to get a final direction.
Then you can use transform.Translate() to move the gameObject (in this case you attached it to your camera) by passing the direction you calculated based on the keys being pressed as a parameter. Then multiply to get direction * speed * Time.deltaTime;

Unity: Can't get object's z axis to lock when facing camera

I want a sprite to always face the camera, except in the Z-Axis. My sprites keep tipping left or right when I move the camera, and I can't have that.
I have been googling this for hours. I've tried transform.LookAt or Quaternion.LookRotation and manually setting the z to 0, but for whatever reason the z keeps adjusting. I've seen and tried so many solutions that feel like they should work but just don't. If it matters, my sprite is a child of another object, but trying localRotation doesn't work either. Freezing rigidbody constraints also has no effect.
The most accurate I can get it is this:
public class Billboard : MonoBehaviour
{
GameObject cam;
float minDist;
// Start is called before the first frame update
void Start()
{
cam = GameObject.Find("Main Camera");
}
// Update is called once per frame
void LateUpdate()
{
//Scale
minDist = cam.GetComponent<CameraOrbit>().distanceMin;
transform.localScale = new Vector3(1f, 1f, 1f) * (cam.GetComponent<CameraOrbit>().distance - minDist) * 1.01f / 3;
//Direction
transform.LookAt(cam.transform.position);
Vector3 rot = transform.rotation.eulerAngles;
transform.rotation = Quaternion.Euler(rot.x, rot.y, 0);
}
}
With this I can get the sprite to face the camera, but the z axis refuses to stay at zero.
Special thanks to StarManta for answering this question on the Unity Forums.
"OK, I think I see what's happening. Them looking like they're rotated is, I think, an illusion; I think they really are accurately pointing at the camera and right-side-up. But, you're treating the camera as if it has a round/fisheye projection, when it really has a rectilinear projection. Usually this doesn't matter but in this case it does. It's hard to explain exactly how this affects this, but the upshot is that, when things that are on either side of the center of the screen are set to "look towards" the camera, they actually appear to be rotated around their Y axes.
The solution to this is actually annoyingly simple: don't set the rotation to look at the camera, set it to be the same as the camera."
transform.rotation = cam.transform.rotation;
Have you tried rotation constraints?
https://docs.unity3d.com/Manual/class-RotationConstraint.html
I had a similar problem, where I wanted some 3d text to always look up, but rotated to the camera.
What worked for me was setting the undesired euler components to zero after applying the lookat rotation.
In your case, it would be something like this.
transform.LookAt(cam.transform.position);
var rot = transform.rotation.eulerAngles;
transform.rotation = Quaternion.Euler(rot.x, rot.y, 0);
In case you need another z value, just replace the 0.

Strange behaviour using Slerp

I am using Quaternion.Slerp to rotate a car when turning. I've noticed that right before a left turn, the car will rotate slightly right before rotating left to make the turn. I am also Lerping the car from one position to the next. Any idea why this happens and how to stop it?
car.transform.position = Vector3.Lerp(car.transform.position, nextPosition, fracJourney);
if (direction != Vector3.zero)
{
Quaternion lookRotation = Quaternion.LookRotation(direction);
car.transform.rotation = Quaternion.Slerp(car.transform.rotation, lookRotation, Time.deltaTime * rotationSpeed);
}
Quaternion.Slerp uses interpolation and shortest path. It does not work well with large angles. And is literally undefined at exactly 180 degrees. Around that angle you will get something "jerky" from frame to frame.
Two options:
Tween your animation. That is, effectively, rotating by smaller angles up until you reach the final angle. Think of key frames or breaking one rotation into smaller chunks.
Or you can do the interpolation while still in Euler Angles space. And then use Quaternion.Euler after interpolation.

Moving a 2d character based on local rotation using physics in unity

I have found a solution for this if I were to be using translation as a means of movement:
http://answers.unity3d.com/questions/1035804/how-do-you-make-an-omnidirectional-2d-character-co.html
however I cannot find a solution for how to do this with my movement being physics based.
I have in my chracters controller the ability to rotate the camera around the z axis:
public Transform target;
private float cameraRot = 3;
if (Input.GetKey("q"))
{
target.transform.Rotate(0, 0, cameraRot);
}
I then have a script on all sprites in the world I am creating that rotates to always face the camera:
public Transform target;
void Start () {
target = GameObject.Find("MainCamera").GetComponent<Transform>();
}
void Update () {
if (target != null)
this.transform.rotation = Camera.main.transform.rotation;
}
That all works fine. However when I have rotated the camera, and therefore the sprites. The rigidbody movements become all skewed as they are rotating in the "global" space and not the "local".
I have tried placing the facecamera script on the child objects only to leave the rigidbody alone but this has no effect.
I hope I made this clear enough and that someone can help.
thank you very much for your time, if I find a solution I will mark the answer as correct and if I fix this myself before an answer I will update with how I fixed it.
The solution was to use:
Rigidbody.AddRelativeForce(Vector2.down * speed);
in lieu of:
Rigidbody.AddForce(Vector2.down * speed);
that adds the force in the local axis not the global.
documentation is here:
https://docs.unity3d.com/ScriptReference/Rigidbody.AddRelativeForce.html

Get position from player forward at constant distance

The simple way to get player front position at specific distance
Vectro3 forward = player.transform.forward * distance;
Vector3 newPlayerFronPosition= player.transform.position + new Vector3(forward.x, forward.y, forward.z);
newPlayerFronPosition= new Vector3(newPlayerFronPosition.x, newPlayerFronPosition.y - 4f, newPlayerFronPosition.z);
navigationCanvas.transform.position = newPlayerFronPosition;
navigationCanvas.transform.rotation = camRotationToWatch.transform.rotation;
its actually working fine but the problem is as my player move up or down the navCanvas become appear ver near to my player. How to mainitain spcific distance all the time.?? that no matter player look above or down the navcanvas display at specfic distance.(position)
disatnceUICam = Vector3.Distance(newPlayerFronPosition, player.transform.position);
I also logged the distance and surprisingly it the distance is changing when i am moving up or down. its changing from 6 to 12 as i am looking up to down.
If I've understood you correctly, and you want a point on in front of your player transform on the X Z Plane a set distance from the forward of your player, you should try something like this:
Vector3 horizontalForward = new Vector3(
player.transform.position.x + player.transform.forward.x,
player.transform.position.y,
player.transform.position.z + player.transform.forward.z
).normalized * distance;
I suspect what you're describing is occurring because the transform of your 'player' variable is connected to the direction of your game camera. As the camera looks up, the world position of your forward changes relative to the camera. Using just the X and Z will produce a varying distance as your camera transform rotates around the X Axis. Perhaps this diagram will illustrate what I mean a little better:
Sorry the hypotenuse is a little wonky but you get the idea right?

Categories