My camera is flickkering after rotating around a particular point. Can someone tell me what's the problem?
I have shared the image also, the image is flickkering a lot between scene frame and snipping tool frameenter image description here
using UnityEngine;
public class CameraFollowMain : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float camMotionSpeed = 2f;
[SerializeField] private float camDistance = 1.5f;
Vector3 offset;
// Start is called before the first frame update
void Start()
{
//gets the distance between 2 vectors in vector format.
offset = (transform.position + target.position).normalized * camDistance;
}
// Update is called once per frame
void FixedUpdate()
{
transform.position = target.position + offset;
offset = Quaternion.AngleAxis(Input.GetAxis("Mouse X") * camMotionSpeed, Vector3.up) * offset;
offset = Quaternion.AngleAxis(Input.GetAxis("Mouse Y") * camMotionSpeed, Vector3.right) * offset;
transform.LookAt(target.transform.position);
}
}
I have tried out this code and I was expecting the camera to rotate around the character like that in GTA5
The cause of "flickering" camera is "Gimbal lock" effect.
Gimbal lock is the loss of one degree of freedom in a
three-dimensional, three-gimbal mechanism that occurs when the axes of
two of the three gimbals are driven into a parallel configuration,
"locking" the system into rotation in a degenerate two-dimensional
space.
In this code, I don't handle obstacles, only follow and observe the target:
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float rotationSpeed = 5f;
[SerializeField] private float viewDistance = 1.5f;
[Range(-90f, 90f)]
[SerializeField] private float minVerticalAngle = -90f;
[Range(-90f, 90f)]
[SerializeField] private float maxVerticalAngle = 90f;
[SerializeField] private float rotationSensitive = 10000f;
[SerializeField] private float followingSensitive = 10000f;
[SerializeField] private float distanceMovementSensitive = 10f;
private Vector3 planarDirection;
private float targetVerticalAngle;
private Vector3 currentPosition;
private float currentDistance;
void Start()
{
planarDirection = Vector3.forward;
targetVerticalAngle = 0f;
currentPosition = target.position;
}
void Update()
{
var deltaTime = Time.deltaTime;
var rotationInput = new Vector3(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"), 0f);
var targetTransformUp = target.transform.rotation * Vector3.up;
var rotationFromInput = Quaternion.Euler(targetTransformUp * (rotationInput.x * rotationSpeed));
planarDirection = rotationFromInput * planarDirection;
planarDirection = Vector3.Cross(targetTransformUp, Vector3.Cross(planarDirection, targetTransformUp));
var planarRotation = Quaternion.LookRotation(planarDirection, targetTransformUp);
targetVerticalAngle -= (rotationInput.y * rotationSpeed);
targetVerticalAngle = Mathf.Clamp(targetVerticalAngle, minVerticalAngle, maxVerticalAngle);
var verticalRotation = Quaternion.Euler(targetVerticalAngle, 0, 0);
var targetRotation = Quaternion.Slerp(
transform.rotation,
planarRotation * verticalRotation,
1f - Mathf.Exp(-rotationSensitive * deltaTime));
transform.rotation = targetRotation;
currentPosition = Vector3.Lerp(currentPosition, target.position, 1f - Mathf.Exp(-followingSensitive * deltaTime));
currentDistance = Mathf.Lerp(currentDistance, viewDistance, 1 - Mathf.Exp(-distanceMovementSensitive * deltaTime));
transform.position = currentPosition - ((targetRotation * Vector3.forward) * currentDistance);
}
}
Related
I'm a new programmer and I was following some tutorial on YouTube but I am having difficulty making it work.
Here's the error I get:
NullReferenceException: Object reference not set to an instance of an object
Moving.Update () (at Assets/Moving.cs:39)
Here's the code:
public class Moving : MonoBehaviour
{
public float mouseSensitivity = 100.0f;
public float clampAngle = 80.0f;
private float rotY = 0.0f; // rotation around the up/y axis
private float rotX = 0.0f; // rotation around the right/x axis
public GameObject player;
public CharacterController controller;
public float speed = 6f;
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
Vector3 rot = transform.localRotation.eulerAngles;
rotY = rot.y;
rotX = rot.x;
}
void Update()
{
float mouseX = Input.GetAxis("Mouse X");
float mouseY = -Input.GetAxis("Mouse Y");
rotY += mouseX * mouseSensitivity * Time.deltaTime;
rotX += mouseY * mouseSensitivity * Time.deltaTime;
rotX = Mathf.Clamp(rotX, -clampAngle, clampAngle);
Quaternion localRotation = Quaternion.Euler(rotX, rotY, 0.0f);
transform.rotation = localRotation;
transform.parent.transform.Rotation = Quaternion.Euler(rotX, rotY, 0.0f);
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
Vector3 Direction = (player.transform.forward * vertical + player.transform.right * horizontal).normalized;
controller.Move(Direction * speed * Time.deltaTime);
}
}
I'm using unity 2020.3.37
You haven't provided all the code so I can't exactly know which line is 39 but I think you are getting this error because your transform doesn't have a parent so this line is causing the error.
transform.parent.transform.Rotation = Quaternion.Euler(rotX, rotY, 0.0f);
So first make sure you have assigned the values for player and controller in the inspector then make sure either your object with Moving.cs attached to it have a parent or try remove or change the line of code that is trying to get the transform.parent.
I have a player in the game, which I can move using the keyboard and rotate only on the horizontal axis using the mouse. That means, I can aim only horizontally and I can not aim it up and down.
I have the Main Camera and another VM Camera from Cinemachine. The current state of the game is like this:
On the horizontal axis, I rotate the player, but on the vertical axis I only want the player's camera/FOV to be moved up and down.
My movement script attached to the player is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController characterController;
public float speed = 35f;
public Animator animator;
// camera and rotation
public Transform cameraHolder;
public float mouseSensitivity = 2f;
public float upLimit = 50;
public float downLimit = -50;
// gravity
private float gravity = 9.87f;
private float verticalSpeed = 0;
void Update()
{
Move();
Rotate();
}
public void Rotate()
{
float horizontalRotation = Input.GetAxis("Mouse X");
float verticalRotation = Input.GetAxis("Mouse Y");
transform.Rotate(0, horizontalRotation * mouseSensitivity, 0);
cameraHolder.Rotate(-verticalRotation * mouseSensitivity, 0, 0);
Vector3 currentRotation = cameraHolder.localEulerAngles;
if (currentRotation.x > 180) currentRotation.x -= 360;
currentRotation.x = Mathf.Clamp(currentRotation.x, upLimit, downLimit);
cameraHolder.localRotation = Quaternion.Euler(currentRotation);
}
private void Move()
{
float horizontalMove = Input.GetAxis("Horizontal");
float verticalMove = Input.GetAxis("Vertical");
if (characterController.isGrounded) verticalSpeed = 0;
else verticalSpeed -= gravity * Time.deltaTime;
Vector3 gravityMove = new Vector3(0, verticalSpeed, 0);
Vector3 move = transform.forward * verticalMove + transform.right * horizontalMove;
characterController.Move(speed * Time.deltaTime * move + gravityMove * Time.deltaTime);
}
}
This is the code i use, it works for me, it's super easy to implement, and stops moving the camera when you aren't focusing the game, is the script from one of Brackey's tutorials modified for this purpose:
using UnityEngine;
public class CameraController : MonoBehaviour
{
public PlayerController player;
public float sensitivity = 150f;
public float clampAngle = 85f;
public bool look = true;
private float verticalRotation;
private float horizontalRotation;
private void Start()
{
verticalRotation = transform.localEulerAngles.x;
horizontalRotation = player.transform.eulerAngles.y;
// Defines the state of the cursor
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
private void Update()
{
// Looks around if the user is in the window
if (look)
{
Look();
}
Debug.DrawRay(transform.position, transform.forward * 2, Color.red);
// If the player presses ESC while in the game, it unlocks the cursor
if (look && Input.GetKeyDown(KeyCode.Escape))
{
look = false;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else if (Input.GetMouseButtonDown(0) && !look)
{
look = true;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
private void Look()
{
float _mouseVertical = -Input.GetAxis("Mouse Y");
float _mouseHorizontal = Input.GetAxis("Mouse X");
verticalRotation += _mouseVertical * sensitivity * Time.deltaTime;
horizontalRotation += _mouseHorizontal * sensitivity * Time.deltaTime;
verticalRotation = Mathf.Clamp(verticalRotation, -clampAngle, clampAngle);
transform.localRotation = Quaternion.Euler(verticalRotation, 0f, 0f);
player.transform.rotation = Quaternion.Euler(0f, horizontalRotation, 0f);
}
}
I have two scripts one is the MouseHandler and the other is the SimpleMovement. rotating the camera works and moving works however when the camera turns the movement doesn't go in that direction. E.G i turn the camera 90 degrees to the right but the forward doesn't change. The forward doesn't go to where the camera is facing. Sorry if i'm just being stupid. Any help would be appreciated
MouseHandler script:
public class MouseHandler : MonoBehaviour
{
// horizontal rotation speed
public float horizontalSpeed = 1f;
// vertical rotation speed
public float verticalSpeed = 1f;
private float xRotation = 0.0f;
private float yRotation = 0.0f;
private Camera cam;
void Start()
{
cam = Camera.main;
}
void Update()
{
float mouseX = Input.GetAxis("Mouse X") * horizontalSpeed;
float mouseY = Input.GetAxis("Mouse Y") * verticalSpeed;
yRotation += mouseX;
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90, 90);
cam.transform.eulerAngles = new Vector3(xRotation, yRotation, 0.0f);
}
}
SimpleMovement Script:
public class SimpleMovement : MonoBehaviour
{
CharacterController characterController;
public float MovementSpeed = 1;
public float Gravity = 9.8f;
private float velocity = 0;
private void Start()
{
characterController = GetComponent<CharacterController>();
}
void Update()
{
// player movement - forward, backward, left, right
float horizontal = Input.GetAxis("Horizontal") * MovementSpeed;
float vertical = Input.GetAxis("Vertical") * MovementSpeed;
characterController.Move((Vector3.right * horizontal + Vector3.forward * vertical) * Time.deltaTime);
// Gravity
if (characterController.isGrounded)
{
velocity = 0;
}
else
{
velocity -= Gravity * Time.deltaTime;
characterController.Move(new Vector3(0, velocity, 0));
}
}
}
First, get a reference to the main cmaera and cache it, because you're going to be referencing it frequently, and simply using Camera.main is a bit expensive:
private Camera mainCam;
...
private void Start()
{
characterController = GetComponent<CharacterController>();
mainCam = Camera.main;
}
Then, use mainCam.transform.right and mainCam.transform.forward but with the y set to 0 and normalized instead of Vector3.right and Vector3.forward. This will make the movement be based on the rotation of the camera:
float horizontal = Input.GetAxis("Horizontal") * MovementSpeed;
float vertical = Input.GetAxis("Vertical") * MovementSpeed;
Vector3 camRightFlat = new Vector3(mainCam.transform.right.x, 0f,
mainCam.transform.right.z).normalized;
Vector3 camForwardFlat = new Vector3(mainCam.transform.forward.x, 0f,
mainCam.transform.forward.z).normalized;
characterController.Move(
(camRightFlat * horizontal + camForwardFlat * vertical) * Time.deltaTime);
Altogether:
public class SimpleMovement : MonoBehaviour
{
CharacterController characterController;
public float MovementSpeed = 1;
public float Gravity = 9.8f;
private float velocity = 0;
private Camera mainCam;
private void Start()
{
characterController = GetComponent<CharacterController>();
mainCam = Camera.main;
}
void Update()
{
// player movement - forward, backward, left, right
float horizontal = Input.GetAxis("Horizontal") * MovementSpeed;
float vertical = Input.GetAxis("Vertical") * MovementSpeed;
Vector3 camRightFlat = new Vector3(mainCam.transform.right.x, 0f,
mainCam.transform.right.z).normalized;
Vector3 camForwardFlat = new Vector3(mainCam.transform.forward.x, 0f,
mainCam.transform.forward.z).normalized;
characterController.Move((camRightFlat * horizontal + camForwardFlat * vertical)
* Time.deltaTime);
// Gravity
if (characterController.isGrounded)
{
velocity = 0;
}
else
{
velocity -= Gravity * Time.deltaTime;
characterController.Move(new Vector3(0, velocity, 0));
}
}
}
There is my script Rigidbody controller -
public float Speed = 5f;
public float JumpHeight = 2f;
public float GroundDistance = 0.2f;
public float DashDistance = 5f;
public LayerMask Ground;
private Rigidbody _body;
private Vector3 _inputs = Vector3.zero;
private bool _isGrounded = true;
private Transform _groundChecker;
void Start()
{
_body = GetComponent<Rigidbody>();
_groundChecker = transform.GetChild(0);
}
void Update()
{
_isGrounded = Physics.CheckSphere(_groundChecker.position, GroundDistance, Ground, QueryTriggerInteraction.Ignore);
_inputs = Vector3.zero;
_inputs.x = Input.GetAxis("Horizontal");
_inputs.z = Input.GetAxis("Vertical");
if (_inputs != Vector3.zero)
transform.forward = _inputs;
if (Input.GetButtonDown("Jump") && _isGrounded)
{
_body.AddForce(Vector3.up * Mathf.Sqrt(JumpHeight * -2f * Physics.gravity.y), ForceMode.VelocityChange);
}
if (Input.GetButtonDown("Sprint"))
{
Vector3 dashVelocity = Vector3.Scale(transform.forward, DashDistance * new Vector3((Mathf.Log(1f / (Time.deltaTime * _body.drag + 1)) / -Time.deltaTime), 0, (Mathf.Log(1f / (Time.deltaTime * _body.drag + 1)) / -Time.deltaTime)));
_body.AddForce(dashVelocity, ForceMode.VelocityChange);
}
}
void FixedUpdate()
{
_body.MovePosition(_body.position + _inputs * Speed * Time.fixedDeltaTime);
}
What the best way to make a turn on y in the direction of the camera ? That is,the player turns to the side where the mouse is turned? Is it in fixedUpdate or update?
This is the camera script:
public float Smoothness = 0.3F;
public Vector2 Sensitivity = new Vector2(4, 4);
public Vector2 LimitX = new Vector2(-70, 80);
private Vector2 NewCoord;
public Vector2 CurrentCoord;
private Vector2 vel;
public GameManager GameMangerS;
public Transform Target;
public float TransformSpeed;
public Animator CameraAnimator;
void Update()
{
NewCoord.x = Mathf.Clamp(NewCoord.x, LimitX.x, LimitX.y);
NewCoord.x -= Input.GetAxis("Mouse Y") * Sensitivity.x;
NewCoord.y += Input.GetAxis("Mouse X") * Sensitivity.y;
CurrentCoord.x = Mathf.SmoothDamp(CurrentCoord.x, NewCoord.x, ref vel.x, Smoothness / 2);
CurrentCoord.y = Mathf.SmoothDamp(CurrentCoord.y, NewCoord.y, ref vel.y, Smoothness / 2);
transform.rotation = Quaternion.Euler(CurrentCoord.x, CurrentCoord.y, 0);
}
And added this line to the controller script -
void FixedUpdate()
{
_body.MovePosition(_body.position + _inputs * Speed * Time.fixedDeltaTime);
transform.rotation = Quaternion.Euler(0, MainCamera.CurrentCoord.y, 0);
}
When I'm standing the player normally rotates, but when I start to move, all rotations are reset and the player is not moving.
Update
Simple Rotation can be achieved using transform.Rotate().
Example:
this.transform.Rotate(Vector3.up, 30);
This example is gonna rotate the transform by 30° around the Vector that points upwards.
LookAtMouse:
To make your object turn towards the mouse, you need the ScreenToWorldSpace() method from your camera. In order to convert the ScreenCoordinates into your WorldCoordinates.
Example:
Please note:
You have to set the camera instance! If you don't add that, you'll get a NullReferenceException.
This Snippets shall only show the steps needed to achieve the behavior you wish.
You will have to find out yourself how to integrate that lines of code into your code to make it work. Consider what Programmer told you in the comment when integrating that.
Vector3 mousePosition = Input.mousePosition; //get the screenSpaceMousePosition
Vector3 worldPosition = this.camera.ScreenToWorldPoint(mousePosition); //convert it into worldSpacePosition
Vector3 calculatedDirection = worldPosition - transform.position; //calucate the looking direction
calculatedDirection.y = 0;
Quaternion rotation = Quaternion.LookRotation(calculatedDirection);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime);
Now it's rotating in space i can rotate the camera around but not around the player. I want the camera to be rotating only around the player.
using UnityEngine;
using System.Collections;
public class CameraMover : MonoBehaviour
{
public float speedH = 2.0f;
public float speedV = 2.0f;
private float yaw = 0.0f;
private float pitch = 0.0f;
public Transform playerTransform;
public Transform mainCameraTransform = null;
private Vector3 cameraOffset = Vector3.zero;
public float turnSpeed = 3;
void Start()
{
mainCameraTransform = Camera.main.transform;
//Get camera-player Transform Offset that will be used to move the camera
cameraOffset = mainCameraTransform.position - playerTransform.position;
}
void LateUpdate()
{
//Move the camera to the position of the playerTransform with the offset that was saved in the begining
mainCameraTransform.position = playerTransform.position + cameraOffset;
yaw += speedH * Input.GetAxis("Mouse X");
pitch -= speedV * Input.GetAxis("Mouse Y");
mainCameraTransform.eulerAngles = new Vector3(pitch, yaw, 0.0f);
}
}
I'm using now eulerAngles for the rotation.
As mentioned in the comments you need to create a parent object for the camera, and rotate that object instead of the camera. Try this code:
using UnityEngine;
using System.Collections;
public class CameraMover : MonoBehaviour
{
public float speedH = 2.0f;
public float speedV = 2.0f;
private float yaw = 0.0f;
private float pitch = 0.0f;
public Transform playerTransform;
public Transform mainCameraTransform = null;
private Vector3 cameraOffset = Vector3.zero;
public float turnSpeed = 3;
// Create a camera parent object
GameObject cameraParent;
void Start()
{
cameraParent = new GameObject();
mainCameraTransform = Camera.main.transform;
//Get camera-player Transform Offset that will be used to move the camera
cameraOffset = mainCameraTransform.position - playerTransform.position;
// Position the camera parent to the player and add the camera as a child
cameraParent.transform.position = playerTransform.position;
mainCameraTransform.parent = cameraParent.transform;
}
void LateUpdate()
{
//Move the camera to the position of the playerTransform with the offset that was saved in the begining
//mainCameraTransform.position = playerTransform.position + cameraOffset;
yaw += speedH * Input.GetAxis("Mouse X");
pitch -= speedV * Input.GetAxis("Mouse Y");
// Rotate the camera parent instead of the camera
cameraParent.transform.eulerAngles = new Vector3(pitch, yaw, 0.0f);
}
}