Strange behaviour of the Cinemachine virtual camera - c#

I am using the new input system in my unity project. I also use Cinemachine. I use Cinemachine Input Provider to change the input from the old to the new system.
When I change max speed to Input Value Gain in speed field of virtual camera's settings (I did it because it is the most comfortable way to control camera) I face a problem.
My problem: When my character moves after some time the camera speed changes. If I start to move in the opposite direction, the camera speed returns to normal.
This is independent of the other components in the scene. My scene has only plane, cube, camera and my character.
Here's my character control code (ignore the awful calculation of movement direction):
private Rigidbody _rb;
private Vector2 _moveDirection;
private float speed = 5f;
private void Awake()
{
_rb = GetComponent<Rigidbody>();
Cursor.lockState = CursorLockMode.Locked;
}
public void OnMove(InputAction.CallbackContext context)
{
_moveDirection = context.ReadValue<Vector2>();
}
private void FixedUpdate()
{
Move(_moveDirection);
}
private void Move(Vector3 moveDirection)
{
float scaledMoveSpeed = speed * Time.deltaTime;
moveDirection = new Vector3(Camera.main.transform.forward.x, 0, Camera.main.transform.forward.z).normalized * moveDirection.y + new Vector3(Camera.main.transform.right.x, 0, Camera.main.transform.right.z).normalized * moveDirection.x;
_rb.MovePosition(transform.position + moveDirection * scaledMoveSpeed);
}
Here's a screenshot of the camera settings and Cinemachine Input Provider:
And screenshots of the Input Actions settings:

I found a solution for those who will ever face this problem! On your main camera, in the CinemachineBrain component, change the Update Method from Smart Update to Late Update. That should help

Related

I want my camera to move further from the player the faster they go. Unity C#

I'm working on a 3d side scroller BMX game. It's going pretty well so far but one of the problems I'm having now is that when going very fast it's hard for the player to see the upcoming terrain and will crash into things they would otherwise easily avoid. How can I get the camera to move further back and get a wider view for the player while moving? Here's the current camera code.
private Vector3 _offset;
[SerializeField] private Transform target;
[SerializeField] private float smoothTime;
private Vector3 _currentVelocity = Vector3.zero;
private void Awake()
{
_offset = transform.position - target.position;
}
private void LateUpdate()
{
Vector3 targetPosition = target.position + _offset;
transform.position = Vector3.SmoothDamp(current: transform.position, targetPosition, ref _currentVelocity, smoothTime);
I'm very new to Unity and I really have no idea where to start. I tried adding a rigidbody to the camera and maybe change it's distance with .magnitude but I'm really very new to this.
According to my experience in racing games, what you want to change should be the FOV rather than moving further, so you can simply try this:
cam.fieldOfView = Mathf.Clamp(playerSpeed * factor, minFOV, maxFOV);

Keeping camera & mouse movement speeds the same on Drag in Unity3D

this question is a bit long but please bare with me.
I am working with Unity3D's newer input system, and I've been able to set up camera movement so when the user clicks the middle mouse button, they can drag the camera around along the X- & Y-axis. However, has a very parallax-y feel to it, which I am trying to avoid. From my understanding this is happening because the speed of the mouse movement & the camera movements are not the same (See, visual).
My InputController class:
public class InputController : MonoBehaviour
{
private InputControls inputControls;
[Header("Camera Movement")]
[SerializeField] CameraController cameraController;
private InputAction.CallbackContext context;
void Awake()
{
inputControls = new InputControls();
}
private void Start()
{
inputControls.Mouse.MiddleButton.started += MiddleButton_started;
}
public void MiddleButton_started(InputAction.CallbackContext ctx)
{
context = ctx;
}
private void Update()
{
bool mouseIsDown = context.performed;
if (mouseIsDown)
{
Vector2 delta = inputControls.Mouse.DeltaPosition.ReadValue<Vector2>();
cameraController.Move(delta, false);
}
}
}
My CameraController class:
public class CameraController : MonoBehaviour
{
[SerializeField] Vector2 minPosition;
[SerializeField] Vector2 maxPosition;
[SerializeField] float speed = 3;
[SerializeField] float zPosition = -10f;
private Camera mainCam;
private void Start()
{
mainCam = GetComponent<Camera>();
}
public void Move(Vector2 deltaPosition, bool convertToViewportPoint = true)
{
if (convertToViewportPoint) deltaPosition = mainCam.ScreenToViewportPoint(deltaPosition);
Vector3 moveTo = new Vector3(deltaPosition.x, deltaPosition.y, 0);
Vector3 target = transform.position - moveTo;
float clampedX = Mathf.Clamp(target.x, minPosition.x, maxPosition.x);
float clampedY = Mathf.Clamp(target.y, minPosition.y, maxPosition.y);
transform.position = Vector3.Lerp(transform.position, new Vector3(clampedX, clampedY, -10), speed * Time.deltaTime);
}
}
Now, in this version of the CameraController, the parallax-y feel might be coming from the fact that the Lerp speed is constant, whereas the speed of the mouse movement is not.
However, I've tested it with various magnitudes (ie., the magnitudes of the delta mouse position, the current mouse position, the current mouse position subtracted from the delta mouse position, etc...) with generally the same results -- either the camera moves too fast for the mouse or vice versa.
From my limited but growing understanding of trig, magnitudes represents the speed of a vector but I CANNOT get the speed of the camera movement and the speed of the mouse movement to match up. I would like for this to happen so that when the user clicks a certain point, that point generally stays under the cursor when in movement (See other visual).
Can someone help me understand how I might achieve this?
Thanks kindly.
What I did to solve this, in case anyone comes across this, is get the position of the cursor when the mouse is first clicked. We can call that dragOrigin. Then we can get the change in position as the mouse moves (polling the input through Unity's input system can be done through an Update function). Then we subtract the new mouse position from dragOrigin. Once we have that difference -- lets call it deltaPosition -- we just add it to the camera's current position.
To ensure that the speed matches that of the mouse, run the deltaPosition and the currentMousePosition through SmoothDamp to get the velocity of the change. Its magnitude will be the speed you want the camera to move.
So for example:
// Call this when the user first clicks the mouse.
// Lets assume this is part of a class that controls the camera.
public void SetDragOrigin(Vector2 mousePosition)
{
// could probably cache Camera.main for efficiency
dragOrigin = Camera.main.ScreenToWorldPoint(mousePosition);
}
// This is called in an update function of another class that deals with input.
// (Or perhaps you can simply pass the input controls to the class controlling the camera, but that's not the case here).
public void Move(Vector2 newMousePosition)
{
mousePosition = mainCam.ScreenToWorldPoint(mousePosition);
Vector2 deltaPosition = dragOrigin - mousePosition;
Vector3.SmoothDamp(deltaPosition, mousePosition, ref dragVelocity, 0.1f, 250f, Time.deltaTime);
cameraPosition += new Vector3(deltaPosition.x, deltaPosition.y, 0) * dragVelocity.magnitude * Time.deltaTime;
// anything else you want to do like clamping camera position
// ....
}
One thing to note here, is that the 5th argument of SmoothDamp is the maxSpeed. I hardcoded it in this example, but you might want to play around with it. When I did not set the maxSpeed, there was some wonky things happening to the dragVelocity over time, so it may be better to set the maxSpeed to what suits you best.

How to make the main camera rotate with the player?

I have the following script which should make the main camera follow and rotate with the player's movements.
public class FollowPlayer : MonoBehaviour
{
[SerializeField]
float mouseSensitivity;
public Vector3 cameraOffset;
public Transform Player;
public Transform mainCamera;
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
cameraOffset = transform.position - Player.transform.position;
}
void Update()
{
Rotate();
}
private void Rotate()
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
Player.Rotate(Vector3.up, mouseX);
mainCamera.Rotate(Vector3.up, mouseX); //shows abnormal rotation (hides the player as well)
}
private void LateUpdate()
{
Vector3 newPosition = Player.position + cameraOffset;
transform.position = newPosition;
}
}
The camera follows the player, however, but it does not rotate with the player's rotations. Please note that making the main camera the child of the player is not an option here, since I have to use this script on multiplayer. I want the mouse to be able to rotate both the main camera and the player at the same time.
The reason the camera is not rotating, is that you capture the initial offset on start, which is expressed in absolute (world space) position. This can be easily fixed using transform.TransformPoint method. What you then need to do is address camera rotation. In the simplest case you can just use 'LookAt' method
private void LateUpdate()
{
Vector3 newPosition = Player.position + Player.TransformPoint(cameraOffset);
mainCamera.position = newPosition;
mainCamera.LookAt(Player.position, Vector3.up);
}
I also noticed that you use transform.position (a transform from the object your script is attached to) but then you also use mainCamera transform as a seperate transform, mixing it like that might lead to confusion later. You should either always access the camera via mainCamera reference, or you could always keep the script attached to the camera and use transform reference.
I also noticed that you use one script to do two seperate things, it controls both player rotation and camera position/rotation while following the player. While there is nothing stoping you from doing that, its often a good idea to split it into doing two things each doing one logical thing

Projectile not shooting direction of my weapon

So my game is sort of like a 3d top down shooter, so I want my gun to shoot wherever the mouse is and it wont go to the mouse unless im shooting down. If you've seen brackyes game called ball wars, im sort of trying to replicate one like that but the projectile is not shooting the right way.
I got my script from blackthornprods ranged combat tutorial (which is for 2d so maybe thats the issue but I dont know how to solve it) :
public float speed;
public float lifeTime;
private void Start()
{
Invoke("DestoryProjectile", lifeTime);
}
private void Update()
{
transform.Translate(transform.up * speed * Time.deltaTime);
}
void DestroyProjectile()
{
Destroy(gameObject);
}
Appreciate anyone to try!
Here is my other script:
Camera mainCam;
public GameObject projectile;
public Transform shotPoint;
private float timeBtwShots;
public float startTimeBtwShots;
void Awake()
{
mainCam = Camera.main;
}
void Update()
{
float objectDepthFromCamera = Vector3.Dot(
transform.position - mainCam.transform.position,
mainCam.transform.forward);
Vector3 cursorWorldPosition = mainCam.ScreenToWorldPoint(Input.mousePosition
+ Vector3.forward * objectDepthFromCamera);
Vector3 localUpNeeded = Vector3.Cross(Vector3.forward,
cursorWorldPosition - transform.position);
transform.rotation = Quaternion.LookRotation(Vector3.forward, localUpNeeded);
if(timeBtwShots <= 0)
{
if (Input.GetMouseButtonDown(0))
{
Instantiate(projectile, shotPoint.position, transform.rotation);
timeBtwShots = startTimeBtwShots;
}
}
else
{
timeBtwShots -= Time.deltaTime;
}
}
Projectile not shooting direction of my weapon. Simple solution -
First instantiate or pool the instance of projectile.
Set rotation of projection from the rotation of weapon & set location to spawn point
Now fire, or whatever strategy you are using
Consider Global rotation, if you need help, tell me, I will edit and give a snippet of code.
This should work. If doesn't post all necessary code, I will give a better solution.
Here is sample github project I created, just for you. I opened Unity nearly after a year. Please check all the versions.
Must check :
firing in facing direction 💋
just instantiate at spawn point
just added some rotation
I think this should give you concept.
Press X for a rantom rotation
Press Space to shoot a projectile :lol:
The white cube shows that it always shoots at a constant direction

I have a cube that spins all over the place when I hit an object.(the camera and character spins) UNITY

I have a simple movement that relvolves around moving foward depending on where I look. The camera is made to follow the player. The problem I am havaing is that whenever I hit an object, my character(along with the camera) start spinning crazily all over the place. (I am new to coding)
Here is the code to the movement of where my character is facing :
public class Player : MonoBehaviour {
public float movementSpeed = 10;
public float turningSpeed = 60;
public Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody> ();
}
void Update() {
float horizontal = Input.GetAxis("Mouse X") * turningSpeed *
Time.deltaTime;
transform.Rotate(0, horizontal,0);
float vertical = Input.GetAxis("Mouse Y")* turningSpeed * Time.deltaTime;
transform.Rotate(vertical, 0, 0);
float movement = Input.GetAxis("Foward") * movementSpeed *
Time.deltaTime;
transform.Translate(0, 0,movement);
}
}
(Sorry for bad format)
The Mouse X just makes it so that it rotates on the x axis of mouse(same with y axis). The Foward is just the vertical input preset in unity.
Here is the code to the lookAt player :
public class LookAtCamera : MonoBehaviour {
public GameObject target;
void LateUpdate() {
transform.LookAt(target.transform);
}
}
Answer
I believe your rigidbody is being more heavily affected than what you desire by the bounce force occuring as you hit the object.
Possible solutions
Depending on which collider type acts as your legs, the weight of the objects involved, what behaviour you intend and more the solution can vary.
Possible solution 1:
One option is to freeze the rotation of your object on it's Rigidbody component, you can decide which axes to freeze rotation on. If freezed they can't be pushed by outside forces.
Possible solution 2:
If you wish the player to only be affected by your script you can set the rigidbody kinematic, meaning that it only is affected by scripts and animation. This is a contrast to being set to dynamic where other objects can affect it.
Possible solution 3:
Play around with the angular drag and mass of the rigidbody to slow down rotation.

Categories

Resources