Vector3.Lerp() not smoothing correctly - c#

I'm working on a hand sway system. And the problem is that when I use Vector3.Lerp(); for it, it looks really bad and laggy :
https://streamable.com/64y52o
And this is my source code :
Transform target;
float smooth;
void Update()
{
transform.position = Vector3.Lerp(transform.position, target.transform.position, smooth * Time.deltaTime);
}
And this is my setup in editor :
enter image description here
The script is attached to Hand game object. And the target input is Hand Pos object in inspector.
I tried using both Vector3.Lerp(); and Vector3.Slerp(); but it didn't change anything.
I also tried running code on both Update() and FixedUpdate() and even LateUpdate() but not much changed.
Full code for source :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HandSway : MonoBehaviour
{
public float smooth;
public float swayMultiplier = 1f;
public Vector3 handOffset;
public Transform target;
private void Update()
{
float x = Input.GetAxisRaw("Mouse X") * swayMultiplier;
float y = Input.GetAxisRaw("Mouse Y") * swayMultiplier;
Quaternion xRot = Quaternion.AngleAxis(-y, Vector3.right);
Quaternion yRot = Quaternion.AngleAxis(x, Vector3.up);
Quaternion rotation = xRot * yRot * target.rotation;
transform.localRotation = Quaternion.Slerp(transform.localRotation, rotation, smooth * Time.deltaTime);
transform.position = Vector3.Lerp(transform.position, target.transform.position, smooth * Time.deltaTime);
}
}

There are a few different approaches when animating an object.
One is to start from position A and interpolate over T seconds to position B. This would be expressed in code like:
t += Time.deltaTime;
transform.position = Vector3.Lerp(A, B, t / T);
This should move the object with a constant speed. If you want to control the speed instead you you could compute T = A.Distance(B) / speed. If you want a constant acceleration instead you could use SLerp.
If you want the object to track the target continuously rather than animating it I would probably not recommend just using Lerp. This will result in a speed that is completely dependent on the distance. This would be equal to a proportional only regulation, see PID controller. Notably, if your proportional factor (i.e. smooth * Time.deltaTime) is larger than 1 you will get oscillations, that might be what is happening.
I would probably recommend that you instead calculate the direction to the target, and cap the speed. You might also want to cap the acceleration for a smoother animation.

Related

How to make a game object move to the opposite direction of a constantly moving object? Unity 2D

I have a game object that constantly rotates around another one:
What I am trying to achieve is to have the circle move in the opposite direction of the square when I press the space key, the square will simulate a propeller, for example:
This is the code I have, which kinda works:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] GameObject rotatingPropellant;
[SerializeField] float rotationSpeed;
[SerializeField] float impulseForce;
Rigidbody2D playerRb;
void Start()
{
playerRb = GetComponent<Rigidbody2D>();
}
void Update()
{
RotatePropellant();
Move();
}
void RotatePropellant()
{
rotatingPropellant.transform.RotateAround(transform.position, new Vector3(0f, 0f, 1f), rotationSpeed * Time.deltaTime);
}
void Move()
{
if (Input.GetButtonDown("Jump"))
{
playerRb.velocity = -rotatingPropellant.transform.position * impulseForce * Time.deltaTime;
}
}
}
But sometimes the circle moves up even if the square is up (meaning that the circle should be pushed down), not sure if maybe the signs are not correct or if I should be approaching this with a different method
So this:
playerRb.velocity = -rotatingPropellant.transform.position * impulseForce * Time.deltaTime;
relies on rotatingPropellant position relative to World's zero position (Vector3.zero), which might work only if the propellant revolves around this zero point.
What you should probably do instead is get the difference:
Vector3 dir = (rotatingPropellant.transform.position - transform.position).normalized;
playerRb.velocity = dir * impulseForce * Time.deltaTime;
Also, instead of changing velocity, you can add force instead:
Vector3 dir = (rotatingPropellant.transform.position - transform.position).normalized;
playerRb.AddForce(dir * impulseForce, ForceMode2D.Impulse);
To get movement direction, you can use this vector formula AB = B - A. This formula will give you the position vector of A Related to B space and if you normalize this vector you will get the movement direction
A is sphere and B is Square at here. Check Vector Addition and Substraction.

Relative input but global movement in Unity

I'm working on a spaceflight game in unity and stumbled across this simple logical error. I want to be able to add relative movement to my spaceship, but also for it to keep the momentum in that direction when you turn. I've sot a separate script for looking around and movement. Here is my movement source code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController ship;
public float speed = 0.001f;
float momentum = 0f;
Vector3 velocity;
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
void Update()
{
momentum = momentum + Input.GetAxis("Vertical");
Vector3 move = transform.forward * momentum * 0.001f;
ship.Move(move);
}
}
I know this is a simple question, my brain is just kind of stuck right now. Thanks! ~OwenPT
Do I understand correctly that you want the spaceship fly forward and when it turns right or left it must continue flying forward?
Your spaceship must have component rigidbody (I think it does) and you get mode him using function GetComponent().AddForce. There you can choose the ForceMode. There are 4 kinds of force_mode:
Force - Add a continuous force to the rigidbody, using its mass.
Acceleration - Add a continuous acceleration to the rigidbody, ignoring its mass.
Impulse - Add an instant force impulse to the rigidbody, using its mass.
VelocityChange - Add an instant velocity change to the rigidbody, ignoring its mass.
So, choose the one you need and the spaceship must continue flying forward after turning
You've neglected your velocity variable. You're applying a scalar speed (momentum) in the direction of facing (transform.forward).
If you want to have a feel of momentum, you need to deal with Acceleration:
public CharacterController Ship;
public float AccelerationFactor = 1.0f;
public float BrakingFactor = 0.1f;
public float MaxSpeed = 20.0f;
private Vector3 Velocity;
void Update()
{
var totalBraking = Velocity.normalized * BrakingFactor;
var totalAcceleration = transform.forward * AccelerationFactor * Input.GetAxis("Vertical");
Velocity = Velocity + (totalAcceleration + totalBraking) * Time.deltaTime;
Velocity = Vector3.ClampMagnitude(Velocity, MaxSpeed);
Ship.Move(Velocity * Time.deltaTime);
}

Camera Rotation value on y axis get high float number by time

i try to create free look camera i was follow tutorial on YouTube everything work fine except i noticed that the rotation value about the y axis which is stored in float variable the angle value is getting Continue to accumulate i try to clamp it but its result in undesired behavior i also try the mathf.repeat the same i tried to zero the angle if it larger than 360 but this create another instant rotation in the opposite dir , i use the += operator which i think it causes this if I am not mistaken
my question dose this affect the performance i target mobile device's in general
If it affects performance, how should I deal with this problem?
thank you for any help really
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Camera : MonoBehaviour
{
public Transform target;
public float destotarget;
public float sensetivity;
public float smoothTime;
public float yaw;
public float pitch;
public Vector2 minandmax = new Vector2(34, 54);
public Vector3 currnetrot;
public Vector3 velocitysmooth;
// Update is called once per frame
void LateUpdate()
{
yaw += Input.GetAxis("Mouse X") * sensetivity;
pitch += Input.GetAxis("Mouse Y") * sensetivity;
pitch = Mathf.Clamp(pitch, minandmax.x, minandmax.y);
currnetrot = Vector3.SmoothDamp(currnetrot, new Vector2(pitch, yaw), ref velocitysmooth, smoothTime);
transform.eulerAngles = currnetrot;
transform.position = target.position - transform.forward * destotarget;
}
}
This shouldn't effect the performance much, but the only way to ever know is to profile:
https://docs.unity3d.com/Manual/profiler-profiling-applications.html
https://blog.theknightsofunity.com/mobile-optimization-unity-profiler/

How to add avoidance and chase behavior in Unity3D

I would like to implement the type of behavior where a group of prey is evading from a predator like this Game
I tried to write the script this way but I don't get the desired motion the prey just moves forward.
public Transform target;
public float damping;
public float drivespeed;
void Update () {
transform.Translate(Vector3.forward * Time.deltaTime * -drivespeed);
Quaternion rotation = Quaternion
.LookRotation(target.position - transform.position);
transform.rotation = Quaternion
.Slerp(transform.rotation, rotation, Time.deltaTime * damping);
}
Looks like you want
transform.Translate(transform.forward * Time.deltaTime * -drivespeed);
instead of
transform.Translate(Vector3.forward * Time.deltaTime * -drivespeed);
(Vector3.forward being a world forward vector, not the object's forward vector.)
It could be that the transform.translate is being called before the rotation logic but it's hard to tell what's going wrong here.
Is the object rotating correctly?
If so is the transform moving forward ignoring the rotation?
Are drivespeed and damping variables != 0?

Camera shaking on rotating player while crouching in unity

I am having a problem with the camera following the player. When the player moves, the camera shakes and this effect is more noticeable when the player is in the crouched position. I am using root motion for the player with animations by mixamo.
Player Script:
Transform cameraT;
void Start () {
cameraT = Camera.main.transform;
}
void FixedUpdate ()
{
float sideMotion = Input.GetAxis("SideMotion");
float straightMotion= Input.GetAxis("StraightMotion");
if (Mathf.Abs(sideMotion) > 0 || Mathf.Abs(straightMotion) > 0)
{
transform.eulerAngles = new Vector3(transform.eulerAngles.x,
cameraT.eulerAngles.y);
}
}
Camera Script:
public float distanceFromPlayer=2f;
public float mouseSensitivity=6;
public Transform player;
public Vector2 pitchConstraint= new Vector2(-30,80);
Vector3 rotationSmoothVelocity;
Vector3 currentRotation;
public float rotationSmoothTime = 0.2f;
float yaw; //Rotation around the vertical axis is called yaw
float pitch; //Rotation around the side-to-side axis is called pitch
private void LateUpdate()
{
yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
pitch = Mathf.Clamp(pitch, pitchConstraint.x, pitchConstraint.y);
currentRotation = Vector3.SmoothDamp
(currentRotation, new Vector3(pitch, yaw), ref rotationSmoothVelocity, rotationSmoothTime);
transform.eulerAngles = currentRotation;
transform.position = player.position - transform.forward * distanceFromPlayer;
}
For public transform I just added an empty game object to player chest level and parented it to the player. I got the rotating camera smoothly trick from an online tutorial but that exact thing won't work on player rotation though.
A character controller is attached to player without any rigidbody or collider.
You are going to want to use Lerp on the camera in order to smooth its motion from one position to another. The Scripting API has a good example of Vector3.Lerp.
So in your case, you could add a public variable for smoothing position as well. Something like positionSmoothTime. Then make a "Desired Position" variable, we'll call it destPosition.
Vector3 destPosition = player.position - transform.forward * distanceFromPlayer;
transform.position = Vector3.Lerp(transform.position, destPosition, positionSmoothTime);
This should effectively smooth it to where the stuttering should go away. Another thing that will help that someone else mentioned is using a part of the body that moves less (Like the head) as the target. This combined with the Lerp function will give you a smooth camera movement.
Another large help would be to move things into the Update() function. The reason being is FixedUpdate() doesn't get called every frame. So you could potentially get stutter as a result. If you move everything into Update() it will update every frame and help smooth things out. If you do this though you will need to multiply all movement by Time.deltaTime as shown in the example below.
Vector3 destPosition = (player.position - transform.forward * distanceFromPlayer) * Time.deltaTime;
For more examples, check the links to each function to see Unity's documentation on it. It has examples of everything I've shown here.

Categories

Resources