Unity 3D - How to use LateUpdate in Mouselook script? - c#

My build suffers from terrible stutter/lag when I cirle objects.
In this forum I have been advised to set the rigid body to "Interpolate" and to use LateUpdate in my script.
Problem is...I dont know how?
When I try, I get compiler error or just cant move the cam.
I found another free FPS script that worked, by using camera follow lag, but i cant figure out how to use that code either.
How can I use LateUpdate in my current script?
void Start() {
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
void Update() {
float x = Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime;
float y = Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime * -1f;
transform.Rotate(0f, x, 0f);
headRotation += y;
headRotation = Mathf.Clamp(headRotation, -headRotationLimit, headRotationLimit);
cam.localEulerAngles = new Vector3(headRotation, 0f, 0f);
}

Here is an edited version of my FPS player rotation method, use this as a guide for how it can be done and modify it for your needs including a couple of methods I use to limit how far the Camera can rotate (the player can look up and down)
// Set the Camera in the inspector so that it can be rotated
public Camera camera;
// Rotation variables for both the player and camera
private Quaternion _playerRotation;
private Quaternion _cameraRotation;
// The speed you want to be able to look
private float _lookSpeed = 3f;
// Set the initial rotations to the rotation variables
private void Awake()
{
_playerRotation = transform.localRotation;
_cameraRotation = camera.transform.localRotation;
}
// Method to be called from LateUpdate
private void UpdateRotation()
{
Vector2 input = new Vector2(
Input.GetAxis("Mouse X"),
Input.GetAxis("Mouse Y")
);
if (input != Vector2.zero)
{
_playerRotation *= Quaternion.Euler(0f, _lookSpeed * input.x, 0f);
_cameraRotation *= Quaternion.Euler(_lookSpeed * -input.y, 0f, 0f);
_cameraRotation = ClampRotationAroundXAxis(_cameraRotation, -50f , 75f);
}
transform.localRotation = Quaternion.Slerp(transform.localRotation, _playerRotation, 10f * Time.deltaTime);
camera.transform.localRotation = Quaternion.Slerp(camera.transform.localRotation, _cameraRotation, 10f * Time.deltaTime);
}
// A couple of rotation methods
// I suggest making these extensions for use anywhere in the game and for all rotations
private Quaternion ClampRotationAroundXAxis(Quaternion q, float minX = 0f, float maxX = 0f)
{
if (q.w != 0f)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1f;
}
q.y = 0f;
q.z = 0f;
if (minX != 0f || maxX != 0f)
{
q = ClampRotationXAxis(q, minX, maxX);
}
return q;
}
private Quaternion ClampRotationXAxis(Quaternion q, float min, float max)
{
if (q.w != 0f)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1f;
}
float angle = 2f * Mathf.Rad2Deg * Mathf.Atan(q.x);
angle = Mathf.Clamp(angle, min, max);
q.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angle);
return q;
}

Related

Problem with Mathf.Clamp and rotation in Unity

I have a problem with my camera movement. I want to limit my camera rotation, but I don't know how to do this. I searched for a solution, but I was not able to find one.
In my current code, my camera rotates rapidly in any direction and I don't know how to implement the Mathf.Clamp correctly.
Here is my code:
public float rightSpeed = 20.0f;
public float leftSpeed = -20.0f;
public float rotationLimit = 0.0f;
void Update()
{
//EdgeScrolling
float edgeSize = 40f;
if (Input.mousePosition.x > Screen.width - edgeSize)
{
//EdgeRight
transform.RotateAround(this.transform.position, Vector3.up, rotationLimit += rightSpeed * Time.deltaTime);
}
if (Input.mousePosition.x < edgeSize)
{
//EdgeLeft
transform.RotateAround(this.transform.position, Vector3.up, rotationLimit -= leftSpeed * Time.deltaTime);
}
rotationLimit = Mathf.Clamp(rotationLimit, 50f, 130f);
}
RotateAround method rotates by an angle. It doesn't assign the angle value you pass it. In this case I would suggest using a different approach. Instead of RotateAround method use the eulerAngles property and assign the rotation values directly.
Example
using UnityEngine;
public class TestScript : MonoBehaviour
{
public float rightSpeed = 20.0f;
public float leftSpeed = -20.0f;
private void Update()
{
float edgeSize = 40f;
if (Input.mousePosition.x > Screen.width - edgeSize)
RotateByY(rightSpeed * Time.deltaTime);
else if (Input.mousePosition.x < edgeSize)
RotateByY(leftSpeed * Time.deltaTime);
}
public void RotateByY(float angle)
{
float newAngle = transform.eulerAngles.y + angle;
transform.eulerAngles = new Vector3(
transform.eulerAngles.x,
Mathf.Clamp(newAngle, 50f, 130f),
transform.eulerAngles.z);
}
}

Unity rigidbody collision not working properly

Im having a lot of weird prolems with my rigidbody collision in unity. I have a player controller script which allows me to move my player, but when it collides with stairs, it glitches out. when it collides with a door, it glitches out and when it collides with 2 nvisible box colliders at the edge of the map while walking diagonally, it walks through one of them. Ive searched around quite a bit but couldn't find anything. I know it's not a lot to go on, but here is some stuff that might help:
a video of what happens exactly
the character controller code:
using System;
using UnityEngine;
public class PlayerController : MonoBehaviour{
public Rigidbody body;
//player movement
private float speed = 12f;
private float walkSpeed = 10;
private float runSpeed = 15;
private float gravity = -9.81f;
public float jumpHeight = 2f;
private Vector3 inputs;
//player rotation
private float targetAngle = 0f;
private float angle = 0f;
public float turnSmoothTime = .1f;
public float turnSmoothVelocity;
//player jump
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
private bool isGrounded;
//there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
public int direction = 1;
public void movePlayer(Vector2 movement){
float horizontal = movement.x;
float vertical = movement.y;
//check if the player is standing on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
Quaternion rotation = new Quaternion();
body.freezeRotation = true;
if (Mathf.Abs(direction) == 1){
//gravity in y direction
//set the direction of the gravity
Physics.gravity = new Vector3(0f, direction * gravity, 0f);
//set the direction the inputs should work in
inputs.x = horizontal;
inputs.z = vertical;
inputs.y = body.velocity.y;
//calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
//set the characters rotation
rotation = Quaternion.Euler(0f, angle, 0f);
}
else if (Mathf.Abs(direction) == 2){
//gravity in x direction
Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);
inputs.y = -horizontal;
inputs.z = vertical;
inputs.x = body.velocity.x;
targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;
rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
}
else if (Mathf.Abs(direction) == 3){
//gravity in z-direction
Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);
inputs.x = horizontal;
inputs.y = vertical;
inputs.z = body.velocity.z;
targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;
//set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
Quaternion.AngleAxis(0f, Vector3.forward) *
Quaternion.AngleAxis(targetAngle, Vector3.up);
}
else{
direction = 1;
}
/*
if (inputs != Vector3.zero){
body.velocity = inputs;
}*/
//rotate the player in the move direction as long as they are moving
if (inputs.magnitude >= 0.1f){
transform.rotation = rotation;
}
}
void FixedUpdate(){
//move the player
body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);
}
public void flip(int changedDirection){
inputs = Vector3.zero;
angle = 0f;
targetAngle = 0f;
direction = changedDirection;
}
public void walk(){
if (isGrounded){
speed = walkSpeed;
}
}
public void run(){
if (isGrounded){
speed = runSpeed;
}
}
public void jump(){
if (isGrounded){
if (direction == 1){
body.velocity = new Vector3(inputs.x, jumpHeight, inputs.z);
}
else if (direction == 2){
body.velocity = new Vector3(jumpHeight, inputs.y, inputs.z);
}
else if (direction == 3){
body.velocity = new Vector3(inputs.x, inputs.y, jumpHeight);
}
}
}
}
A screenshot of my player object's important components:
P.S. the code has some weird gravty changing parts. Thats for the rest of the game, but it's not important for this question. Hopefully you guys can help me. Im happy to provide any other information you might need :) thanks for your time in advance!!
Edit: Commented out one part based on the first answer, but that din't fix it
First of all, you move your player 'twice', first inside movePlayer function you have:
//move the player
if (inputs != Vector3.zero){
body.velocity = inputs;
}
and then in every FixedUpdate:
body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);
body.MovePosition moves yours player, but not zeroes velocity (which you set in movePlayer function).
By moving player this way you can 'overshoot' too small colider, so object will pass through.
You can add more drag to rigidbody to slowdown object a bit.
Okay so for anyone having similar problems, I found the answer:
The problem was that I was using body.moveposition, this should actually body.addforce.
This oes mean that you have to change some of the code. If you want further explanation because you had a similar problem, contact me, but here is my improved code to get you started:
using System;
using UnityEngine;
public class PlayerController : MonoBehaviour{
public Rigidbody body;
//player movement
private float speed = 12f;
private float walkSpeed = 10;
private float runSpeed = 15;
public float gravity = -9.81f;
public float jumpHeight = 2f;
private Vector3 inputs;
//player rotation
private float targetAngle = 0f;
private float angle = 0f;
public float turnSmoothTime = .1f;
public float turnSmoothVelocity;
//player jump
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
private bool isGrounded;
//there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
public int direction = 1;
public void movePlayer(Vector2 movement){
float horizontal = movement.x;
float vertical = movement.y;
//check if the player is standing on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
Quaternion rotation = new Quaternion();
body.freezeRotation = true;
if (Mathf.Abs(direction) == 1){
//gravity in y direction
//set the direction of the gravity
Physics.gravity = new Vector3(0f, direction * gravity, 0f);
//set the direction the inputs should work in
inputs.x = horizontal;
inputs.z = vertical;
inputs.y = 0;
//calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
//set the characters rotation
rotation = Quaternion.Euler(0f, angle, 0f);
}
else if (Mathf.Abs(direction) == 2){
//gravity in x direction
Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);
inputs.y = -horizontal;
inputs.z = vertical;
inputs.x = body.velocity.x;
targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;
rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
}
else if (Mathf.Abs(direction) == 3){
//gravity in z-direction
Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);
inputs.x = horizontal;
inputs.y = vertical;
inputs.z = body.velocity.z;
targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;
//set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
Quaternion.AngleAxis(0f, Vector3.forward) *
Quaternion.AngleAxis(targetAngle, Vector3.up);
}
else{
direction = 1;
}
//rotate the player in the move direction as long as they are moving
if (inputs.magnitude >= 0.1f){
transform.rotation = rotation;
}
}
void FixedUpdate(){
body.AddForce(inputs * speed * Time.fixedDeltaTime);
}
public void flip(int changedDirection){
inputs = Vector3.zero;
angle = 0f;
targetAngle = 0f;
direction = changedDirection;
}
public void walk(){
if (isGrounded){
speed = walkSpeed;
}
}
public void run(){
if (isGrounded){
speed = runSpeed;
}
}
public void jump(){
if (isGrounded){
if (direction == 1){
body.AddForce(new Vector3(0, jumpHeight, 0));
}
else if (direction == 2){
body.AddForce(new Vector3(jumpHeight, 0, 0));
}
else if (direction == 3){
body.AddForce(new Vector3(0,0 , jumpHeight));
}
}
}
}
For me this created some additionl problems with jump for example, so here are the values you need to tweak to fix those: the rigidbody mass and drag and the player controller gravity and jump height.

Auto leveling 6DOF Unity

I developing an 6DOF game. I have some problems with the auto leveling (so the ship will always goes horizontal). The auto leveling worked, but I can't turn anymore on the x-axis more than 90 degrees. The spaceship must fly free in any direction. I hope someone can help me.
// Update is called once per frame
void Update()
{
yaw = Input.GetAxis("Mouse X") * speed;
pitch = Input.GetAxis("Mouse Y") * speed;
roll = Input.GetAxis("Roll") * speed;
float ver = 0;
float up = 0;
float hor = 0;
up = Input.GetAxis("Up");
hor = Input.GetAxis("Horizontal");
ver = Input.GetAxis("Vertical");
ver *= speed * Time.deltaTime;
up *= speed * Time.deltaTime;
hor *= speed * Time.deltaTime;
transform.Rotate(Vector3.up, yaw);
transform.Rotate(Vector3.left, pitch);
transform.Rotate(Vector3.forward, -roll);
Vector3 cross = Vector3.Cross(Vector3.up, transform.forward);
Quaternion rotator = Quaternion.FromToRotation(transform.right, cross)
// Apply rotation
transform.rotation = Quaternion.Slerp(transform.rotation, rotator * transform.rotation, Time.deltaTime);
transform.Translate(hor, up, ver);
}
As requested in comments (note: untested):
void Update() {
var yaw = Input.GetAxis("Mouse X");
var pitch = Input.GetAxis("Mouse Y");
var roll = Input.GetAxis("Roll");
var up = Input.GetAxis("Up"); // better name is 'heave' (up/down)
var hor = Input.GetAxis("Horizontal"); // better name is 'sway' (left/right)
var ver = Input.GetAxis("Vertical"); // better name is 'surge' (forward/back)
// If no rotation input, then 'auto-correct' for roll (up direction)
if ( Mathf.Approximately(yaw + pitch + roll, 0)) {
// Find what the 'up' rotation is
var levelRotation = Quaternion.LookRotation(transform.forward, Vector3.up);
// Apply it over time (Limit the angular change with Time.deltaTime)
transform.rotation = Quaternion.RotateTowards(transform.rotation, levelRotation, Speed * Time.deltaTime);
}
// Else there IS input rotation, so deal with that instead.
else {
// Scale inputs for speed (rotation speed should probably be different from translation speed)
yaw *= Speed * Time.deltaTime;
pitch *= Speed * Time.deltaTime;
roll *= Speed * Time.deltaTime;
var rotation = Quaternion.Euler(yaw, pitch, roll);
transform.rotation *= rotation;
}
// Acale and apply translation
ver *= speed * Time.deltaTime;
up *= speed * Time.deltaTime;
hor *= speed * Time.deltaTime;
transform.Translate(hor, up, ver);
}

Clamp LookAtMouse Z Rotation

I have an object that looks at mouse position, but it has no limits. For example, if the object's rotation is greater than 40 or less -40 then it does not rotate.
public class GunController : MonoBehaviour
{
public float maxTop, minBottom;
void Update()
{
var pos = Camera.main.WorldToScreenPoint(transform.position);
var dir = Input.mousePosition - pos;
var angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
}
This is a little function I use to clamp the rotation in an FPS up/down aim rotation.
You can modify it for your usage.
Quaternion ClampRotationAroundXAxis(Quaternion q)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;
float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan(q.x);
angleX = Mathf.Clamp(angleX, -90f, 90f);
q.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleX);
return q;
}

Zoom camera in/out with Mouse Scrollwheel via the transform instead of fov?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseOrbit : MonoBehaviour {
public Transform target;
public float distance = 5.0f;
public float xSpeed = 120.0f;
public float ySpeed = 120.0f;
public float yMinLimit = -20f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
private Rigidbody rigidbody;
float x = 0.0f;
float y = 0.0f;
float minFov = 15f;
float maxFov = 90f;
float sensitivity = 10f;
// Use this for initialization
void Start()
{
Vector3 angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody != null)
{
rigidbody.freezeRotation = true;
}
}
void Update()
{
// Updating camera distance on every frame
distance = RayCast3.distance3;
//Setting maximum distance so the camera doesnt go too far
if (distance > 2)
{
distance = 2;
}
}
void LateUpdate()
{
if (target)
{
x += Input.GetAxis("Mouse X") * xSpeed * distance * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
y = ClampAngle(y, yMinLimit, yMaxLimit);
Quaternion rotation = Quaternion.Euler(y, x, 0);
//distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel") * 5, distanceMin, distanceMax);
//distance += Input.GetAxis("Mouse ScrollWheel") * sensitivity;
float fov = Camera.main.fieldOfView;
fov += Input.GetAxis("Mouse ScrollWheel") * sensitivity;
fov = Mathf.Clamp(fov, minFov, maxFov);
Camera.main.fieldOfView = fov;
RaycastHit hit;
if (Physics.Linecast(target.position, transform.position, out hit))
{
distance -= hit.distance;
}
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + target.position;
transform.rotation = rotation;
transform.position = position;
}
}
public static float ClampAngle(float angle, float min, float max)
{
if (angle < -360F)
angle += 360F;
if (angle > 360F)
angle -= 360F;
return Mathf.Clamp(angle, min, max);
}
}
Now i'm using fov:
And it's working fine.
float fov = Camera.main.fieldOfView;
fov += Input.GetAxis("Mouse ScrollWheel") * sensitivity;
fov = Mathf.Clamp(fov, minFov, maxFov);
Camera.main.fieldOfView = fov;
But now i want to use the distance variable and not fov.
So i tried first the line:
distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel") * 5, distanceMin, distanceMax);
It didn't work so i tried the line:
distance += Input.GetAxis("Mouse ScrollWheel") * sensitivity;
But in both lines the character is stuttering and it's not zooming in out with the mouse wheel.
It's really simple. Get mouse scroll wheel speed then multiply it by some speed value. You can also multiply it by Time.deltaTime if you want. Finally use transform.Translate to move the camera with that value.
This will move in z-axis:
private float zoomSpeed = 2.0f;
void Update()
{
float scroll = Input.GetAxis("Mouse ScrollWheel");
transform.Translate(0, 0, scroll * zoomSpeed, Space.World);
}
Or where camera is facing:
private float zoomSpeed = 5.0f;
void Update()
{
float scroll = Input.GetAxis("Mouse ScrollWheel");
transform.position += this.transform.forward * scroll * zoomSpeed;
}
You should calculate a delta between your camera point and your target point. Normalize it and multiply it with the scrollwheel delta. Add this on your camera position. I used the camera target as angle to zoom-in.
Pseudo:
var delta = cameraTarget - cameraPosition;
delta.Normalize();
cameraPosition += delta * ScrollWheel.delta * sensitivity;
// you can even move your cameraTarget in the same direction
cameraTarget += delta * ScrollWheel.delta * sensitivity;
You can use the distance instead of calculating a delta.

Categories

Resources