Character randomly rotating on the X and Z axes even thought Rigidbody constraints are enabled - c#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
class FirstPersonCamera : MonoBehaviour
{
public float mouseSensitivity = 100f;
public Transform playerTransform;
public Transform weaponTransform;
private float xRotation = 0;
void Start()
{
UnityEngine.Cursor.lockState = CursorLockMode.Locked; //Hides the cursor and locks it to the center
}
void Update()
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90, 90);
transform.localRotation = Quaternion.Euler(xRotation, 0, 0);
weaponTransform.localRotation = Quaternion.Euler(xRotation, 0, 0);
playerTransform.Rotate(new Vector3(0.0f, mouseX, 0.0f));
//playerTransform.gameObject.GetComponent<Rigidbody>().MoveRotation(Quaternion.Euler(0.0f,mouseX,0.0f));
if (Input.GetKeyDown(KeyCode.Escape))
{
UnityEngine.Cursor.lockState = CursorLockMode.None;
}
}
}
This is what I'm using for player looking (mouse controls) and this keeps happening:
even though I have rigidbody X and Z rotations locked. The issue mainly seems to arise when using keyboard controls and mouse together. Here is the playerMove code as well: https://codeshare.io/wnzrYj . It shouldn't be doing anything with rotation.
I've tried removing the playerTransform.Rotate and the issue seems to disappear. I've also tried rotating the gameObject via the rigidbody but that doesn't seem to rotate the body at all.

You're causing the rotations yourself. You've added the xRotation, which will affect the pitch, but then you use Transform.Rotate, which works locally. That means that when pitched, your Rotate is no longer around the world's Y axis, but rather around the object's pitched Y-axis, adding rotation to axes you don't want.
The easiest way to solve this is to build your hierarchy properly to make sure that the rotations are applied in the order you want. I usually go with something like:
Root -> YawPivot -> Body -> PitchPivot -> Head/Camera
The Root object would have the translations (offsets/movement) applied to it. The YawPivot is only rotated around the Y axis. And the PitchPivot is only rotated around the X axis (and is usually located around the neck or head area).

Related

Vector3.Lerp() not smoothing correctly

I'm working on a hand sway system. And the problem is that when I use Vector3.Lerp(); for it, it looks really bad and laggy :
https://streamable.com/64y52o
And this is my source code :
Transform target;
float smooth;
void Update()
{
transform.position = Vector3.Lerp(transform.position, target.transform.position, smooth * Time.deltaTime);
}
And this is my setup in editor :
enter image description here
The script is attached to Hand game object. And the target input is Hand Pos object in inspector.
I tried using both Vector3.Lerp(); and Vector3.Slerp(); but it didn't change anything.
I also tried running code on both Update() and FixedUpdate() and even LateUpdate() but not much changed.
Full code for source :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HandSway : MonoBehaviour
{
public float smooth;
public float swayMultiplier = 1f;
public Vector3 handOffset;
public Transform target;
private void Update()
{
float x = Input.GetAxisRaw("Mouse X") * swayMultiplier;
float y = Input.GetAxisRaw("Mouse Y") * swayMultiplier;
Quaternion xRot = Quaternion.AngleAxis(-y, Vector3.right);
Quaternion yRot = Quaternion.AngleAxis(x, Vector3.up);
Quaternion rotation = xRot * yRot * target.rotation;
transform.localRotation = Quaternion.Slerp(transform.localRotation, rotation, smooth * Time.deltaTime);
transform.position = Vector3.Lerp(transform.position, target.transform.position, smooth * Time.deltaTime);
}
}
There are a few different approaches when animating an object.
One is to start from position A and interpolate over T seconds to position B. This would be expressed in code like:
t += Time.deltaTime;
transform.position = Vector3.Lerp(A, B, t / T);
This should move the object with a constant speed. If you want to control the speed instead you you could compute T = A.Distance(B) / speed. If you want a constant acceleration instead you could use SLerp.
If you want the object to track the target continuously rather than animating it I would probably not recommend just using Lerp. This will result in a speed that is completely dependent on the distance. This would be equal to a proportional only regulation, see PID controller. Notably, if your proportional factor (i.e. smooth * Time.deltaTime) is larger than 1 you will get oscillations, that might be what is happening.
I would probably recommend that you instead calculate the direction to the target, and cap the speed. You might also want to cap the acceleration for a smoother animation.

Unity 3D first person movement

I'm following brackeys 1st person movement tutorial. but I can't get the camera working.
I followed the tutorial correctly, But this code isn't working. gives no errors but it doesn't work. here's the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseLook : MonoBehaviour
{
public float mouseSensitivity = 100f;
public Transform playerBody;
float xRotation = 0f;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
playerBody.Rotate(Vector3.up * mouseX);
}
}
This code gives no errors but doesn't work. how can i fix this?
The code you've attached is correct.
I recommend you follow the tutorial once more and pay close attention to where this script should be attached.
Having checked the tutorial myself right now I got it to work by parenting camera as a child of player, attaching MouseLook.cs to Camera game object, and setting player game object as a Player Body variable in MouseLook.cs.I recommend making sure that mouseSensitivity variable is set to 100. Next, if that won't solve your issue, it could mean a number of things.
First, your project can have Axis "Mouse X" and "Mouse Y" unset, meaning that it does not record the movement of your mouse when you move it.
Second, player or camera rotation can be overridden by some other behavior that might cause MouseLook rotation to be ignored.

Why can't I look horizontally in Unity3D after adding this line(FPS)?

I was following Brackeys's tutorial on youtube to make my character look horizontally and vertically, at first I was able to look to my right and left in with my mouse, but after I added this line near the end of void update():
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
I can look up and down but can't look to left and right anymore. Could anyone tell me how to fix it? It is confusing because it worked fine in the video tutorial.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseLook : MonoBehaviour
//https://www.youtube.com/watch?v=_QajrabyTJc
{
public float MouseSensitivity = 100f;
//this variable controls the speed of the mouse
public Transform PlayerBody;
float xRotation = 0f;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
//this line is to hide the ouse cursor in game
}
// Update is called once per frame
void Update()
{
float mouseX = Input.GetAxis("Mouse X") * MouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis("Mouse Y") * MouseSensitivity * Time.deltaTime;
//these 2 variables will store the movement input from mouse
//this enables us to look horizontally (rotate around Y Axis)
//InvalidOperationException: You are trying to read Input using the UnityEngine.Input class, but you have switched active Input handling to Input System package in Player Settings.
//MouseLook.Update() this is a but that will appear after this line was added, to fix this
//Project Settings > Player > Active Input Handling change it to both and add camera to playerbody
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation,-90,90f);//this line prevent player to rotate over its head/crotch
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f); *This line!*
PlayerBody.Rotate(Vector3.up * mouseX);
//line 31-33 is for the function to be able to look up and down
//remember Quaternion is about rotation
}
}
This line:
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
It in the Update void, so it will call every frame. You can't look vertically because
every in every frame, this line will make your character y rotation equal to 0
You can see more in here
To fix that you can make a variable call yRotation or something you want then make it like the xRotation but with your mouseY variable and then edit that line to
transform.localRotation = Quaternion.Euler(xRotation, yRotation, 0f);
Thank you guys!
It worked after I:
Declared this new variable
float yRotation = 0f;
Set yRotation to be equal to mouseX + itself
yRotation += mouseX;
Changed the problematic line to what #HiggHigg suggested
transform.localRotation = Quaternion.Euler(xRotation, yRotation, 0f);
Now I can look to 4 directions in FPS with my cursor, the screen kinda shivers when I move though, maybe I'll find a way to fix it later.

How to rotate an object along all 3 axes with finger swipe?

I'm working on a simple AR Vuforia application. How can I implement the rotation of an object along all three axes with one finger swipe?
The code I'm currently using has one bug: the rotation of the object depends on its local axes. For example, if I look at the object from the front, everything works as it should, but if I look at the object from the back side, the finger swipe upwards makes it rotate downwards and vice versa.
Here is this script:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X")*rotSpeed*Mathf.Deg2Rad;
float rotY = Input.GetAxis("Mouse Y")*rotSpeed*Mathf.Deg2Rad;
transform.Rotate(Vector3.up, -rotX);
transform.Rotate(Vector3.right, -rotY);
}
This is not what I need, how can I rotate the object according to the finger swipe direction regardless of the angle from which I look at it?
Update
A simple non-AR example, which may help you understand what I need is an iOS game "Space Frontier 2". After a successful launch of the rocket, it lands on the planet and you can rotate the planet with your finger swipe.
Here is the video demo: https://youtu.be/OiNPP1WNIAI
This works nice regardless of your object's rotation, and regardless of your camera position relative to the object:
public float rotSpeed = 30f;
void OnMouseDrag()
{
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed;
Camera camera = Camera.main;
Vector3 right = Vector3.Cross(camera.transform.up, transform.position - camera.transform.position);
Vector3 up = Vector3.Cross(transform.position - camera.transform.position, right);
transform.rotation = Quaternion.AngleAxis(-rotX, up) * transform.rotation;
transform.rotation = Quaternion.AngleAxis(rotY, right) * transform.rotation;
}
Make sure your camera has the "MainCamera" tag, or assign the camera externally if necessary.
I do not have the exact code with me right now.
But if you did not update your point of view coordinates, this should be the expected result.
Consider a real ball with 2 colors, blue and red, separated vertically.
When you are in front of it, seeing only the blue side, stroking it up will make the blue side go up and the red side appear from the bottom.
Now move behind it, seeing only the red side, and stroke it up again.
The blue face will go down and appear from the bottom.
Unity applies physics to virtual objects the same way we interact with real objects.
So you need to consider your camera position with the object orientation when you apply movements to it.
You need to apply a transformation matrix to your movement based on your camera location related to the object origin orientation.
I hope this is clear enough to put you on tracks to fix it.
I think you have to somehow clamp the rotation to have the desired behaviour. I wrote a script recently to do just that. I did a little modification though.
public float rotSpeed = 30f;
float ClampAngle(float _angle, float _min, float _max)
{
if (_angle < 0f) _angle = 360 + _angle;
if (_angle > 180f) Mathf.Max(_angle, 360 + _min);
return Mathf.Min(_angle, _max);
}
USAGE:
void RotateGameObject()
{
float h = Input.GetTouch(0).deltaPosition.x * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
float v = Input.GetTouch(0).deltaPosition.y * Time.deltaTime * rotSpeed*Mathf.Deg2Rad;
Vector3 rot = transform.rotation.eulerAngles + new Vector3(-v, h, 0f);
//Change the y & z values to match your expected behaviour.
rot.x = ClampAngle(rot.x, -5f, 20f);
//Clamp rotation on the y-axis
rot.y = ClampAngle(rot.y, -20f, 20f);
transform.eulerAngles = rot;
}
See if that works and of course, try to play with the values.

Camera shaking on rotating player while crouching in unity

I am having a problem with the camera following the player. When the player moves, the camera shakes and this effect is more noticeable when the player is in the crouched position. I am using root motion for the player with animations by mixamo.
Player Script:
Transform cameraT;
void Start () {
cameraT = Camera.main.transform;
}
void FixedUpdate ()
{
float sideMotion = Input.GetAxis("SideMotion");
float straightMotion= Input.GetAxis("StraightMotion");
if (Mathf.Abs(sideMotion) > 0 || Mathf.Abs(straightMotion) > 0)
{
transform.eulerAngles = new Vector3(transform.eulerAngles.x,
cameraT.eulerAngles.y);
}
}
Camera Script:
public float distanceFromPlayer=2f;
public float mouseSensitivity=6;
public Transform player;
public Vector2 pitchConstraint= new Vector2(-30,80);
Vector3 rotationSmoothVelocity;
Vector3 currentRotation;
public float rotationSmoothTime = 0.2f;
float yaw; //Rotation around the vertical axis is called yaw
float pitch; //Rotation around the side-to-side axis is called pitch
private void LateUpdate()
{
yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
pitch = Mathf.Clamp(pitch, pitchConstraint.x, pitchConstraint.y);
currentRotation = Vector3.SmoothDamp
(currentRotation, new Vector3(pitch, yaw), ref rotationSmoothVelocity, rotationSmoothTime);
transform.eulerAngles = currentRotation;
transform.position = player.position - transform.forward * distanceFromPlayer;
}
For public transform I just added an empty game object to player chest level and parented it to the player. I got the rotating camera smoothly trick from an online tutorial but that exact thing won't work on player rotation though.
A character controller is attached to player without any rigidbody or collider.
You are going to want to use Lerp on the camera in order to smooth its motion from one position to another. The Scripting API has a good example of Vector3.Lerp.
So in your case, you could add a public variable for smoothing position as well. Something like positionSmoothTime. Then make a "Desired Position" variable, we'll call it destPosition.
Vector3 destPosition = player.position - transform.forward * distanceFromPlayer;
transform.position = Vector3.Lerp(transform.position, destPosition, positionSmoothTime);
This should effectively smooth it to where the stuttering should go away. Another thing that will help that someone else mentioned is using a part of the body that moves less (Like the head) as the target. This combined with the Lerp function will give you a smooth camera movement.
Another large help would be to move things into the Update() function. The reason being is FixedUpdate() doesn't get called every frame. So you could potentially get stutter as a result. If you move everything into Update() it will update every frame and help smooth things out. If you do this though you will need to multiply all movement by Time.deltaTime as shown in the example below.
Vector3 destPosition = (player.position - transform.forward * distanceFromPlayer) * Time.deltaTime;
For more examples, check the links to each function to see Unity's documentation on it. It has examples of everything I've shown here.

Categories

Resources