XNA-Moving rotated camera(view) relative to world - c#

So I've been trying to get this to work but no luck so far, hopefully you can help. The thing is I have a camera in my project that the user can freely move with mouse and buttons.
Currently like so:
move = new Vector3(0, 0, -1) * moveSpeed;
move = new Vector3(0, 0, 1) * moveSpeed;
...
And then I just add move vector to cameraPos vector: cameraPos += move
Then problem is if I rotate the camera and then try to move, for example down, it will not move straight down but in a certain angle. I am assuming this is due to moving on local axis. But what I want to do is to move on a world axis. Is something like that possible, or do I have to somehow calculate the angle and then move on more than one axis?
Best regards!
EDIT:
I am rotating the camera where cameraPos is the current position of the camera and rotation is the current rotation of the camera. And this is the code to rotate the camera:
void Update()
{
...
if(pressed)
{
int newY = currentY - oldY;
pitch -= rotSpeed * newY;
}
Rotate();
}
void Rotate()
{
rotation = Matrix.CreateRotationX(pitch);
Vector3 transformedReference = Vector3.Transform(cameraPos, rotation);
Vector3 lookAt = cameraPos + transformedReference;
view = Matrix.CreateLookAt(cameraPos, lookAt, Vector3.Up);
oldY = currentY;
}
Ihope this is more readable.

I was able to solve this problem by using:
Vector3 v;
if (state.IsKeyDown(Keys.Up))
v = new Vector3(0, 0, 1) * moveSpeed;
... //Other code for moving down,left,right
if (state.IsKeyDown(Keys.V))
view *= Matrix.CreateRotationX(MathHelper.ToRadians(-5f) * rotSpeed); //Multiplying view Matrix to create rotation
view *= Matrix.CreateTranslation(v); //Multiplying view Matrix to create movement by Vector3 v

I suppose you're already saving the direction you're looking at in a Vector3. Replace your method with this:
direction.Normalize();
var move = direction * moveSpeed;
cameraPos += move;

Related

How to rotate to a specific point when a game object rotating in vector3.forward

My player is the cube and the target is sphere
`void Update()
{
Vector3 direction = target.position - player.transform.position;
Quaternion rotation = Quaternion.LookRotation(direction);
if (Input.GetMouseButton(0))
{
player.transform.rotation = Quaternion.RotateTowards(player.transform.rotation, Quaternion.Euler(player.transform.rotation.x, player.transform.rotation.y, rotation.z), rotationSpeed * Time.deltaTime);
}
else
{
player.transform.Rotate(-Vector3.forward * 1f);
}
}
`
Player is rotating infinitely like a spherically movement with transform rotate. When I click I want to rotate my player to target position. I'm trying with rotate towards but its rotating to 0. How can I fix this problem or should I do with something else.
So first of all: The x, y, z of a Quaternion are not what you expect them to be! They have nothing to do with Euler angles and move in normalized ranges between -1 and 1.
Then assuming you rotate the player only ever on the Z axis then you could simply use e.g.
void Update()
{
// use Vector2 to eliminate any delta on the Z axis
// -> vector is only in XY space
Vector2 direction = target.position - player.transform.position;
// -> rotation is only on Z axis
Quaternion rotation = Quaternion.LookRotation(direction);
if (Input.GetMouseButton(0))
{
player.transform.rotation = Quaternion.RotateTowards(player.transform.rotation, rotation), rotationSpeed * Time.deltaTime);
}
else
{
player.transform.Rotate(-Vector3.forward * Time.deltaTime);
}
}

Rotating towards a final rotation challenge

Consider this working script, that handles a FPS camera movement:
using UnityEngine;
public class CameraHandler : MonoBehaviour {
public Transform target;
float dragSpeed = 10f;
float lookAtSensitivity = 200f;
float xRot;
Transform parentGO;
private void Start() {
parentGO = transform.parent;
}
void goToPivot(Transform pivot) {
parentGO.position = Vector3.Lerp(transform.position, pivot.position, 0.05f);
transform.rotation = Quaternion.Lerp(transform.rotation, pivot.rotation, 0.05f);
}
void resetCamRot() {
xRot = 0;
float yRot = transform.localEulerAngles.y;
parentGO.transform.eulerAngles += new Vector3(0, yRot, 0);
transform.localEulerAngles -= new Vector3(0, yRot, 0);
}
void LateUpdate() {
if (Input.GetKey(KeyCode.Mouse1)) {
float touchX = Input.GetAxis("Mouse X") * lookAtSensitivity * Time.deltaTime;
float touchY = Input.GetAxis("Mouse Y") * lookAtSensitivity * Time.deltaTime;
xRot -= touchY;
xRot = Mathf.Clamp(xRot, -90f, 90f);
transform.localRotation = Quaternion.Euler(xRot, 0f, 0f);
parentGO.transform.Rotate(Vector3.up * touchX);
}
if (Input.GetKey(KeyCode.Space)) {
goToPivot(target);
}
if (Input.GetKeyUp(KeyCode.Space)) {
resetCamRot();
}
}
}
Check how the rotations take place in different gameobjects in their respective axis, so that each of rotations are kept independent and everything works.
transform.localRotation = Quaternion.Euler(xRot, 0f, 0f); //camera GO only rotates in local x
parentGO.transform.Rotate(Vector3.up * touchX); //parent GO only rotates in global y
Problem comes when I need to "force" the camera look a certain direction without the inputs, to the FPS movement rules break, and for example the camera gameobject rotates also in the Y xis. That is why I need to call the resetCamRot() method, and traspass the local rotation from the camera object to the parent so that the situation meets the the FPS movement requirements (no local Y axis rotation).
Without calling the resetCamRot() method, when the FPS movement starts on right mouse button click, the camera abruptly changes to the direction it was facing before "forcing" it with goToPivot that sets the position and the rotation.(Just commentinf the resetCamRot method out)
Although resetCamRot() does the work it feels a bit hacky, so is there another way to set the camera to a forced rotation maintaining the local rotation of the child object (where the camera is) to 0?
I thought of decomposing the next step rotation given by Quaternion.Lerp(transform.rotation, pivot.rotation, 0.05f); in the goToPivot() method in each of their respective axis and gameObjects as its done when the rotation is set from the input, to have a clean local Y rot in he camera gameobject each step. Seems to be the over-complicated thing in this case, but was not able to figure that out.
I you wish to try the script out for the challenge just need to add a parent gameobject to the camera and the attach the target in the editor.
This will make the camera look in the direction, the parent transform look in the direction, only flattened, and finally update the internal state (xRot) in accordance with the difference between the two:
void LookTowards(Vector3 direction) {
Vector3 flattened = direction;
flattened.y = 0f;
parentGo.rotation = Quaternion.LookRotation(flattened);
transform.rotation = Quaternion.LookRotation(direction);
xRot = Vector3.SignedAngle(flattened, direction, parentGo.right);
}

2 rotations with transform.Rotate() and transform.localEulerAngles() doesn't work

I'm trying to make a simple car simulator, and when I use the transform.Rotate() to rotate the wheels foreword (x axis), and the transform.localEulerAngles() to rotate in the turning direction (y axis), only the localEulerAngles() works. when I use only one method, the wheel foreword rotation (x axis) works, but I can't manage to make them both work. Do you have any ideas how to make them work together?
float ro = 20f; // 20 degrees turn
//to preserve the x and z values of rotation
Vector3 rot = wheel.gameObject.transform.rotation.eulerAngles;
//rotates the wheels angle
wheel.gameObject.transform.localEulerAngles = new Vector3(rot.x, ro, rot.z);
float vel = wheel.rpm * 2 * Mathf.PI / 60 * Time.deltaTime * Mathf.Rad2Deg;
//rotates the wheels forward
wheel.gameObject.transform.Rotate(vel, 0, 0);
You should not be using localEulerAngles when you are having two different rotations, because when you have 2 movements if you use localEulerAngles you change the local angles with the movements you are providing themselves so you loose the reference of where the angular position of your axis is at.
You can indicate to the rotate method to rotate respect to the world, transform.rotate rotates the transform of your object relative to the world so you can handle simultaneus rotations together because world axis do not change.
Find below the code snippet that I tried, and the picture of my axis orientation which is not exactly the same as yours.
public class WheelTurning : MonoBehaviour
{
float rpm=10f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
turn(direction.left);
}
if (Input.GetKeyDown(KeyCode.D))
{
turn(direction.right);
}
float vel = this.rpm * 2 * Mathf.PI / 60 * Time.deltaTime * Mathf.Rad2Deg;
rotate(vel);
}
enum direction
{
left,
right
}
void turn(direction dir)
{
Vector3 rot = this.gameObject.transform.rotation.eulerAngles;
//rotates the wheels angle
float rotation = dir == direction.left ? 20f : -20f;
gameObject.transform.Rotate(new Vector3(0, rotation, 0), Space.World);
}
void rotate (float speed)
{
gameObject.transform.Rotate(0, speed, 0);
}
}
However it is much more operative to use quaternions, try to check that out.
Hope that helps!
I do not get your point. If you want to turn a wheel it will alwiys be respect to its previous rotational postion. With that reference you can choose the value you like in the rotation vector Vector3(0, rotation, 0). If you want an absolute reference you can make a parent object and rotate this. Objects have the same world axis and when rotated or transformed, the children "suffer" the same transformation. You have to meke sure that the posistion in the childre is 0,0,0 as this is the distance respect to the parent position that will be the rotation pivot.
void setRotation()
{
Vector3 rot = this.gameObject.transform.rotation.eulerAngles;
GameObject wheelParent = gameObject.transform.parent.gameObject;
Vector3 rotationVector = new Vector3(0, 30, 0);//absolute turn set
Quaternion rotation = Quaternion.Euler(rotationVector);
wheelParent.transform.localRotation = rotation;
}
Hope that helps.

Unity: Camera is jumpy/jerky when using touch grab to move rotation

Using Unity, I'm trying to move my turrets rotation using first person camera by using touch, I grab from side of screen to center from the direction i want to go to like in google maps, the touch grab will move my camera there smoothly.
Problem is the camera being very jerky, not smooth in position.
In Global
private float smoothTouchFactor = 5;
This is the code I am using in Update()
Quaternion rotation;
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.GetTouch(0);
x += touch.deltaPosition.x * xSpeed * 0.02f;
y -= touch.deltaPosition.y * ySpeed * 0.02f;
rotation = Quaternion.Euler(y, x, 0f);
turretHeadToMove.rotation = Quaternion.Slerp(turretHeadToMove.rotation, rotation, Time.deltaTime * smoothTouchFactor);
}
}
rotation = Quaternion.Euler(y, x, 0f);
turretHeadToMove.rotation = Quaternion.Slerp(turretHeadToMove.rotation, rotation, Time.deltaTime * smoothTouchFactor);
If I dont add the last 2 lines after the if(touchCount) then the camera goes back to initial position after i lift my finger off the screen.
Here is the mouse axis Mouse X/Y code that works and moves the turret with no jerky motion, smoothly.
private float xSpeed = 40.0f;
private float ySpeed = 40.0f;
in Update()
x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
Quaternion rotation = Quaternion.Euler(y, x, 0f);
turretHeadToMove.rotation = rotation;
From your description of needing those "two lines" at the end, it sounds like you have code elsewhere that's constantly trying to reset their rotation. So, we add a variable to keep rotation consistent with the Quaternion set the last time the touch control was done, and just be sure to assign it to turretHeadToMove.rotation before handling the touch controls.
Then, you can use Euler to create a Quaternion of how much you want to rotate this frame. And then multiply the current rotation by that amount in order to get the new rotation
Altogether this might look like:
As a field:
private Quaternion savedRotation = Quaternion.identity;
In Update:
// Add it before the block so that modifications to `localRotation` are consistent with memory
turretHeadToMove.rotation = savedRotation;
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.GetTouch(0);
Quaternion previousRotation = turretHeadToMove.rotation;
Quaternion rotationThisFrame = Quaternion.Euler(
touch.deltaPosition.y * ySpeed,
touch.deltaPosition.x * xSpeed, 0f);
turretHeadToMove.rotation = previousRotation * rotationThisFrame;
savedRotation = turretHeadToMove.rotation;
}
}

Camera rotation in maze game depending of accelerometer

I'm still newbie to Unity... I'm trying to develop simple maze game. I want to roll my ball through maze, but I have to rotate camera left or right, otherwise the player can't see what's behind while rolling the ball on the left or on the right.
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate()
{
transform.position = player.transform.position + offset;
}
I'm using low pass filter for accelerometer values:
Vector3 lowpass()
{
float LowPassFilterFactor = AccelerometerUpdateInterval / LowPassKernelWidthInSeconds;
lowPassValue = Vector3.Lerp(lowPassValue, Input.acceleration, LowPassFilterFactor);
return lowPassValue;
}
Accelerometer values are from -1 to 1 for each coordinate. Because of that I check my lowPassValue.x value and limit it. If it's positive ( >0.3 ), then the camera should turn right and if it's negative ( <-0.3 ) then camera should turn left.
Quaternion rotation = Quaternion.AngleAxis(45, Vector3.up* Time.deltaTime) ; // right
transform.rotation = rotation;
Quaternion rotation = Quaternion.AngleAxis(-45, Vector3.up * Time.deltaTime) ; // left
transform.rotation = rotation;
But then my offset doesn't work anymore, I can't see ball anymore. And camera rotation doesn't work as it should.
Is there any better solution for this or I'm using the wrong function?
Any help will be very appreciated!
You have a problem with your AngleAxis() where you are multiplying the Axis to rotate on, by Time.deltaTime. this means that essentially you are changing the axis of rotation, and it is unpredictable. Most likely you wont get your "Right" or "Left" rotation. Multiply deltaTime by the angle itself instead.
Also, Quaternions are to be multiplied if you want to apply an angle with them:
Quaternion rotation = Quaternion.AngleAxis(45 * Time.deltaTime, Vector3.up) ; // right
transform.rotation *= rotation;
Quaternion rotation = Quaternion.AngleAxis(-45 * Time.deltaTime, Vector3.up) ; // left
transform.rotation *= rotation;
or this could just be achieved as:
transform.Rotate(45 * Vector3.right * Time.deltaTime); // right
transform.Rotate(45 * -Vector3.right * Time.deltaTime); // left

Categories

Resources