Unity3d - Camera rotation smoothing 'bug' - c#

I made a simple racing game. The camera follows the car (player) and its position and rotation is based on car's Y rotation. I want to smooth the camera rotation, but when it crosses 0 degree point, it rotates 360 degrees.
Here's the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Camera : MonoBehaviour {
public Transform camera, player;
void Update() {
Vector3 cameraPosition = camera.transform.position;
float cameraRotation = camera.eulerAngles.y;
float playerRotation = player.eulerAngles.y;
Vector3 playerPosition = player.transform.position;
cameraPosition.x = (Mathf.Sin((playerRotation / 180) * Mathf.PI) * -6 + player.position.x);
cameraPosition.y = playerPosition.y + 2.5f;
cameraPosition.z = (Mathf.Cos((playerRotation / 180) * Mathf.PI) * -6 + player.position.z);
camera.transform.position = cameraPosition;
cameraRotation = cameraRotation + (playerRotation-cameraRotation)/2;
camera.localRotation = Quaternion.Euler(20f, cameraRotation, 0f);
}
}
I figured out that this rotation is caused by smoothing script:
cameraRotation = cameraRotation + (playerRotation-cameraRotation)/2;
How to prevent this unwanted rotation?

This is how I would do it:
public int smoothSpeed = 1f; // Change accordingly to increase/decrease smooth speed.
Then in update:
Vector3 directionToCar = player.position - camera.position;
Quaternion desiredRotation = Quaternion.LookRotation(directionToCar);
camera.rotation = Quaternion.Slerp(camera.rotation, desiredRotation, Time.deltaTime * smoothSpeed);
On a side node, if this camera script is attached to the camera, you don't have to make a field referencing the camera's transform. You can simply do transform.position instead of camera.transform.position.

A simpler solution to using the Slerp is to use Mathf.SmoothDamp, which has a variant called Mathf.SmoothDampAngle which handles the looping correctly. I've also had success doing the wraparound by hand but its not a very rewarding experience
using UnityEngine;
public class RotFollow : MonoBehaviour
{
[SerializeField] Transform carTransform;
[SerializeField] float smoothTime = .4f;
float currentYAngle;
float targetYAngle;
float angleVel;
void Update()
{
targetYAngle = carTransform.rotation.eulerAngles.y;
currentYAngle = Mathf.SmoothDampAngle(currentYAngle, targetYAngle, ref angleVel, smoothTime);
transform.rotation = Quaternion.Euler(
transform.rotation.eulerAngles.x,
currentYAngle,
transform.rotation.eulerAngles.z);
}
}

Related

How to stop body from rotating around wrong axis in unity

I recently started on unity and I wanted to make simple movement which can be seen below.
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
//Variables
float speed = 5.0f;
public float turnSpeed = 4.0f;
public float moveSpeed = 2.0f;
public float minTurnAngle = -90.0f;
public float maxTurnAngle = 90.0f;
private float rotX;
//Other
Vector3 Char_velocity;
Rigidbody Physics;
void Start()
{
Physics = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
//Get axis on which we want to move
if (Input.GetButton("Vertical"))
{
//Creating vector which velocity is calculated based on vect3, speed and gets FPS compensation via fixed
//delta time
Char_velocity = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
Physics.MovePosition(transform.position + Char_velocity * speed * Time.fixedDeltaTime);
}
if (Input.GetButton("Horizontal"))
{
Char_velocity = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
Physics.MovePosition(transform.position + Char_velocity * speed * Time.deltaTime);
}
float y = Input.GetAxis("Mouse X") * turnSpeed;
rotX += Input.GetAxis("Mouse Y") * turnSpeed;
rotX = Mathf.Clamp(rotX, minTurnAngle, maxTurnAngle);
transform.eulerAngles = new Vector2(-rotX, transform.eulerAngles.y + y);
}
}
Mouse movement has been the problem for me. I got it to somewhat work but I have 2 issues. The camera should move the whole body while rotating from side to side but instead rotates the body when moving along the Y axis.

Rotate to opposite direction

Unity2D
How to make game object to face opposite from the position of another game object?
I have a fish that is going always forward and randomly rotating to make semi random movement,
and i want that in range of player(shark) the fish change direction opposite to shark and start moving faster(trying to escape). I have speed increase already but i doknt know how to make the opposite direction.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FishMove : MonoBehaviour
{
Rigidbody2D rb;
int rotZ = 0;
[SerializeField]
Transform target;
float speed;
bool move=true;
bool rotace = true;
[SerializeField]
int smerRotace;
[SerializeField]
float casRotace;
float nula;
[SerializeField]
Transform shark;
float fearRange=4;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
if (rotace)
{
rotace = false;
smerRotace = Random.Range(-1, 2);
if (smerRotace == 0) nula = 0.2f;
Invoke("Rotace", Random.Range(3.0f*nula, 9.0f*nula));
nula = 1;
}
rotZ += 2 * smerRotace;
float distance = Vector2.Distance(transform.position, shark.position);
if (distance < fearRange)
{
speed = 0.1f;
}
else
{
transform.rotation = Quaternion.Euler(0, 0, rotZ);
}
transform.position = Vector2.MoveTowards(transform.position, target.position, speed);
speed = 0.05f;
}
void Rotace()
{
rotace = true;
}
}
Notice: at the part when I am saying to add/subtract 90 (you’ll know when you get there), try adding 90, if that doesn’t work, try subtracting 90 to get the right result.
To make it move fully the opposite direction, you should do a few things. First, I will tell you about Mathf.Atan2(float y, float x). Atan2 is arctangent. Arctangent takes a position, and finds the amount of rotations to rotate at that object, in radians. Then, you would want to multiply by Mathf.Rad2Deg, or radians to degrees. It converts radians to degrees, which unity uses. Then, you would add some degrees to face the opposite direction.
Here is a way to make an object look away from the the mouse:
using UnityEngine;
using System;
using System.Collections.Generic;
public class LookAtMouse : MonoBehaviour
{
public GameObject obj;
Vector3 offset;
Vector3 mousePosition;
float rotation;
void Update()
{
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
offset = mousePosition - obj.transform.position;
rotation = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg - 90f;
obj.transform.rotation = Quaternion.Euler(0f, 0f, rotation);
}
}
Basically, the script gets the mouse position, and stores it in mousePosition. Then, it gets the offset of the mouse relative to obj. The rotation is the product of the arctangent of the offset and the amount of degrees in a radian (unity uses degrees, not radians), minus 90. Arctangent is 90 degrees off of the target, so people usually add 90 to get it to look at the target. We are looking away from the target, so we subtract 90 to be 180 degrees away, or half way.
We would do the same thing for your script; here it is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FishMove : MonoBehaviour
{
Rigidbody2D rb;
int rotZ = 0;
[SerializeField] Transform target;
float speed;
bool move=true;
bool rotace = true;
[SerializeField] int smerRotace;
[SerializeField] float casRotace;
float nula;
[SerializeField] Transform shark;
float fearRange=4;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
Vector3 offset;
float rotation;
void FixedUpdate()
{
if (rotace)
{
rotace = false;
smerRotace = Random.Range(-1, 2);
if (smerRotace == 0) nula = 0.2f;
Invoke("Rotace", Random.Range(3.0f*nula, 9.0f*nula));
nula = 1;
}
rotZ += 2 * smerRotace;
float distance = Vector2.Distance(transform.position, shark.position);
if (distance < fearRange)
{
speed = 0.1f;
offset = transform.position - shark.transform.position;
rotation = Mathf.Atan2(offset.y, offset.x) * Mathf.Rad2Deg - 90f;
transform.rotation = Quaternion.Euler(0f, 0f, rotation);
}
else
{
transform.rotation = Quaternion.Euler(0, 0, rotZ);
}
transform.position = Vector2.MoveTowards(transform.position, target.position, speed);
speed = 0.05f;
}
void Rotace()
{
rotace = true;
}
}
Tell me in the comments if it works or if it doesn't work.

Unity - Player movement problem, you can fly

If you dont collide with something you can fly! its really strange, please help me if you can.
i dont know how to fix it cause i am new in it.
Here is a script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Movement : MonoBehaviour
{
public float speed = 4.0f;
public float gravity = -9.8f;
private CharacterController _charCont;
// Use this for initialization
void Start()
{
_charCont = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
float deltaX = Input.GetAxis("Horizontal") * speed;
float deltaZ = Input.GetAxis("Vertical") * speed;
Vector3 movement = new Vector3(deltaX, 0, deltaZ);
movement = Vector3.ClampMagnitude(movement, speed); //Limits the max speed of the player
// movement.y = gravity;
movement *= Time.deltaTime; //Ensures the speed the player moves does not change based on frame rate
movement = transform.TransformDirection(movement);
_charCont.Move(movement);
}
}
I don't know that CharacterController but it sounds like it takes the global movement vector.
After
movement = transform.TransformDirection(movement);
you should erase the Y component
movement.y = 0;

How do I change my direction towards rotation angle at all times?

I have this script below and I want my player to always move towards the rotation angle, which doesn't happen. It only changes direction when I click.
My purpose is for the player to move at all times and towards the rotation which should be controlled by mouse position/mouse x axis (kind of like auto-run, but always change rotation based on mouse, not just move right or left).
I've tried about 10 different methods, nothing worked so far...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovementController : MonoBehaviour
{
public float speed = 4;
public float rot = 0f;
public float rotSpeed = 80;
public float gravity = 8;
private Camera cam;
Vector3 moveDir = Vector3.zero;
CharacterController controller;
Animator anim;
// Start is called before the first frame update
void Start()
{
controller = GetComponent<CharacterController> ();
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
float horizontalSpeed = 8.0f;
//Get the mouse delta. This is not in the range -1...1
float h = horizontalSpeed * Input.GetAxis("Mouse X");
float z = horizontalSpeed * Input.GetAxis("Mouse Y");
transform.Rotate(0, h, 0);
//Move Input
if(controller.isGrounded){
if(Input.GetMouseButtonUp(1))
{
anim.SetInteger ("condition", 1);
moveDir = new Vector3 (0,0,1) * speed;
// moveDir *= speed;
moveDir = transform.TransformDirection(moveDir);
}
if(Input.GetMouseButtonDown(1))
{
anim.SetInteger("condition", 0);
moveDir = Vector3.zero;
}
}
moveDir.y -= gravity * Time.deltaTime;
controller.Move(moveDir * Time.deltaTime);
}
}
Transform.LookAt
Just get a cursor position and that's it
Vector3 direction = target.position - player.transform.position;
Quaternion finalPlayerRotation = Quaternion.LookRotation(direction);
player.transform.rotation = finalPlayerRotation;
This also works in some cases:
Vector3 direction = target.position - player.transform.position;
player.transform.right /*You may need to change the Right to upper, -upper, -Right depend on the player rotation and the target position*/ = direction;

rotation to original position in unity 3d

I was making a game where there is a plane which I control using the wasd keys, it rotates and translates. Up-to that its fine, but I would like the plane to re-align to its original rotation when I lift the key. The code I made up is this but it doesn't work. The plane realigns for only one frame and then "misaligned" again . This is the code -**
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class planemovement : MonoBehaviour
{
public int fspeed = 10;
float horizontal; float zrot;
float vertical; float yrot;
public float sense; public int lim = 0;
void Start()
{
}
// Update is called once per frame
void Update()
{
float rotz = Input.GetAxis("Vertical"); float roty = Input.GetAxis("Horizontal");
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
transform.Translate(Vector3.forward * fspeed * Time.deltaTime);
transform.Translate(Vector3.right * sense * Time.deltaTime * horizontal*20f);
transform.Translate(Vector3.up * sense * Time.deltaTime * vertical);
zrot -= rotz;
yrot -= roty;
zrot = Mathf.Clamp(zrot, -lim, lim);
yrot = Mathf.Clamp(yrot, -lim, lim);
transform.localRotation = Quaternion.Euler(zrot, 0f, yrot);
}
}
Rotation in Unity C# is usually quite wonky, the only time it is exact is when you use Quaternions properly.
public Quaternion startQuaternion;
void Start() {
startQuaternion = transform.rotation;
}
//when you want to reset to original
transform.rotation = startQuaternion;
https://docs.unity3d.com/ScriptReference/Quaternion.html
I don't quite understand, but if you using a rigidbody, you can try using "Quaternion.Lerp" and MoveRotation.
Quaternion.Lerp has three parameters and creates a rotation from point A to B, with a speed ugual to T (T goes from 0 to 1).
var currentRot = transform.rotation
var desired Rot = rotation on which the plane must be aligned
Quaternion RotPlane = Quaternion.Lerp (currentRot, desiredRot, 0.5)
MoveRotation(RotPlane)
You can use an if (Input.GetKeyUp) and put the script underneath it, so every time you release the buttons the plane returns to the desired rotation.

Categories

Resources