I’m trying to make a simple camera in the same format as the editor camera - where you right-click to rotate, and move freely (relative to your facing direction) with WASD. I haven’t been able to find this in the standard assets at all.
The camera and movement are working. However the movement is very jerky. Now, I can attempt to fix this with a Lerp. But for some reason this causes the camera to spin around rapidly. I can set the Lerp parameter t lower, but it still does the spinning and is too slow.
See attached script. You can create a new project, create an empty GameObject, set the main Camera as its child (zero the transforms and rotations), and then attach the script. Should work and show the problem. Create a Terrain or something to have something to see it by.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using UnityStandardAssets.Utility;
public class CameraControl : MonoBehaviour
{
public float XSensitivity = 10f;
public float YSensitivity = 10f;
public float movementSpeed = 1f;
public float MinimumX = -90F;
public float MaximumX = 90F;
public bool smooth;
public float smoothTime = 5f;
private Camera camera;
private Quaternion cameraRot;
private Vector3 euler;
GameObject parent;
// Use this for initialization
void Start () {
parent = this.transform.parent.gameObject;
camera = Camera.main;
Init();
}
// Update is called once per frame
void Update () {
}
public void Init()
{
cameraRot = camera.transform.localRotation;
}
private void FixedUpdate()
{
if (Input.GetKey(KeyCode.W))
{
parent.transform.position = new Vector3(parent.transform.position.x + (parent.transform.forward.x * movementSpeed), parent.transform.position.y + (parent.transform.forward.y * movementSpeed), parent.transform.position.z + (parent.transform.forward.z * movementSpeed));
}
if (Input.GetKey(KeyCode.S))
{
parent.transform.position = new Vector3(parent.transform.position.x - (parent.transform.forward.x * movementSpeed), parent.transform.position.y - (parent.transform.forward.y * movementSpeed), parent.transform.position.z - (parent.transform.forward.z * movementSpeed));
}
if (Input.GetKey(KeyCode.A))
{
parent.transform.position = new Vector3(parent.transform.position.x - (parent.transform.right.x * movementSpeed), parent.transform.position.y - (parent.transform.right.y * movementSpeed), parent.transform.position.z - (parent.transform.right.z * movementSpeed));
}
if (Input.GetKey(KeyCode.D))
{
parent.transform.position = new Vector3(parent.transform.position.x + (parent.transform.right.x * movementSpeed), parent.transform.position.y + (parent.transform.right.y * movementSpeed), parent.transform.position.z + (parent.transform.right.z * movementSpeed));
}
if(Input.GetMouseButton(1))
{
RotateView();
}
}
private void RotateView()
{
float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity;
euler.y += yRot;
cameraRot *= Quaternion.Euler(-xRot, 0, 0);
if (smooth == true)
{
parent.transform.eulerAngles = Vector3.Lerp(parent.transform.eulerAngles, euler, 0.03f);
camera.transform.localRotation = Quaternion.Lerp(camera.transform.localRotation, cameraRot, 0.03f);
}
else
{
parent.transform.eulerAngles = euler;
camera.transform.localRotation = cameraRot;
}
}
}
@jexmatex until your code, i didn’t even notice OP wasn’t using deltatime. Perhaps thats why he’s using FixedUpdate(), but even that your code use deltatime, shouldn’t this (camera movement) be handled in LateUpdate()?
I tried this. Commented out all of FixedUpdate. It works, but unfortunately when one moves the camera with WASD it changes the height, which did not happen in my previous script.
I switched to my movement part in FixedUpdate, commenting out the else statement above, and then changed it to transform the camera instead of the parent. It does the same thing as with the else statement (changing height). But if I change it back to transform the parent, and then change the X rotation in the above, it kind of works, but unfortunately moving at all in the Y direction causes the camera to start moving, so if you release the button then press it again, it maintains the motion.
I’m going to try removing all this and adding MouseLook.
So I probably could have gotten it working with the previous suggestion, but it was just too much fiddly stuff I don’t have a whole bunch of experience with. I’ve added a SimpleMouseRotator to the Camera and gotten rid of the cube completely. I put a modified version of my WASD movement in. It doesn’t have zooming (based on mouse wheel scroll) yet, I plan to add that, but here it is if anyone’s interested.
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
namespace UnityStandardAssets.Utility
{
public class SimpleMouseRotator : MonoBehaviour
{
// A mouselook behaviour with constraints which operate relative to
// this gameobject's initial rotation.
// Only rotates around local X and Y.
// Works in local coordinates, so if this object is parented
// to another moving gameobject, its local constraints will
// operate correctly
// (Think: looking out the side window of a car, or a gun turret
// on a moving spaceship with a limited angular range)
// to have no constraints on an axis, set the rotationRange to 360 or greater.
public Vector2 rotationRange = new Vector3(90, 361);
public float rotationSpeed = 10;
public float dampingTime = 0.2f;
public bool autoZeroVerticalOnMobile = true;
public bool autoZeroHorizontalOnMobile = false;
public bool relative = true;
private Vector3 m_TargetAngles;
private Vector3 m_FollowAngles;
private Vector3 m_FollowVelocity;
private Quaternion m_OriginalRotation;
public float movementSpeed = 30f;
private void Start()
{
m_OriginalRotation = transform.localRotation;
}
private void Update()
{
if (Input.GetMouseButton(1))
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
// we make initial calculations from the original local rotation
transform.localRotation = m_OriginalRotation;
// read input from mouse or mobile controls
float inputH;
float inputV;
if (relative)
{
inputH = CrossPlatformInputManager.GetAxis("Mouse X");
inputV = CrossPlatformInputManager.GetAxis("Mouse Y");
// wrap values to avoid springing quickly the wrong way from positive to negative
if (m_TargetAngles.y > 180)
{
m_TargetAngles.y -= 360;
m_FollowAngles.y -= 360;
}
if (m_TargetAngles.x > 180)
{
m_TargetAngles.x -= 360;
m_FollowAngles.x -= 360;
}
if (m_TargetAngles.y < -180)
{
m_TargetAngles.y += 360;
m_FollowAngles.y += 360;
}
if (m_TargetAngles.x < -180)
{
m_TargetAngles.x += 360;
m_FollowAngles.x += 360;
}
#if MOBILE_INPUT
// on mobile, sometimes we want input mapped directly to tilt value,
// so it springs back automatically when the look input is released.
if (autoZeroHorizontalOnMobile) {
m_TargetAngles.y = Mathf.Lerp (-rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH * .5f + .5f);
} else {
m_TargetAngles.y += inputH * rotationSpeed;
}
if (autoZeroVerticalOnMobile) {
m_TargetAngles.x = Mathf.Lerp (-rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV * .5f + .5f);
} else {
m_TargetAngles.x += inputV * rotationSpeed;
}
#else
// with mouse input, we have direct control with no springback required.
m_TargetAngles.y += inputH * rotationSpeed;
m_TargetAngles.x += inputV * rotationSpeed;
#endif
// clamp values to allowed range
m_TargetAngles.y = Mathf.Clamp(m_TargetAngles.y, -rotationRange.y * 0.5f, rotationRange.y * 0.5f);
//Consider changing negative to greater ratio and positive to lower ratio. Why should players look into the sky?
m_TargetAngles.x = Mathf.Clamp(m_TargetAngles.x, -rotationRange.x * 0.5f, rotationRange.x * 0.5f);
}
else
{
inputH = Input.mousePosition.x;
inputV = Input.mousePosition.y;
// set values to allowed range
m_TargetAngles.y = Mathf.Lerp(-rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH / Screen.width);
m_TargetAngles.x = Mathf.Lerp(-rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV / Screen.height);
}
// smoothly interpolate current values to target angles
m_FollowAngles = Vector3.SmoothDamp(m_FollowAngles, m_TargetAngles, ref m_FollowVelocity, dampingTime);
// update the actual gameobject's rotation
transform.localRotation = m_OriginalRotation * Quaternion.Euler(-m_FollowAngles.x, m_FollowAngles.y, 0);
}
else
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
if (Input.GetKey(KeyCode.W))
{
this.transform.position = new Vector3(this.transform.position.x + (this.transform.forward.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z + (this.transform.forward.z * movementSpeed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.S))
{
this.transform.position = new Vector3(this.transform.position.x - (this.transform.forward.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z - (this.transform.forward.z * movementSpeed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.A))
{
this.transform.position = new Vector3(this.transform.position.x - (this.transform.right.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z - (this.transform.right.z * movementSpeed * Time.deltaTime));
}
if (Input.GetKey(KeyCode.D))
{
this.transform.position = new Vector3(this.transform.position.x + (this.transform.right.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z + (this.transform.right.z * movementSpeed * Time.deltaTime));
}
}
}
}