I lifted most of this code from a year-old unity thread. Whenever I run it, my camera goes running off in the negative z direction very quickly. I've been poking at the variables all day, but nothing is making it click for me.
The z changes by 5 units every frame, which is exactly what I have set for the camera distance. This seems like the key to understanding the issue. Part of my problem is that I only barely grasp moving objects around using transforms and Euler angles. Thank you for your time.
public GameObject cameraTarget = null;
public float cameraSpeedX = 120.0f; //x sensitivity
public float cameraSpeedY = 120.0f; //y sensitivity
public float cameraVelocityX = 0.0f;
public float cameraVelocityY = 0.0f;
public float cameraRotationX = 0.0f;
public float cameraRotationY = 0.0f;
public float cameraLimitMinY = -20f;
public float cameraLimitMaxY = 80f;
public float cameraDistance = 5.0f;
public float cameraDdistanceMin = 0.5f;
public float cameraDistanceMax = 15.0f;
// Use this for initialization
void Start () {
gameObject.AddComponent<MeshFilter>();
gameObject.AddComponent<MeshRenderer>();
Vector3 angles = transform.eulerAngles;
cameraRotationX = angles.x;
cameraRotationY = angles.y;
// Make the rigid body not change rotation
if(GetComponent<Rigidbody>()){GetComponent<Rigidbody>().freezeRotation = true;}
cameraTarget = gameObject;
}
void LateUpdate(){
if (cameraTarget){
if (Input.GetMouseButton(1)){
cameraVelocityX += cameraSpeedX * Input.GetAxis("Mouse X") * 0.02f;
cameraVelocityY += cameraSpeedY * Input.GetAxis("Mouse Y") * 0.02f;
}
cameraRotationY += cameraVelocityX;
cameraRotationX -= cameraVelocityY;
cameraRotationX = ClampAngle(cameraRotationX, cameraLimitMinY, cameraLimitMaxY);
//Quaternion fromRotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, 0);
Quaternion toRotation = Quaternion.Euler(cameraRotationX, cameraRotationY, 0);
Quaternion rotation = toRotation;
Vector3 negDistance = new Vector3(0.0f, 0.0f, -cameraDistance);
Vector3 position = rotation * negDistance + cameraTarget.transform.position;
transform.rotation = rotation;
transform.position = position;
cameraVelocityX = Mathf.Lerp(cameraVelocityX, 0, Time.deltaTime * 2.0f);
cameraVelocityY = Mathf.Lerp(cameraVelocityY, 0, Time.deltaTime * 2.0f);
print ("POSITION:"+transform.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);
}
For some reason I thought that putting the camera script and the game object generation in the same object was a good idea. The camera transforms were being applied to itself, which caused the camera to endlessly try to get behind itself. Thank you mprivat for your insight.
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.
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);
I have a camera that I want to rotate around a point (0,0,0) in all directions, but I want to put a clamp on it so that it can't go too far above or below the point. I have seen this question answered for the left and right directions before but never for the vertical one.
I have tried converting the code from these two questions (that basically say the same thing) to work in the vertical direction, but it bugs out at some points along the rotation, and I can't figure out why.
First Question, Second Question
And this is how I tried to convert it:
//how much we want to rotate by this frame
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed; //(before clamping)
//find current direction
Vector3 currentDirection = transform.position - Vector3.zero;
//find current angle between basis for clamp & where we are now
float angle = Vector3.Angle(Vector3.forward, currentDirection);
//finds out if it's up or down
if (Vector3.Cross(Vector3.forward, currentDirection).x < 0) angle = -angle;
//find out how much you can move without violating limits
float newAngle = Mathf.Clamp(angle + rotY, yMinLimit, yMaxLimit);
//grabs how much you are allowed to move the angle from the current angle
rotY = newAngle - angle;
//spinning the garden
transform.RotateAround(Vector3.zero, Vector3.up, rotX);
transform.RotateAround(Vector3.zero, transform.TransformDirection(Vector3.right), -rotY); //vertical rotation
If anyone knows of the correct way to make this work for the Y axis, or a different way to clamp the vertical rotation, I would be super excited to hear it! Ty!
I have a class here that do exactly what you want. It rotates a camera around a target and clamps the Y rotation. It uses the left button to rotate and the scroll press button to translate the target.
You can edit it to adjust to your specific needs - you might want to change the target to a Vector3 so you can set it to (0,0,0) without the need of an object. Hope it helps.
using UnityEngine;
public class RotateAroundCamera : MonoBehaviour
{
Camera cam;
public bool isControlable;
private Vector3 screenPoint;
private Vector3 offset;
public Transform target;
public float distance = 5.0f;
public float xSpeed = 50.0f;
public float ySpeed = 50.0f;
public float yMinLimit = -80f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
public float smoothTime = 2f;
public float rotationYAxis = 0.0f;
float rotationXAxis = 0.0f;
float velocityX = 0.0f;
float velocityY = 0.0f;
float moveDirection = -1;
public void SetControllable(bool value)
{
isControlable = value;
}
// Use this for initialization
void Start()
{
cam = GetComponentInChildren<Camera>();
Vector3 angles = transform.eulerAngles;
rotationYAxis = (rotationYAxis == 0) ? angles.y : rotationYAxis;
rotationXAxis = angles.x;
Rigidbody rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate()
{
if (target)
{
if (Input.GetMouseButton(1) && isControlable)
{
velocityX += xSpeed * Input.GetAxis("Mouse X") * 0.02f;
velocityY += ySpeed * Input.GetAxis("Mouse Y") * 0.02f;
}
if (Input.GetMouseButton(2) && isControlable)
{
Vector3 curScreenPoint = new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = cam.ScreenToWorldPoint(curScreenPoint) + offset;
target.transform.position = curPosition;
}
if (Input.GetKeyDown(KeyCode.R) && isControlable)
{
target.transform.position = Vector3.zero;
}
if (Input.GetKeyDown(KeyCode.T) && isControlable)
{
moveDirection *= -1;
}
if (isControlable)
{
distance -= Input.GetAxis("Mouse ScrollWheel");
if (distance > distanceMax)
{
distance = distanceMax;
}
else if (distance < distanceMin)
{
distance = distanceMin;
}
}
rotationYAxis += velocityX;
rotationXAxis -= velocityY;
rotationXAxis = ClampAngle(rotationXAxis, yMinLimit, yMaxLimit);
Quaternion fromRotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, 0);
Quaternion toRotation = Quaternion.Euler(rotationXAxis, rotationYAxis, 0);
Quaternion rotation = toRotation;
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + target.position;
transform.rotation = rotation;
transform.position = position;
velocityX = Mathf.Lerp(velocityX, 0, Time.deltaTime * smoothTime);
velocityY = Mathf.Lerp(velocityY, 0, Time.deltaTime * smoothTime);
screenPoint = cam.WorldToScreenPoint(target.transform.position);
offset = target.transform.position - cam.ScreenToWorldPoint(new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z));
}
}
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);
}
}
Here it is. I have a human anatomy, and I would like to rotate the camera when I touch anywhere. but looking at the human anatomy. how can I do that :(
[https://www.youtube.com/watch?v=EfYeL2FYyyA&t=148s] this is what exactly I really wanted to please help me !
`
using UnityEngine;
using System.Collections;
[AddComponentMenu("Camera-Control/Mouse Orbit with zoom")]
public class MouseOrbitImproved : 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;
// 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 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);
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);
}}
You could use a trick instead of using too many "math" in this case.
There will be empty gameObjects in each of the element you want your camera to rotate around, lets call those "anchors"
When the element is selected, you simply make the camera child of the anchor.
And then if you just rotate the anchor, your camera will rotate because it is the child.
This will get the effect you want.
Here is a simple example from youtube, for rotating the object.
Here is another one from Unity answers.
Hope this helps! Cheers!
I have made my own character in Unity, I'm working on the camera right now and I want to clamp the Y rotation of the Camera, while I'm doing this the correct way.
mouseRotY = Mathf.Clamp(mouseRotY, -90.0f, 90.0f);
So what just happens is that the camera is rotating from 359 to 0. Nothing happens until I move my mouse up when playing the game. It makes the screen look like it's flickering.
Here's my full code:
using UnityEngine;
using System.Collections;
public class FirstPersonController : MonoBehaviour {
CharacterController cc;
public float baseSpeed = 3.0f;
public float mouseSensitivity = 1.0f;
float mouseRotX = 0,
mouseRotY = 0;
public bool inverted = false;
float curSpeed = 3.0f;
string h = "Horizontal";
string v = "Vertical";
void Start () {
cc = gameObject.GetComponent<CharacterController>();
}
void FixedUpdate () {
curSpeed = baseSpeed;
mouseRotX = Input.GetAxis("Mouse X") * mouseSensitivity;
mouseRotY -= Input.GetAxis("Mouse Y") * mouseSensitivity;;
mouseRotY = Mathf.Clamp(mouseRotY, -90.0f, 90.0f);
if (!inverted)
mouseRotY *= -1;
else
mouseRotY *= 1;
float forwardMovement = Input.GetAxis(v);
float strafeMovement = Input.GetAxis(h);
Vector3 speed = new Vector3(strafeMovement * curSpeed, 0, forwardMovement * curSpeed);
speed = transform.rotation * speed;
cc.SimpleMove(speed);
transform.Rotate(0, mouseRotX, 0);
Camera.main.transform.localRotation = Quaternion.Euler(mouseRotY, 0 ,0);
}
}
If anyone of you could help me with this, that would be splendid. Thanks.
Your inverted logic is flawed, just take it out and it works. To invert the rotation you need to invert only the input and not the rotation itself every frame(it will just go from + to - and back to + again and so on). Here is a stripped down version for the y-rotation with inverted flag that works:
using UnityEngine;
using System.Collections;
public class FirstPersonController : MonoBehaviour
{
public float mouseSensitivity = 1.0f;
float mouseRotY = 0.0f;
public bool inverted = false;
private float invertedCorrection = 1.0f;
void FixedUpdate ()
{
if(Input.GetAxis ("Fire1") > 0.0f)
inverted = !inverted;
if(inverted)
invertedCorrection = -1.0f;
else
invertedCorrection = 1.0f;
mouseRotY -= invertedCorrection * Input.GetAxis("Mouse Y") * mouseSensitivity;
mouseRotY = Mathf.Clamp(mouseRotY, -90.0f, 90.0f);
Camera.main.transform.localRotation = Quaternion.Euler(mouseRotY, 0.0f, 0.0f);
}
}
another thing you might want to do is get the original rotation of the camera in your Start() function. The way it is now it sets the rotation to zero on the first frame. I cant tell from the script if this is the intended behaviour or not.