Unity Camera flicker when going from 359 rotation to 0 - c#

I'm using this simple CameraFollow script to have my camera follow behind my player's movements. The problem is that my player can spin a full 360 degrees, and the camera has to rotate with it. This works well, except when completing a full turn. When the player transform goes from 359 degrees back to 0, the camera flickers as it does a full backwards 360 degree loop to catch up, instead of moving 1 degree to catch up. How can I fix this?
In the code below the 'target' is my player, and 'trans' is the transform of the camera. It's also worth noting that if the player stops at exactly 0 degrees it jumps back to 180 for some reason.
public class CameraFollow : MonoBehaviour {
[SerializeField] Transform target;
[SerializeField] Vector3 defaultDistance = new Vector3(0f, 3.5f, -12f);
[SerializeField] float distanceDamp = 0.05f;
[SerializeField] Vector3 velocity = Vector3.one;
Transform trans;
private void Awake()
{
trans = transform;
}
private void FixedUpdate()
{
Vector3 toPos = target.position + (target.rotation * defaultDistance);
Vector3 curPos = Vector3.SmoothDamp(trans.position, toPos, ref velocity, distanceDamp);
trans.position = curPos;
trans.up = target.up;
}
}

I solved my issue by changing the last line from
trans.up = target.up;
to
trans.rotation = target.rotation;

Related

Unity Orthographic Camera Panning

(I'm relatively new to Unity) I'm making a scene where I want the camera to move in the opposite direction of the mouse movement when I hold down the right mouse button.
The scene is isotropic, which is why the camera is orthographic.
[SerializeField] private Camera cam;
private Vector3 dragOrigin = Vector3.zero;
public float speed = 10;
void Update(){
if(Input.GetMouseButtonDown(1)){
dragOrigin = cam.ScreenToWorldPoint(Input.mousePosition);
}
if(Input.GetMouseButton(1)){
Vector3 difference = cam.ScreenToWorldPoint(Input.mousePosition) - cam.transform.position;
Vector3 targetPosition = dragOrigin - difference;
//targetPosition.y = cam.transform.position.y;
cam.transform.position = Vector3.Lerp(cam.transform.position, targetPosition, speed * Time.deltaTime);
}
}
This works, but there is the problem that the y-value of the camera changes as well. It should always stay at the same height.
If I use
targetPosition.y = cam.transform.position.y;
the camera stays on the same y-position, but it moves slower when I move it up and down.
How can I rewrite the code so that only the x and z values change and that the camera moves with the same speed in all directions?
Thanks in advance.

Objects changed rotation jumps to it's original Unity3D

I made input joysticks for mobile game. One that moves the player and other one that changes it's rotation. Both are working fine but only problem is that when I change players rotation and release that joystick it jumps to it's original rotation. Here's my script:
public GameObject player;
private PlayerInput playerInput;
void Update()
{
Vector2 input = playerInput.actions["Move"].ReadValue<Vector2>();
Vector3 move = new Vector3(input.x, input.y, 0);
player.transform.position += move * speed * Time.deltaTime;
Vector2 look = playerInput.actions["Look"].ReadValue<Vector2>();
player.transform.rotation = Quaternion.LookRotation(Vector3.forward, look);
}
I typically solve this by ignoring rotation values of small magnitude and maintaining the last frame's orientation in said case. You might have to tune the threshold below to filter out the correct values.
public GameObject player;
private PlayerInput playerInput;
private Vector2 look;
void Update()
{
Vector2 input = playerInput.actions["Move"].ReadValue<Vector2>();
Vector3 move = new Vector3(input.x, input.y, 0);
player.transform.position += move * speed * Time.deltaTime;
var inputLook = playerInput.actions["Look"].ReadValue<Vector2>();
look = inputLook.magnitude > 0.1f ? inputLook : look;
player.transform.rotation = Quaternion.LookRotation(Vector3.forward, look);
}

Unity doesn't update object transform.position

I'm working on a little 2d game where you control a planet to dodge incoming asteroids. I'm implementing gravity in the following manner:
public class Gravity : MonoBehaviour
{
Rigidbody2D rb;
Vector2 lookDirection;
float lookAngle;
[Header ("Gravity")]
// Distance where gravity works
[Range(0.0f, 1000.0f)]
public float maxGravDist = 150.0f;
// Gravity force
[Range(0.0f, 1000.0f)]
public float maxGravity = 150.0f;
// Your planet
public GameObject planet;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
// Distance to the planet
float dist = Vector3.Distance(planet.transform.position, transform.position);
// Gravity
Vector3 v = planet.transform.position - transform.position;
rb.AddForce(v.normalized * (1.0f - dist / maxGravDist) * maxGravity);
// Rotating to the planet
lookDirection = planet.transform.position - transform.position;
lookAngle = Mathf.Atan2(lookDirection.y, lookDirection.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, lookAngle);
}
}
The problem is that the asteroids are attracted to the initial spawn point of the planet (0,0), it doesn't update in real time with the movement of the planet. So if I move the planet to the corner of the screen, the asteroids are still attracted to the centre of it.
When I use Debug.Log for each value all change except for planet.transform.position that stays at 0,0,0 even after moving it.
Is it a problem with the rigidbody of the planet? Any settings? I'm a bit lost.
Is there a way to solve this?
Thank you very much and excuse any flagrant errors!
Because the asteroids were dynamically spanwed from a prefab, they weren't a gameobject, the planet selected on the gameobject variable on the script was the prefab, not the real gameobject on the scene. I had to add this line to my spawner script
if (interval > random) {
GameObject newAsteroid = Instantiate(asteroidPrefab,
GetRandomPosition(), Quaternion.identity);
newAsteroid.GetComponent<Gravity>().planet = planet;
}
and at the top in your variables add
public GameObject planet;
add in your spawner script in the editor, drag and drop your planet
gameobject.
This fixed the issue.

Unity mid air movement with velocitychange

I have made a script for player movement in a 3D game in Unity.
I like how the movement works, but when I jump while moving, the player keeps moving in that direction at the same speed till it falls to the ground, which is the expected behavior for this script.
But I want to be able to move the player in the air slightly (not fully controllable.)
I'm imagining kinda like a minecraft like movement to be exact.
Any advice to improve this code would be greatly apprecciated.
This is my code.
using System.IO;
using UnityEngine;
public class VelocityMovement : MonoBehaviour
{
#region Variables
public float speed;
public float gravity;
public float maxVelocityChange;
public float jumpHeight;
public float raycastDistance;
public Rigidbody rb;
#endregion
private void Awake()
{
//gets rigidbody, freezes rotation of the rigidbody, disables unity's built in gravity system on rigidbody.
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
rb.useGravity = false;
}
private void Update()
{
//Jump system
if(Grounded())
{
if (Input.GetKeyDown(KeyCode.Space))
{
rb.velocity = new Vector3(rb.velocity.x, CalculateJumpSpeed(), rb.velocity.z);
}
}
}
private void FixedUpdate()
{
//Moves the player when on the ground.
if (Grounded())
{
//Calculate how fast the player should be moving.
Vector3 targetVelocity = new Vector3(playerInputs.hAxis, 0, playerInputs.vAxis);
targetVelocity = transform.TransformDirection(targetVelocity);
targetVelocity *= speed ;
//Calculate what the velocity change should be
Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0f;
//applies a force equal to the needed velocity change
rb.AddForce(velocityChange, ForceMode.VelocityChange);
}
//Adds gravity to the rigidbody
rb.AddForce(new Vector3(0, -gravity * rb.mass, 0));
}
//Checks if player is on the ground
private bool Grounded()
{
return Physics.Raycast(transform.position, Vector3.down, raycastDistance);
}
//calculates how high the player should be jumping
private float CalculateJumpSpeed()
{
return Mathf.Sqrt(2 * jumpHeight * gravity);
}
}
private void FixedUpdate()
{
//check how big the movement is. Swap SomeSmallValue with a float like 0.1f
float actualSpeed;
Vector3 velocity;
if(Grounded())
{
actualSpeed = speed;
//HERE IT IS NOT, THIS DOESN'T MATTER
velocity = rb.velocity
}
else{
actualSpeed = speed * SomeSmallValue;
//WITH THIS rb KEEPS THE SPEED IF ANY BUTTON IS PRESSED
velocity = 0;
}
//Moves the player ALWAYS.
//Calculate how fast the player should be moving.
Vector3 targetVelocity = new Vector3(playerInputs.hAxis, 0, playerInputs.vAxis);
targetVelocity = transform.TransformDirection(targetVelocity);
//if Grounded == true the movement is exactly the same than before, because actualSpeed = speed.
//If Grounded == false, the movement is so light
targetVelocity *= actualSpeed;
//Calculate what the velocity change should be
//I'VE PLACED THIS UP IN ORDER TO CALL Grounded() ONLY ONE TIME
//Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0f;
//applies a force equal to the needed velocity change
rb.AddForce(velocityChange, ForceMode.VelocityChange);
//Adds gravity to the rigidbody
rb.AddForce(new Vector3(0, -gravity * rb.mass, 0));
}
If your code is working fine, try something like this. Just moved the grounded condition. Now the movement works also at air time. We check with that grounded bool how big the movement is.
If I understood you correctly you want to slow down what your movements do while mid air.
at least that is the case for left and right.
If I did undersand you correctly, you would make an else{} after the if(Grounded())
and go from there, may make some float variable that acts as a multiplier for you left/right control while mid air, aswell as another float variable for forward and backwards.
Inside that else you could just multiply you speed with the variables (depending on the axis) and you should get some form of slower movement there.
I hope that helped you out at least a bit.

UNITY - Shoot Projectile on the direction of where the gun is facing

I Have a gun that spawn a projectile that bounces of colliders (a Ricochet). It is supposed to be shooting to the direction of where the gun is facing but what I am getting is the projectile always shoots 45 degrees upwards to the right I know this is because of my constant declared vector 2.
I tried using Vector2.up but it prevents the projectile to do the ricochet effect because it always wants to go upwards.
How should I implement those things? I just want the projectile to shoot to the direction where my gun is facing and bounces of on colliders. This is a 2D game btw. I have my codes attached below so you can see. Thanks!
Projectile Script:
private Rigidbody2D rb;
public static bool canMove = true;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.velocity = new Vector2(10f, 10f);
}
void Update()
{
//transform.Translate(Vector2.up * speed * Time.deltaTime);
if (canMove)
{
rb.isKinematic = false;
}
else if (!canMove)
{
rb.isKinematic = true;
}
}
Gun Script:
float offset = -90f;
public GameObject projectile;
public Transform shotPoint;
public GameObject child;
void Start()
{
}
void Update()
{
Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
float rotZ = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotZ + offset);
if (Input.GetMouseButtonDown(0))
{
Instantiate(projectile, shotPoint.position, transform.rotation);
Projectile.canMove = true;
}
}
The Rigodbody.velocity is in World-Space coordinates.
When you pass in
rb.velocity = new Vector2(10f, 10f);
it will go in world space 10 in X and 10 in Y direction.
In order to pass it in as local coordinates in general you can not always rely on Tramsform.InverseTransformDirection as suggested here since the Transform component. In this specific case it might work but in general you set velocities in FixedUpdate and in that moment the Transform component might not be updated yet!
But the Rigidbody2D component is so in general you can use Rigidbody2D.GetRelativeVector in order to convert a local vector relative to the Rigidbody into world coordinates:
// Might also be Vector.up depending on your setup
rb.velocity = rb.GetRelativeVector(Vector2.right * speed);
Note: it would be better you make
[SerializeField] private Rigidbody2D rb;
and already reference it via the Inspector. Then you can get rid of the expensive GetComponent call.
Because you are telling it to do so.
rb.velocity = new Vector2(10f, 10f);
10 to the right, and 10 upwards.
Unless your projectile has a constant force applied to it, like a missile, get rid of everything related to forces or velocity in the projectile script. It will do you no good.
Then, on the gun script:
//...
if (Input.GetMouseButtonDown(0)) {
var projectileInstance = Instantiate(projectile, shotPoint.position, transform.rotation);
var rigidbody = projectileInstance.GetComponent<Rigidbody2D>();
rigidbody.velocity = transform.TransformDirection(yourDirectionVector);
Projectile.canMove = true;
}
Where Transform.TransformDirection is what makes yourDirectionVector, which is a direction relative to the gun, be transformed into one relative to world-space.

Categories

Resources