Jittery movement of the camera when rotating AND moving - 2D top down Unity - unity3d

I am making a 2d top down game where the player can rotate the camera around himself as he moves through the world.
Everything works fine when the player is moving around the world the camera follows him fine. if he standing still then the camera rotation also works very well. However as soon as I start to do both then there is a jittery in the camera that makes all other objects jitter besides the player.
Now in working with this problem I have found out that this could have to do with the fact that I use rigidbody2d.AddRelativeForce (so physics) to move the player and that his movements are checked in FixedUpdate.
https://forum.unity3d.com/threads/camera-jitter-problem.115224/ http://answers.unity3d.com/questions/381317/camera-rotation-jitterness-lookat.html
I have tried moving my camera rotation and the following scripts to LateUpdate, FixedUpdate, Update you name it. Nothing seems to work. I am sure that there is some sort of delay between movement of the camera and the rotation that is causing this. I am wondering if anyone has any feedback?
I have tried disabling Vsync, does not remove it entirely
I have tried interpolating and extrapolating the rigidbody and although there is a difference it does not remove it entirely. Ironically it seemd if I have it set to none, it works best.
Scripts:
To Follow character, script applied to a gameobject that has the camera as a child
public class FollowPlayer : MonoBehaviour {
public Transform lookAt;
public Spawner spawner;
private Transform trans;
public float cameraRot = 3;
private bool smooth = false;
private float smoothSpeed = 30f;
private Vector3 offset = new Vector3(0, 0, -6.5f);
//test
public bool changeUpdate;
private void Start()
{
trans = GetComponent<Transform>();
}
private void FixedUpdate()
{
CameraRotation();
}
private void LateUpdate()
{
following();
}
public void following()
{
Vector3 desiredPosition = lookAt.transform.position + offset;
if (smooth)
{
transform.position = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
}
else
{
transform.position = desiredPosition;
}
}
void CameraRotation()
{
if (Input.GetKey("q"))
{
transform.Rotate(0, 0, cameraRot);
}
if (Input.GetKey("e"))
{
transform.Rotate(0, 0, -cameraRot);
}
}
public void SetTarget(string e)
{
lookAt = GameObject.Find(e).GetComponent<Transform>();
}
}
The character Controller, script applied to the Player, is called in FixedUpdate
private void HandleMovement()
{
if (Input.GetKey("w"))
{
rigid.AddRelativeForce(Vector2.up * speed);
}
if (Input.GetKey("s"))
{
rigid.AddRelativeForce(Vector2.down * speed);
}
if (Input.GetKey("a"))
{
if (facingRight)
{
Flip();
}
rigid.AddRelativeForce(Vector2.left * speed);
}
if (Input.GetKey("d"))
{
if (!facingRight)
{
Flip();
}
rigid.AddRelativeForce(new Vector2(1,0) * speed);
}
}

Try to use Coroutines. I modified some of my scripts to be more familiar to Your code, tried it, and I didn't see any jittery. I hope that will help You.
Camera Class:
public class CameraController : MonoBehaviour {
[SerializeField]
Transform CameraRotator, Player;
[SerializeField]
float rotationSpeed = 10f;
float rotation;
bool rotating = true;
void Start()
{
StartCoroutine(RotatingCamera());
}
IEnumerator RotatingCamera()
{
while (rotating)
{
rotation = Input.GetAxis("HorizontalRotation");
CameraRotator.Rotate(Vector3.up * Time.deltaTime * rotation * rotationSpeed);
CameraRotator.position = Player.position;
yield return new WaitForFixedUpdate();
}
}
private void OnDestroy()
{
StopAllCoroutines();
}
}
Player Class:
public class PlayerMovement : MonoBehaviour {
[SerializeField]
float movementSpeed = 500f;
Vector3 movementVector;
Vector3 forward;
Vector3 right;
[SerializeField]
Transform CameraRotator;
Rigidbody playerRigidbody;
float inputHorizontal, inputVertical;
void Awake()
{
playerRigidbody = GetComponent<Rigidbody>();
StartCoroutine(Moving());
}
IEnumerator Moving()
{
while (true)
{
inputHorizontal = Input.GetAxis("Horizontal");
inputVertical = Input.GetAxis("Vertical");
forward = CameraRotator.TransformDirection(Vector3.forward);
forward.y = 0;
forward = forward.normalized;
Vector3 right = new Vector3(forward.z, 0, -forward.x);
movementVector = inputHorizontal * right + inputVertical * forward;
movementVector = movementVector.normalized * movementSpeed * Time.deltaTime;
playerRigidbody.AddForce(movementVector);
yield return new WaitForFixedUpdate();
}
}
}

I fixed this problem finally:
First I made my cameraRotation() and follow() into 1 function and gave it a better clearer name:
public void UpdateCameraPosition()
{
if (Input.GetKey("q"))
{
transform.Rotate(0, 0, cameraRot);
}
else if (Input.GetKey("e"))
{
transform.Rotate(0, 0, -cameraRot);
}
Vector3 desiredPosition = lookAt.transform.position + offset;
transform.position = desiredPosition;
}
I then called that function from the character controller straight after the handling of movement. Both calls (handleMovement & cameraPosition) in fixedUpdate.
void FixedUpdate()
{
HandleMovement();
cameraController.UpdateCameraPosition();
}
and the jittering was gone.
So it seems it was imply because there was a slight delay between the two calls as the previous posts I read had said. But I had failed to be able to properly Set them close enough together.
Hope this helps someone.

Related

Jump in using Rigidbody or Character controller

i have been recreating my jump code, i have it all done but i can't add force or anything else.
Here's my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class pBeh : MonoBehaviour
{
CharacterController characterController;
public float MovementSpeed = 1;
public float Gravity = 9.8f;
private float velocity = 0;
private Camera mainCam;
public Rigidbody rb;
public float jumpSpeed = 5.2f;
private Vector3 movingDirection = Vector3.zero;
public CharacterController controller;
public float speed;
float turnSmoothVelocity;
public float turnSmoothTime;
public bool canJump = false;
private void Start()
{
characterController = GetComponent<CharacterController>();
mainCam = Camera.main;
}
void Update()
{
// player movement - forward, backward, left, right
float horizontal = Input.GetAxis("Horizontal") * 10;
float vertical = Input.GetAxis("Vertical") * 10;
Vector3 camRightFlat = new Vector3(mainCam.transform.right.x, 0,
mainCam.transform.right.z).normalized;
Vector3 camForwardFlat = new Vector3(mainCam.transform.forward.x, 0,
mainCam.transform.forward.z).normalized;
characterController.Move((camRightFlat * horizontal + camForwardFlat * vertical)
* Time.deltaTime);
// Gravity
if (characterController.isGrounded)
{
velocity = 0;
}
else
{
velocity -= Gravity * Time.deltaTime;
characterController.Move(new Vector3(0, velocity, 0));
}
if (canJump == true && Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Jumped");/*
transform.Translate(Vector3.up * 5.0f * Time.deltaTime);
rb.AddRelativeForce(Vector3.up * 8.0f);
rb.AddForce(Vector3.up * 8.0f)
i have tried a lot more, but it just doesn't work.
The sphere (Player) does nothing or shakes.
*/
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "enemy")
{
SceneManager.LoadScene("SampleScene");
}
}
void FixedUpdate()
{
if ((controller.collisionFlags & CollisionFlags.Below) != 0)
{
//Debug.Log("ground");
canJump = true;
}
else
{
canJump = false;
}
}
As i said it works just fine i just can't find reason why i cannot jump.
I have all character controller right and rigidbody too. If you could help i would be happy.
Btw i am beginner so i copied movement to be same as camera. Thanks!
From what I know, rigidbody and character controller do not work together (on the same object) so you have to choose one or the other, if you are using rigidbody then a ground check or similiar stuff would not be necessary since rigidbody is using unity physicis system so a lot of the stuff would be already done for you to simulate physics but you should still read thru the document

Why is there a constant stutter when i move in Unity 2d?

So i have a simple scene in unity, a player with a parallax background and a Tilemap as a ground, as well as some very simple post processing. I know this isn't a The minute i move, there is a consistent stutter just under ever second. I'm not sure whether it's to do with my player movement code, camera movement or anything else. I'm also using a Cinemachine virtual camera. My rigidbody interpolation is set to interpolate and collision detection set to continuous. Here's my player movement if this helps. Here is a sample of what it looks like, if you look at the background or the tilemap it's quite noticeable. https://youtu.be/h2rSheZWtKs
[SerializeField] private LayerMask groundLayerMask;
public float speed;
public float Jump;
public sword swordScript;
public GameObject swordSprite;
private float move;
private Rigidbody2D rb;
private BoxCollider2D boxCollider2d;
private bool facingRight;
public SpriteRenderer spr;
public Animator PlayerAnims;
public bool movementAllowed;
void Awake()
{
Application.targetFrameRate = 60;
Application.targetFrameRate = Screen.currentResolution.refreshRate;
boxCollider2d = GetComponent<BoxCollider2D>();
rb = GetComponent<Rigidbody2D>();
facingRight = true;
spr = GetComponent<SpriteRenderer>();
}
// Start is called before the first frame update
void Start()
{
boxCollider2d = GetComponent<BoxCollider2D>();
rb = GetComponent<Rigidbody2D>();
facingRight = true;
spr = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void FixedUpdate()
{
if(movementAllowed == true)
{
rb.velocity = new Vector2(move * speed, rb.velocity.y);
if (isGrounded() && Input.GetButtonDown("Jump"))
{
rb.AddForce(new Vector2(rb.velocity.x, Jump));
}
}
}
void Update()
{
move = Input.GetAxis("Horizontal");
rb.velocity = new Vector2(move * speed, rb.velocity.y);
if (movementAllowed == true)
{
Flip(move);
if (move == 0)
{
PlayerAnims.SetBool("isRunning", false);
}
else
{
PlayerAnims.SetBool("isRunning", true);
}
}
}
private bool isGrounded()
{
float extraHeightText = .1f;
RaycastHit2D raycasthit2d = Physics2D.BoxCast(boxCollider2d.bounds.center, boxCollider2d.bounds.size, 0f, Vector2.down, extraHeightText, groundLayerMask);
Color rayColour;
if (raycasthit2d.collider != null)
{
rayColour = Color.green;
PlayerAnims.SetBool("isJumping", false);
}
else
{
rayColour = Color.red;
PlayerAnims.SetBool("isJumping", true);
}
Debug.DrawRay(boxCollider2d.bounds.center + new Vector3(boxCollider2d.bounds.extents.x, 0), Vector2.down * (boxCollider2d.bounds.extents.y + extraHeightText), rayColour);
Debug.DrawRay(boxCollider2d.bounds.center - new Vector3(boxCollider2d.bounds.extents.x, 0), Vector2.down * (boxCollider2d.bounds.extents.y + extraHeightText), rayColour);
Debug.DrawRay(boxCollider2d.bounds.center - new Vector3(boxCollider2d.bounds.extents.x, boxCollider2d.bounds.extents.y + extraHeightText), Vector2.right * (boxCollider2d.bounds.extents.x), rayColour);
return raycasthit2d.collider != null;
}
private void Flip(float move)
{
if (move > 0 && !facingRight || move < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
if (swordScript.isFollowing == true)
{
Vector3 swordScale = swordSprite.transform.localScale;
swordScale.x *= -1;
swordSprite.transform.localScale = swordScale;
}
}
}
You are setting rb.velocity in both the Update() and FixedUpdate() methods. I would try only using one of those.
On top of that, your jump check also re-applies the X velocity along with the upward force. So if you're jumping the player will be pushed forward at double speed.
You also have an error being outputted in the console about an Index being out of range... I would look into that.
Can you also post your code for the parallax background?
FixedUpdate is a method where you want to do everything physics, player-controller and simulation related.
Update is just for rendering-related fluff i.e. code of no real consequence other than making things look correctly.
Hence:
Move all your player/physics controller code to FixedUpdate.
Move bg parallax code to Update.
Use Time.deltaTime (in Update) and Time.fixedDeltaTime (in FixedUpdate) time steps when animating or interpolating between values.
Ad #3.: Although - as #Menyus noted (below) - Time.deltaTime is all you really need.
Time.fixedDeltaTime is for that extra intent explicitness (but was necessary in earlier unity versions).

Unity2D How do i get the main camera to move up on the Y axis continuously after i left mouse click?

I'm trying to get my main camera to move upwards on the Y axis slowly only after the left mouse button is clicked.
Here is my code so far.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class CameraPanUp : MonoBehaviour
{
public float speed = 5f;
public Transform target;
Vector3 offset;
// Start is called before the first frame update
void Start()
{
offset = transform.position - target.position;
}
// Update is called once per frame
void FixedUpdate()
{
Vector3 targetCamPos = target.position + offset;
transform.position = Vector3.Lerp(transform.position, targetCamPos, speed * Time.deltaTime);
if (Input.GetMouseButtonDown(0))
{
}
}
}
I'm unsure what to put in the if statement above. I tried using transform.Translate before and it just made the Camera move up in small increments every time i left click. Why is that? Any help would be gladly appreciated.
One option is to use Coroutines:
Coroutine moveCoroutine;
IEnumerator StartMovingUp() {
float moveSpeed = 2f;
while(true) {
transform.Translate(0, moveSpeed * Time.deltaTime, 0);
yield return null;
}
}
void Update() {
if (Input.GetMouseButtonDown(0) && moveCoroutine == null) {
moveCoroutine = StartCoroutine(StartMovingUp());
}
}
another is doing it in the Update function with fields for state. Anything more may make the code too complicated.
bool isMovingUp;
float moveSpeed = 2f;
void Update() {
if (Input.GetMouseButtonDown(0)) {
isMovingUp = true;
}
if (isMovingUp) {
transform.Translate(0, moveSpeed * Time.deltaTime, 0);
}
}

How do I move a GameObject at the same speed as onMouseDrag?

I am trying click on a GameObject and move it at the same rate as the mouse. I am able to get the Object to move, but I have to do some crazy modifications in order for it to not vanish off the screen.
Note: My ultimate goal will be to do this for mobile, but am starting with the mouse.
public class ItemController : MonoBehaviour {
private Vector3 startPos;
private bool ObjectMouseDown = false;
void Update()
{
Debug.Log(Input.mousePosition + new Vector3(0,0,15));
}
void OnMouseDown()
{
startPos = transform.position;
ObjectMouseDown = true;
}
void OnMouseDrag()
{
if (ObjectMouseDown == true)
{
transform.position = Vector3.MoveTowards(transform.position, Input.mousePosition + new Vector3(0, 0, 5), Time.deltaTime * 2f);
// transform.position = Vector3.MoveTowards(transform.position, endPosition, speed * Time.deltaTime);
}
}
void OnMouseUp()
{
ObjectMouseDown = false;
}
}
Notice how I have to add a z-value of 15, so that the object doesn't float up out of the screen.
Any help would be awesome.
Input.mousePosition return the absolute pixel position on the screen and not world position. You need to use Camera.ScreenToWorldPoint something like this
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.position.x, Input.position.y, 15);
transform.position = mouseWorldPos;
You can read more here https://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html

Moving the player when the bridge is moved?

I'm creating a game, and I created an bridge that move to right and left.
I want my player when colliding with the bridge go along on the move.
I'm trying set position player with position of the bridge, but when my player is on the bridge his doing small jumps
How can I do this ?
I'm trying this.
public class MoveBridge : MonoBehaviour {
private bool isLeft = false;
public float speed = 5f;
public float delaySpeed;
private float moveTime;
public GameObject player;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
move();
}
private void move(){
moveTime += Time.deltaTime;
if (moveTime <= delaySpeed){
if (isLeft){
gameObject.transform.Translate(-Vector2.right * speed * Time.deltaTime);
}else{
gameObject.transform.Translate(Vector2.right * speed * Time.deltaTime);
}
}else{
isLeft = !isLeft;
moveTime = 0f;
}
}
void OnCollisionStay2D(Collision2D coll){
if(coll.gameObject.name.Equals("PlayerObject")){
player.transform.position = gameObject.transform.position;
}
}
}
I solved the problem.
void OnCollisionStay2D(Collision2D coll){
if(coll.gameObject.name.Equals("PlayerObject")){
coll.gameObject.transform.parent = transform;
}
}