FPS camera with y-axis limit to certain angle - c#

I am starting a new game and right now my player can view 360* but I want to limit how far the player looks up in the sky and down (straight up and down).
Here's my code
Vector2 mouseLook;
Vector2 smoothV;
public float sensitivity = 5.0f;
public float smoothing = 2.0f;
GameObject player;
void Start () {
player = this.transform.parent.gameObject;
}
// Update is called once per frame
void Update () {
var md = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
md = Vector2.Scale(md, new Vector2(sensitivity * smoothing, sensitivity * smoothing));
smoothV.x = Mathf.Lerp(smoothV.x, md.x, 1f / smoothing);
smoothV.y = Mathf.Lerp(smoothV.y, md.y, 1f / smoothing);
mouseLook += smoothV;
transform.localRotation = Quaternion.AngleAxis(-mouseLook.y, Vector3.right);
player.transform.localRotation = Quaternion.AngleAxis(mouseLook.x, player.transform.up);
}
}

You have to use Mathf.Clamp to do this. Below is what I use to rotate the camera up/down and left/right. You can modify the yMaxLimit and yMinLimit variables to the angles you want to limit it to. There should be no limit while moving in the x direction.
public float xMoveThreshold = 1000.0f;
public float yMoveThreshold = 1000.0f;
public float yMaxLimit = 45.0f;
public float yMinLimit = -45.0f;
float yRotCounter = 0.0f;
float xRotCounter = 0.0f;
Transform player;
void Start()
{
player = Camera.main.transform;
}
// Update is called once per frame
void Update()
{
xRotCounter += Input.GetAxis("Mouse X") * xMoveThreshold * Time.deltaTime;
yRotCounter += Input.GetAxis("Mouse Y") * yMoveThreshold * Time.deltaTime;
yRotCounter = Mathf.Clamp(yRotCounter, yMinLimit, yMaxLimit);
//xRotCounter = xRotCounter % 360;//Optional
player.localEulerAngles = new Vector3(-yRotCounter, xRotCounter, 0);
}

Related

Why do objects stutter while I move and the camera is rotating?

I have began developing an fps script and followed a tutorial to help with the script. Everything works great now but the only issue is any objects in the view seem to stutter whenever the player is moving and rotating at the same time.
The script for the player's movement and camera rotation is below.
Can anybody point me in the right direction?
Thank you.
{
public Transform cam;
public Rigidbody rb;
public float camRotationSpeed = 5f;
public float camMinimumY = -60f;
public float camMaximumY = 75f;
public float rotationSmoothSpeed = 10f;
public float walkSpeed = 9f;
public float runSpeed = 14f;
public float maxSpeed = 20f;
public float jumpPower = 30f;
public float extraGravity = 45;
float bodyRotationX;
float camRotationY;
Vector3 directionIntentX;
Vector3 directionIntentY;
float speed;
public bool grounded;
void Update()
{
LookRotation();
Movement();
ExtraGravity();
GroundCheck();
if(grounded && Input.GetButtonDown("Jump"))
{
Jump();
}
}
void LookRotation()
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
bodyRotationX += Input.GetAxis("Mouse X") * camRotationSpeed;
camRotationY += Input.GetAxis("Mouse Y") * camRotationSpeed;
camRotationY = Mathf.Clamp(camRotationY, camMinimumY, camMaximumY);
Quaternion camTargetRotation = Quaternion.Euler(-camRotationY, 0, 0);
Quaternion bodyTargetRotation = Quaternion.Euler(0, bodyRotationX, 0);
transform.rotation = Quaternion.Lerp(transform.rotation, bodyTargetRotation, Time.deltaTime * rotationSmoothSpeed);
cam.localRotation = Quaternion.Lerp(cam.localRotation, camTargetRotation, Time.deltaTime * rotationSmoothSpeed);
}
void Movement()
{
directionIntentX = cam.right;
directionIntentX.y = 0;
directionIntentX.Normalize();
directionIntentY = cam.forward;
directionIntentY.y = 0;
directionIntentY.Normalize();
rb.velocity = directionIntentY * Input.GetAxis("Vertical") * speed + directionIntentX * Input.GetAxis("Horizontal") * speed + Vector3.up * rb.velocity.y;
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = runSpeed;
}
if (!Input.GetKey(KeyCode.LeftShift))
{
speed = walkSpeed;
}
}
void ExtraGravity()
{
rb.AddForce(Vector3.down * extraGravity);
}
void GroundCheck()
{
RaycastHit groundHit;
grounded = Physics.Raycast(transform.position, -transform.up, out groundHit, 1.25f);
}
void Jump()
{
rb.AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
}
}
This probably happens because the frame needs to update the camera rotation and the player position at the same time. i would suggest doing the rotation of the camera in fixed update. because this will run at the end of each frame.
like this:
void FixedUpdate()
{
LookRotation();
}
another thing i would suggest is to move the player while the groundcheck is being ran, because if you do it seperately i can see a bug coming up when the player moves faster then the code can run or something. so a tip would be or to run it inside the movement method, or call the method while you are calling the movement method.
this:
void Movement()
{
directionIntentX = cam.right;
directionIntentX.y = 0;
directionIntentX.Normalize();
directionIntentY = cam.forward;
directionIntentY.y = 0;
directionIntentY.Normalize();
rb.velocity = directionIntentY * Input.GetAxis("Vertical") * speed + directionIntentX * Input.GetAxis("Horizontal") * speed + Vector3.up * rb.velocity.y;
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = runSpeed;
}
if (!Input.GetKey(KeyCode.LeftShift))
{
speed = walkSpeed;
}
GroundCheck();
}
or litteraly copy and paste the code within your movement method.

Limit Player Rotation Up and Down

I have the basic movement and rotation working however I can not work out a way to limit the rotation up and down. I want to make it so that you cant look more than 90° up and down.
Ive tried multiple ways such as using if statments and using clamp.
using UnityEngine;
public class FPSController : MonoBehaviour {
public float speed = 5f;
public float sensitivity = 2f;
public GameObject Camera;
CharacterController controller;
float moveFB;
float moveLR;
public float rotX;
public float rotY;
void Start()
{
controller = GetComponent<CharacterController>();
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void FixedUpdate ()
{
moveFB = Input.GetAxis("Vertical");
moveLR = Input.GetAxis("Horizontal");
rotX = Input.GetAxis("Mouse X") * sensitivity;
rotY = Input.GetAxis("Mouse Y") * sensitivity;
transform.Rotate(0, rotX, 0);
Vector3 movement = new Vector3(moveLR * speed * Time.deltaTime, 0, moveFB * speed * Time.deltaTime);
controller.Move(transform.rotation * movement);
Camera.transform.Rotate(-rotY, 0, 0);
}
}
With this code you will be able to rotate the camera beyond 90 degrees causing it to be upside down etc
"Camera" is a built-in unity class, I would recommend renaming it to "camera".
Try this to clamp the camera's rotation:
(with your other public floats)
public float minAngle = -90;
public float maxAngle = 90;
(at the end of FixedUpdate)
Vector3 temp = camera.transform.localEulerAngles;
camera.transform.localEulerAngles = new Vector3(Mathf.Clamp(Mathf.DeltaAngle(0, temp.x), minAngle, maxAngle), temp.y, temp.z);
Edit: changed eulerAngles to localEulerAngles
Edit 2: changed the order of the arguements of Mathf.DeltaAngle
I fixed it here. Not to sure on how it works but it works. Credit to video:https://www.youtube.com/watch?v=F5eE1YL1ZJY
using UnityEngine;
public class FPSController : MonoBehaviour {
public float speed = 5f;
public float sensitivity = 2f;
public GameObject Camera;
CharacterController controller;
float moveFB;
float moveLR;
public float rotX;
public float rotY;
public float minAngle = -90f;
public float maxAngle = 90f;
void Start()
{
controller = GetComponent<CharacterController>();
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void FixedUpdate ()
{
moveFB = Input.GetAxis("Vertical");
moveLR = Input.GetAxis("Horizontal");
rotX = Input.GetAxis("Mouse X") * sensitivity;
rotY -= Input.GetAxis("Mouse Y") * sensitivity;
rotY = Mathf.Clamp(rotY, minAngle, maxAngle);
transform.Rotate(0, rotX, 0);
Vector3 movement = new Vector3(moveLR * speed * Time.deltaTime, 0, moveFB * speed * Time.deltaTime);
controller.Move(transform.rotation * movement);
Camera.transform.localRotation = Quaternion.Euler(rotY, 0, 0);
}
}

Unity Player Controller - how to make it so it doesn't go upside down

This is my CamMouseLook script and I need it so when the player moves the mouse all the way up it doesnt turn upside down. I want him to be able to look up just not so much up that it turns the view upside down
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CamMouseLook : MonoBehaviour {
Vector2 mouseLook;
Vector2 smoothV;
public float sensitivity = 5.0f;
public float smoothing = 2.0f;
GameObject character;
// Use this for initialization
void Start () {
character = this.transform.parent.gameObject;
}
// Update is called once per frame
void Update () {
var md = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
md = Vector2.Scale(md, new Vector2(sensitivity * smoothing, sensitivity * smoothing));
smoothV.x = Mathf.Lerp(smoothV.x, md.x, 1f / smoothing);
smoothV.y = Mathf.Lerp(smoothV.y, md.y, 1f / smoothing);
mouseLook += smoothV;
transform.localRotation = Quaternion.AngleAxis(-mouseLook.y, Vector3.right);
character.transform.localRotation = Quaternion.AngleAxis(mouseLook.x, character.transform.up);
}
}
What you can do is to lock the rotation in a specific axis. For example to limit in the Y and X axis so the player can only rotate from [-60,60] degrees you can use:
using System;
using UnityEngine;
public class MouseLook : MonoBehaviour
{
public float mouseSensitivity = 70.0f;
public float clampAngle = 60.0f;
private float rotY = 0.0f; // rotation around the up/y axis
private float rotX = 0.0f; // rotation around the right/x axis
void Start ()
{
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;
}
}
Now you can adapt this script to limit the rotation in the angle and the range you need

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.

Smoothing Vector3.normalized?

I have created a player inside of Unity 3D with a Character Controller, I got him all configured to walk, look around and such. So when using a normal vector3 the player starts of smoothly until it's at his max speed. When I don't normalize it, you can walk faster by pressing W and D/A at the same time, you go about 50% faster than normal. But when I normalize it, the player is immediately at it's max speed. Which looks very weird.
How would I do it so the player starts smoothed out before it's at it max speed?
Here's my full script, incase you need it:
using UnityEngine;
using System.Collections;
public class FirstPersonController : MonoBehaviour {
CharacterController cc;
public float baseSpeed = 3.0f;
public float mouseSensitivity = 1.0f;
public bool inverted = false;
public bool gravityOn = true;
public bool lockMouse = true;
float mouseRotX = 0,
mouseRotY = 0;
float curSpeed = 3.0f;
float invertion = 1.0f;
float gravitySpeed = 0;
string h = "Horizontal";
string v = "Vertical";
void Start () {
cc = gameObject.GetComponent<CharacterController>();
if (lockMouse && Debug.isDebugBuild)
Screen.lockCursor = true;
if (!Debug.isDebugBuild)
Screen.lockCursor = true;
}
void FixedUpdate () {
curSpeed = baseSpeed;
if (inverted)
invertion = -1.0f;
else
invertion = 1.0f;
mouseRotX = Input.GetAxis("Mouse X") * mouseSensitivity;
mouseRotY -= invertion * Input.GetAxis("Mouse Y") * mouseSensitivity;;
mouseRotY = Mathf.Clamp(mouseRotY, -90.0f, 90.0f);
float forwardMovement = Input.GetAxis(v);
float strafeMovement = Input.GetAxis(h);
Vector3 speed = new Vector3(strafeMovement, 0, forwardMovement);
speed = transform.rotation * speed;
Debug.Log(speed.normalized);
//Applying Gravity
if (cc.isGrounded)
{
gravitySpeed = 0.0f;
}
else if (gravityOn)
{
if (gravitySpeed >= 20.0f)
{
gravitySpeed = 20.0f;
}
if (cc.isGrounded == false)
{
gravitySpeed += Physics.gravity.y * Time.deltaTime;
}
cc.Move(new Vector3(0, gravitySpeed, 0) * Time.deltaTime);
}
//Applying movement and rotation.
cc.Move(speed.normalized * curSpeed * Time.deltaTime);
transform.Rotate(0, mouseRotX, 0);
Camera.main.transform.localRotation = Quaternion.Euler(mouseRotY, 0 ,0);
}
}
The feature you want to get is uniformly accelerated motion.
You need something like this:
Vector3 _speed = Vector3.zero;
const float KDrag = 0.25f;
void FixedUpdate ()
{
float forwardMovement = Input.GetAxis(v);
float strafeMovement = Input.GetAxis(h);
Vector3 acceleration = cc.transform.right * strafeMovement + cc.transform.forward * forwardMovement;
_speed += acceleration * Time.fixedDeltaTime;
_speed -= _speed * KDrag * Time.fixedDeltaTime;
cc.Move( _speed * Time.fixedDeltaTime );
}

Categories

Resources