The CineMachine Camera ruin the 2d parallax Effect because its shaking - c#

I am working in a 2d platform game I applied cinemachine camera and parallax script to give a good effect ,but the parallax is shaking and vibrating hard , I found out that the cinamchine was the reason because the camera it shaking, when I disabled the cinemachine it work smoothly
here is the parallax code
private float startpos;
private GameObject cam;
[SerializeField] private float parallax;
[SerializeField] private float speed = 0.1f;
// Start is called before the first frame update
void Start()
{
cam = GameObject.Find("Main Camera");
startpos = transform.position.x;
}
// Update is called once per frame
void Update()
{
float distance = (cam.transform.position.x * parallax);
transform.position = new Vector3(startpos + distance, transform.position.y, transform.position.z);
}
and the settings of the MC vcam1
enter image description here
please any help I dont find any on with that problem

You could try setting the CinemachineBrain update method to Manual Update and then just calling ManualUpdate() in another script.
using UnityEngine;
using Cinemachine;
public class ManualBrainUpdate : MonoBehaviour
{
public CinemachineBrain cineBrain;
public float smoothTime;
private void Start()
{
cineBrain = GetComponent<CinemachineBrain>();
}
void Update()
{
cineBrain.ManualUpdate();
}
}

To avoid any kind of jitter in Unity (like what the camera is adding to distance when it shakes) use the various SmoothDamp functions e.g. https://docs.unity3d.com/ScriptReference/Vector3.SmoothDamp.html:
public float smoothTime = 0.3f; // adjust this to taste
private float distance;
private Vector3 velocity = Vector3.zero;
private Vector3 targetPos
void Update()
{
distance = cam.transform.position.x * parallax;
targetPos = new Vector3(startpos + distance, transform.position.y, transform.position.z)
transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref velocity, smoothTime);
}

Related

Unity Animator component unnecessarily overriding scripted position of Game Objects

I have a hand and pistol(fps) gameObject. and the recoil system is controlled directly from script (including the slide on the pistol) and it works perfectly.
the moment I added an idle and reload animation the pistol slider stops moving back when recoiling.
When I disable the animator component it works back fine, I even deleted all my keyframes on the "idle" animation still the slider doesn't work.
I have my Recoil Script below
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponRecoil : MonoBehaviour
{
[SerializeField]
private float recoilX;
[SerializeField]
private float recoilY;
[SerializeField]
private float recoilZ;
[SerializeField]
private float recoilResetSpeed = 0.8f;
[SerializeField]
private float snappiness = 2f;
public Transform parent;
Vector3 targetRotation;
Vector3 currentRotation;
Vector3 targetHandPosition;
Vector3 currentHandPosition;
[SerializeField]
private List<EjectorData> bulletEjectors;
[SerializeField]
float ejectorBackDistance;
[SerializeField]
float ejectorReturnSpeed=10;
void Start() {
foreach (EjectorData ejector in bulletEjectors)
{
ejector.startPosition = ejector.obj.localPosition;
}
}
void Update()
{
coolDownWeaponRecoilEffect();
}
void coolDownWeaponRecoilEffect()
{
targetRotation = Vector3.Lerp(targetRotation, Vector3.zero, recoilResetSpeed * Time.deltaTime);
currentRotation = Vector3.Slerp(currentRotation, targetRotation, snappiness * Time.deltaTime);
//resetting the pushback effect of the recoil of the hand
targetHandPosition = Vector3.Lerp(targetHandPosition, Vector3.zero, recoilResetSpeed * Time.deltaTime);
currentHandPosition = Vector3.Slerp(currentHandPosition, targetHandPosition, snappiness * Time.deltaTime);
if (parent == null) return;
parent.localRotation = Quaternion.Euler(currentRotation);
transform.localPosition = currentHandPosition;
//resseting the bullet ejectors back to their normal positions
foreach (EjectorData ejector in bulletEjectors)
{
ejector.obj.localPosition = Vector3.Lerp(ejector.obj.localPosition, ejector.startPosition, ejectorReturnSpeed * Time.deltaTime);
}
}
public void Recoil() {
targetRotation += new Vector3(recoilX, Random.Range(-recoilY, recoilY), 0);
targetHandPosition -= new Vector3(0, 0, recoilZ);
foreach (EjectorData ejector in bulletEjectors) {
ejector.obj.localPosition -= new Vector3(0, 0, ejectorBackDistance);
}
}
[System.Serializable]
class EjectorData {
public Transform obj;
public Vector3 startPosition;
}
}
To put is simply your script is overriding the position of the bones, and the animator is overriding that; rendering it useless
To change the bones rotation/Position on top the animation you should look into Unity's Animation Rigging
AnimationRigging works as a post-process step of the Animator and has the same restrictions as any animated hierarchy. you can use the Override Transform Constraint To achieve the effect you are looking for.
this tutorial might help you a bit if you are stuck.

Rotate enemy character to see player character

I am making the enemy character to follow the player character.
In the FixedUpdate method the enemy character move toward the player character,
then in the Update method character rotates to the player character.
However, with this script, somehow enemy character is just nudging and gets stuck.
Where is the mistake, what's wrong???
public class enemy : MonoBehaviour
{
GameObject tObj;
private Vector3 latestPos;
public string targetObjectName;
public float speed = (float)1.0;
void Start()
{
tObj = GameObject.Find("player");
latestPos = transform.position;
}
void Update()
{
Vector3 diff = transform.position - latestPos;
latestPos = transform.position;
if (diff.magnitude > 0.01f)
{
transform.rotation = Quaternion.LookRotation(diff);
}
}
void FixedUpdate(){
Vector3 dir = (tObj.transform.position - this.transform.position).normalized;
float vx = dir.x * speed;
float vz = dir.z * speed;
this.transform.Translate((float)(vx / 50.0),0,(float)(vz / 50.0));
}
}
Use Package Manager "Standard Assets", Inside Unity put two FPSController one should be Player and the second can be Enemy.
I know this does not answers your question but its a faster way to ad Enemy.
AI Settings
Just remove the camera, Audio Source and First Person Controller Script as in image.
The Code for AI:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowAI : MonoBehaviour
{
public CharacterController _controller;
public Transform target;
public GameObject Player;
[SerializeField]
float _moveSpeed = 2.0f;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update() {
Vector3 direction = target.position - transform.position;
direction = direction.normalized;
Vector3 velocity = direction * _moveSpeed;
_controller.Move(velocity * Time.deltaTime);
Vector3 lookVector = Player.transform.position - transform.position;
lookVector.y = transform.position.y;
Quaternion rot = Quaternion.LookRotation(lookVector);
transform.rotation = Quaternion.Slerp(transform.rotation, rot, 1);
}
}

Cant Change Friction of Player In Unity2D

I am extremely new to both Unity and C# and have been working on it for a few days. I'm currently trying to stop my player from sliding and to do this I've set the friction value of the players material high so that it doesn't slide. This however creates an issue where my character travels entirely too fast. To get around this I created a child object with a BoxCollider2D tagged as Friction Controller that I can modify. I get a code that changes the friction value of the physics material to 0 when i start moving and 100 when am supposed to stop. The problem is that while this updates the material itself it does not affect the box colliders settings. Does anybody know a solution for this?
using System.Collections.Generic;
using System.Collections.Specialized;
using UnityEngine;
public class Player_Movement : MonoBehaviour
{
GameObject frictionController;
public BoxCollider2D collider;
public float speed = 400f;
public float jumpForce;
private float friction;
private Rigidbody2D rb2d;
private bool isMoving;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D> ();
}
// Update is called once per frame
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
Vector2 movement = new Vector2(moveHorizontal,0);
rb2d.AddForce(movement * speed);
}
void Update()
{
frictionController = GameObject.FindWithTag("Friction Controller");
collider = frictionController.GetComponent<BoxCollider2D>();
if (Input.GetKey("a") || (Input.GetKey("d")))
{
{ Debug.Log("Pressed Button"); }
collider.sharedMaterial.friction = 0;
} else { collider.sharedMaterial.friction = 100; }
///This part isn't complete yet
float moveVertical = Input.GetAxis("Vertical");
Vector2 jump = new Vector2(0, moveVertical);
if (Input.GetKeyDown("space"))
{
rb2d.AddForce(Vector3.up * jumpForce);
}
}
}
I'm not sure that your approach is a particularly good one and is likely to give you problems later on. Since you're using the physics system, a better approach would be to apply a force to your Rigidbody that is the OPPOSITE of its velocity when want it to come to a stop.
Nevertheless here is a solution that effectively does what you want to do using a similar approach to what you're attempting. Rather than manipulating the physics material properties, this solution manipulates the drag value of the rigidbody.
public class Player_Movement : MonoBehaviour
{
private Rigidbody2D rb2d;
private float speed = 100f;
void Start()
{
rb2d = GetComponent<Rigidbody2D> ();
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
Vector2 movement = new Vector2(moveHorizontal,0);
rb2d.AddForce(movement * speed);
}
void Update()
{
if (Input.GetKey(KeyCode.A) || (Input.GetKey(KeyCode.D)))
{
rb2d.drag = 5; // Adjust this value to modify speed
}
else
{
rb2d.drag = 100; // Adjust this value to modify slippery-ness
}
}
}

Can't rotate and move at the same time

I'm currently developing an FPS shooter in Unity 3D. I'm fairly new to Unity and I've been having a bit of trouble with my player movement script. Individually everything seems to work, I can rotate and move the player freely, however when I try doing the two simultaneously my player seems to lock and won't rotate.
Sometimes jumping or moving to higher ground on the terrain seems to fix the issue, however I ran a few checks with gravity disabled, no colliders, and with the player well above ground, so the problem seems to be with the script. I've also done a bit of debugging and the Rotate() code does run, just the rotation amount doesn't seem to change.
Here is the player movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMov : MonoBehaviour
{
[SerializeField]
private Camera cam;
[SerializeField]
private float speed = 5f;
[SerializeField]
private float looksensitivity = 4f;
[Header("Camera View Lock:")]
[SerializeField] //min and max amount for looking up and down (degrees)
private float lowlock = 70f;
[SerializeField]
private float highlock = 85f;
private Rigidbody rb;
private float currentrotx; //used later for calculating relative rotation
public Vector3 velocity;
public Vector3 rotation; // rotates the player from side to side
public float camrotation; // rotates the camera up and down
public float jmpspe = 2000f;
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
CalcMovement();
CalcRotation();
Rotate();
}
void FixedUpdate()
{
Move();
}
private void CalcRotation()
{
float yrot = Input.GetAxisRaw("Mouse X"); //around x axis
rotation = new Vector3(0f, yrot, 0f) * looksensitivity;
float xrot = Input.GetAxisRaw("Mouse Y"); //around y axis
camrotation = xrot * looksensitivity;
}
private void CalcMovement()
{
float xmov = Input.GetAxisRaw("Horizontal");
float zmov = Input.GetAxisRaw("Vertical");
Vector3 movhor = transform.right * xmov;
Vector3 movver = transform.forward * zmov;
velocity = (movhor + movver).normalized * speed;
}
void Move()
{
//move
if (velocity != Vector3.zero)
{
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
}
//jump
if (Input.GetKeyDown(KeyCode.Space))
{
//add double jump limit later!
rb.AddForce(0, jmpspe * Time.deltaTime, 0, ForceMode.Impulse);
}
}
void Rotate()
{
//looking side to side
rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
// camera looking up and down
currentrotx -= camrotation;
currentrotx = Mathf.Clamp(currentrotx, -lowlock, highlock);
cam.transform.localEulerAngles = new Vector3(currentrotx, 0, 0);
}
}
Here are the relevant components attached to my player:
(The player has a couple more components attached but I ran tests without them and the problem still occurs)
Like I said I'm a bit of a unity novice, so i'm sure I missed something small but I just can't seem to place my finger on it, I've been stuck on this for a while so any help is much appreciated.
SOLVED:
It seems the problem I had was because I was running the scene from my laptop and not a desktop which I assume is what the Unity input was built for.

How to enable gyroscope camera at current device orientation

I would like to enable gyro controlled camera onButtonClick event but I want it to start at the camera's current position. Currently when the gyro gets enabled it moves the camera off to a new position (probably the devices current gyro rotation) rather than leaving it where it is and gyro-ing from that point.
Hope I'm making sense, but basically I don't want the user to notice any change in what they are seeing in the game (ie. camera controlled by gyro but not that user would notice that change). Here's the code I'm using:
void Update ()
{
Quaternion attitudeFix = new Quaternion (-gyro.attitude.x, -gyro.attitude.z, -gyro.attitude.y, gyro.attitude.w);
Quaternion offsetRotation = initialGyroRotation * attitudeFix;
rotation = initialRotation * offsetRotation;
transform.rotation = rotation;
}
public void EnableGyro()
{
initialGyroRotation = Input.gyro.attitude;
initialRotation = transform.rotation;
Debug.Log("initialRotation: " + initialRotation.ToString());
Debug.Log("transform.rotation: " + transform.rotation.ToString());
Debug.Log("initialGyroRotation: " + initialGyroRotation.ToString());
}
**
EDIT: Here's a screen of exactly how I want the view to look as the user is holding their device in front of their face (portrait) AND heading north. Regardless of the orientation of the device when the app starts, this is how it should look when heading north with phone in portrait orientation (again as the user is looking through the phone).
EDIT 2:
Tests were getting confusing so I put the code back to exactly how your solution suggests. There is still a slight problem, but it seems like this script is very close. The main problem is the screen doesn't look like the above pic when I run each test, starting the app with the device on strange angles. It really shouldn't matter what angle the device is when the app is started, it needs to look like the above screen when pointing north and portrait.
I need to do more tests, and will do so with a new/clean project.
You need to get the offset camera position in the Awake or Start function. In the Update function, apply that offset value to the value from the gyro sensor.
It looks like you already know offset should be used but you are not doing that the right way. The confusing part is getting the offset which requires subtracting the current camera rotation from the gyro sensor value.
To subtract a Quaternion multiply the Inverse not just the Quaternion:
Quaternion = Quaternion *Quaternion.Inverse
To add a Quaternion multiply the Quaternion:
Quaternion = Quaternion * Quaternion.
This is what your code should look like:
Quaternion offset;
void Awake()
{
Input.gyro.enabled = true;
}
void Start()
{
//Subtract Quaternion
offset = transform.rotation * Quaternion.Inverse(GyroToUnity(Input.gyro.attitude));
}
void Update()
{
GyroModifyCamera();
}
void GyroModifyCamera()
{
//Apply offset
transform.rotation = offset * GyroToUnity(Input.gyro.attitude);
}
private static Quaternion GyroToUnity(Quaternion q)
{
return new Quaternion(q.x, q.y, -q.z, -q.w);
}
I hade trouble with this and it wasn't working in build this is what I found and this script has worked.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GyroMovement : MonoBehaviour
{
// Start is called before the first frame update
//Movement
[SerializeField] float speed = 3.3f;
private float rotspeed = 90f;
private Vector3 moveDirection = Vector3.zero;
[SerializeField] private CharacterController controller;
//Rotation
private float _initialYAngle = 0f;
private float _appliedGyroYAngle = 0f;
private float _calibrationYAngle = 0f;
private Transform _rawGyroRotation;
private float _tempSmoothing;
//settings
private float _smoothing = 0.1f;
private void Update(){
//Movement
//Vector3 move = new Vector3 (Input.acceleration.x * speed * Time.deltaTime, 0f, -Input.acceleration.z * speed * Time.deltaTime);
//Vector3 rotMovement = transform.TransformDirection(move);
//controller.Move(rotMovement);
//Rotation
ApplyGyroRotation();
ApplyCalibration();
transform.rotation = Quaternion.Slerp(transform.rotation, _rawGyroRotation.rotation, _smoothing);
}
private IEnumerator Start(){
Input.gyro.enabled = true;
Application.targetFrameRate = 60;
_initialYAngle = transform.eulerAngles.y;
_rawGyroRotation = new GameObject("GyroRaw").transform;
_rawGyroRotation.position = transform.position;
_rawGyroRotation.rotation = transform.rotation;
yield return new WaitForSeconds(1f);
StartCoroutine (CalibrateYAngle());
}
private IEnumerator CalibrateYAngle(){
_tempSmoothing = _smoothing;
_smoothing = 1f;
_calibrationYAngle = _appliedGyroYAngle - _initialYAngle;
yield return null;
_smoothing = _tempSmoothing;
}
private void ApplyGyroRotation(){
_rawGyroRotation.rotation = Input.gyro.attitude;
_rawGyroRotation.Rotate(0f, 0f, 180f, Space.Self);
_rawGyroRotation.Rotate(90f, 180f, 0f, Space.World);
_appliedGyroYAngle = _rawGyroRotation.eulerAngles.y;
}
private void ApplyCalibration(){
_rawGyroRotation.Rotate(0f, -_calibrationYAngle, 0f, Space.World);
}
public void SetEnabled (bool value){
enabled = true;
StartCoroutine(CalibrateYAngle());
}
}

Categories