I want to write an IEnumerator to move at the desire distance at a specified time. I have tried to write the code for this but this is running a different way.
float moveDistance=1f;
float moveSpeed=5f;
float elapsedDistance = 0f;
while (elapsedDistance <= moveDistance)
{
elapsedDistance += Time.deltaTime * moveSpeed;
Vector3 cubeLocalPosition = transform.localPosition;
cubeLocalPosition.y += Time.deltaTime * moveDistance;
transform.localPosition = cubeLocalPosition;
yield return null;
}
Through this code, Object can't able to travel 1 unit distance. How can I correct this code?
Your while loop condition uses elapsedDistance which is increasing with moveSpeed. That latter is 5 so it will be 1 in 1/5 of a second. Your object is likely only moving 0.2unit.
you should use Mathf.Lerp or MoveTowards
float distance = 1f;
float time = 0f;
float period = 1f; // how long in second to do the whole movement
yield return new WaitUntil(()=>
{
time += Time.deltaTime / period;
float movement = Mathf.Lerp(0f, distance, time);
Vector3 cubeLocalPosition = transform.localPosition;
cubeLocalPosition.y += movement;
transform.localPosition = cubeLocalPosition;
return time >= 1f;
});
Following your own rotation, you calculate the finalpoint to go
and after,
you could use Vector3.Lerp or Vector.Slerp to move in the specified time..So the moving speed adapt itself following the time desired
var endpoint = transform.position + transform.forward.normalized * distance;
StartCoroutine(MoveToPosition(transform, endpoint, 3f)
:
:
public IEnumerator MoveToPosition(Transform transform, Vector3 positionToGO, float timeToMove)
{
var currentPos = transform.position;
var t = 0f;
while (t < 1f)
{
t += Time.deltaTime / timeToMove;
transform.position = Vector3.Lerp(currentPos, positionToGO, t);
yield return null;
}
transform.position = positionToGO;
}
Related
Hello i am new in the forum! I hope i am in the right section! Im trying to rotate a camera (that rapresent the player POV) using the mouse delta and im rotating the camera in local coordinates not world coordinates and i want avoid gimbal lock effect. I read somewhere on the internet that for that purpose i have to use quaternions, and i read how to do that. The problem is that axis rotations works well moving in local orientation but one of the axis is losing its local orientation and it rotate following the world coordinates orientation. I will post the code and i hope someone can help me and telling me where im doing things wrong. Thanks!
public class Player : MonoBehaviour {
[Header("Camera")]
[SerializeField] private Camera _camera;
[SerializeField] private Vector2 _xMinMaxRotation = new Vector2(-90, 90);
[SerializeField] private Vector2 _yMinMaxRotation = new Vector2(-90, 90);
[SerializeField] private float _mouseXSensistivity = 1;
[SerializeField] private float _mouseYSensistivity = 1;
[SerializeField] private float _mouseZSensistivity = 1;
[SerializeField] private float _xStartRotation = 0;
[SerializeField] private float _yStartRotation = 0;
private Vector2 _mouseDelta;
private float _rotY, _rotX, _rotZ;
//public GameObject head;
// Start is called before the first frame update
void Start() {
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update() {
_mouseDelta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
MoveCamera();
}
private void MoveCamera() {
_rotX += _mouseDelta.x * _mouseXSensistivity * Time.deltaTime * 100;
_rotX = Mathf.Clamp(_rotX, _xMinMaxRotation.x, _xMinMaxRotation.y);
_rotY += _mouseDelta.y * _mouseYSensistivity * Time.deltaTime * 100;
_rotY = Mathf.Clamp(_rotY, _yMinMaxRotation.x, _yMinMaxRotation.y);
//Calculation for RotZ
if (Input.GetKey(KeyCode.Q)) {
_rotZ += +_mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ > 25) _rotZ = 25;
}
else {
if (_rotZ > 0) {
_rotZ -= 2 * _mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ < 0) _rotZ = 0;
}
}
if (Input.GetKey(KeyCode.E)) {
_rotZ += -_mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ < -25) _rotZ = -25;
}
else {
if (_rotZ < 0) {
_rotZ -= 2 * -_mouseZSensistivity * Time.deltaTime * 50;
if (_rotZ > 0) _rotZ = 0;
}
}
Quaternion currentRotation = Quaternion.identity;
currentRotation = currentRotation * Quaternion.AngleAxis(_rotX, transform.up);
currentRotation = currentRotation * Quaternion.AngleAxis(-_rotY, transform.right);
currentRotation = currentRotation * Quaternion.AngleAxis(_rotZ, transform.forward);
_camera.transform.localRotation = currentRotation;
//head.transform.position = _camera.transform.position;
//head.transform.rotation = _camera.transform.rotation;
}
The last part with quaternions is where im trying to calculate angles in order to properly rotate in local coordinates.
You don’t need to use quaternions at all.
You can use transform.EulerAngles instead of the transform.rotation or transform.localEulerAngles instead of transform.LocalRotation.
I messed up the capitalization I’m sure.
Say you wanted to rotate the camera 10 degrees along the local x axis. That would look something like
transform.localEulerAngles = transform.localEulerAngles.Add(10,0,0);
That’s it as far as I know. If you wanna read more about this,
transfrom.localEulerAngles
If your question was completely different, let me know and I can change or remove my answer.
I'm trying to use the Character Controller component in Unity and I managed to make the movement code, however, I was unable to add jumping and gravity or at least have them work together so my temporary solution was to just break them into 2 different methods. This probably isn't ideal so how could I get this to work properly?
void Update()
{
GetInput();
JumpingCode();
MovementCode();
}
void JumpingCode()
{
// Jumping
if (jumpPressed && characterController.isGrounded)
velocityY = Mathf.Sqrt(jumpHeight * -2f * (gravity * gravityScale));
// Gravity
velocityY += gravity * gravityScale * Time.deltaTime;
Vector3 direction = new Vector3(horizontalInput, velocityY, verticalInput).normalized;
characterController.Move(direction * walkSpeed * Time.deltaTime);
}
void MovementCode()
{
Vector3 direction = new Vector3(horizontalInput, 0f, verticalInput).normalized;
if (direction.magnitude > 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + playerCamera.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
transform.rotation = Quaternion.Euler(0f, angle, 0f);
characterController.Move(moveDirection.normalized * walkSpeed * Time.deltaTime);
}
}
I can't understand how you're arriving at the values you're using there, but the solution would be to accumulate the outputs and then do the .Move() action once at the end, like:
void Update()
{
Vector3 motion;
GetInput();
motion += JumpingCode();
motion += MovementCode();
characterController.Move(motion*Time.deltaTime);
}
private Vector3 JumpingCode()
{
// stuff
return direction * walkSpeed;
}
private Vector3 MovementCode()
{
// stuff
return direction * walkSpeed;
}
Noteworthy there is that I dropped Time.deltaTime from your functions, but I don't know how you were using it in the code you provided.
I have a problem with blend tree which I'm using it and a script to change the float so I can control the player's animation. But the value of the parameter in the blend tree went crazy when it return to 0. It start appearing random numbers and the only way I know to fix it is to reset it manually.
This is what happen after hitting 0 -->
what happen.gif
Is it there way I use the blend tree wrong or a new bug in unity?. Any ideas??
AnimationController
animationController.jpg
ThirdPersonCharacterController
public float walkSpeed = 2;
public float runSpeed = 6;
public float gravity = -12;
public float jumpHeight = 1;
public float airControlPercent;
public float turnSmoothTime = 0.2f;
float turnSmoothVelocity;
public float speedSmoothTime = 0.1f;
float speedSmoothVelocity;
float currentSpeed;
float velocityY;
Animator animator;
Transform cameraT;
CharacterController controller;
void Start () {
animator = GetComponent<Animator> ();
cameraT = Camera.main.transform;
controller = GetComponent<CharacterController> ();
}
void Update () {
// input
Vector2 input = new Vector2 (Input.GetAxisRaw ("Horizontal"), Input.GetAxisRaw ("Vertical"));
Vector2 inputDir = input.normalized;
bool running = Input.GetKey (KeyCode.LeftShift);
Move (inputDir, running);
if (Input.GetKeyDown (KeyCode.Space)) {
Jump ();
}
// animator
float animationSpeedPercent = ((running) ? currentSpeed / runSpeed : currentSpeed / walkSpeed * .5f);
animator.SetFloat ("speedPercent", animationSpeedPercent, speedSmoothTime, Time.deltaTime);
}
void Move(Vector2 inputDir, bool running) {
if (inputDir != Vector2.zero) {
float targetRotation = Mathf.Atan2 (inputDir.x, inputDir.y) * Mathf.Rad2Deg + cameraT.eulerAngles.y;
transform.eulerAngles = Vector3.up * Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref turnSmoothVelocity, GetModifiedSmoothTime(turnSmoothTime));
}
float targetSpeed = ((running) ? runSpeed : walkSpeed) * inputDir.magnitude;
currentSpeed = Mathf.SmoothDamp (currentSpeed, targetSpeed, ref speedSmoothVelocity, GetModifiedSmoothTime(speedSmoothTime));
velocityY += Time.deltaTime * gravity;
Vector3 velocity = transform.forward * currentSpeed + Vector3.up * velocityY;
controller.Move (velocity * Time.deltaTime);
currentSpeed = new Vector2 (controller.velocity.x, controller.velocity.z).magnitude;
if (controller.isGrounded) {
velocityY = 0;
}
}
void Jump() {
if (controller.isGrounded) {
float jumpVelocity = Mathf.Sqrt (-2 * gravity * jumpHeight);
velocityY = jumpVelocity;
}
}
float GetModifiedSmoothTime(float smoothTime) {
if (controller.isGrounded) {
return smoothTime;
}
if (airControlPercent == 0) {
return float.MaxValue;
}
return smoothTime / airControlPercent;
}
Note: the parameter for the blend tree is "speedPercent"
I am not sure but i think that the value you are seeing is so near to zero that it has gone to exponential form as Unity always does for smaller values like
And this is because you are using smooth transition for SetFloat
animator.SetFloat ("speedPercent", animationSpeedPercent,
speedSmoothTime, Time.deltaTime);
Try this
animator.SetFloat ("speedPercent", animationSpeedPercent);
I want to have a coroutine to use the lerp function and so far I managed to do so partially. The characters will turn their position to face the target object. However, I want the characters to move their rotation starting from their own while what is currently happening is their rotation is set to some abstract value like X=0 and then it will start rotating them from there.
What I want to do is simply turn the character to face another transform smoothly. Here's the code:
public IEnumerator LookSlerpAt(Transform target, int seconds)
{
IsTurningHead = true;
Vector3 relativePos = target.position - this.transform.position;
Quaternion lookRotation = Quaternion.LookRotation(relativePos);
float elapsedTime = 0f;
float fraction = elapsedTime / seconds;
while (elapsedTime <= seconds)
{
this.transform.rotation = Quaternion.Lerp(target.rotation, lookRotation, fraction);
print($"rotation:{this.transform.rotation}");
elapsedTime += Time.deltaTime;
fraction = elapsedTime / seconds;
yield return Time.deltaTime;
}
IsTurningHead = false;
}
Thanks for your time
if you want to rotate smoothly to direction you could use that as coroutine: You specify the specified time to rotate and the velocity is automatically adjusted
public IEnumerator RotateToDirection(Transform transform, Vector3 positionToLook, float timeToRotate)
{
var startRotation = transform.rotation;
var direction = positionToLook - transform.position;
var finalRotation = Quaternion.LookRotation(direction);
var t = 0f;
while (t <= 1f)
{
t += Time.deltaTime / timeToRotate;
transform.rotation = Quaternion.Lerp(startRotation, finalRotation, t);
yield return null;
}
transform.rotation = finalRotation;
}
I have tried something like
float speed = (currentPosition - previousPosition).magnitude / Time.deltaTime
in Update().
But I get very bad results because currentPosition and previousPosition are too close. After subtraction there's too much rounding error. The speed values fluctuate too much.
And also I don't want to average across multiple frames because that produces delays and only improves the result a little.
Is there any better way to calculate the speed of an object?
You could use a coroutine that calculates the speed slower than every frame:
void OnEnabled() {
StartCoroutine(SpeedReckoner());
}
public float Speed;
public float UpdateDelay;
private IEnumerator SpeedReckoner() {
YieldInstruction timedWait = new WaitForSeconds(UpdateDelay);
Vector3 lastPosition = transform.position;
float lastTimestamp = Time.time;
while (enabled) {
yield return timedWait;
var deltaPosition = (transform.position - lastPosition).magnitude;
var deltaTime = Time.time - lastTimestamp;
if (Mathf.Approximately(deltaPosition, 0f)) // Clean up "near-zero" displacement
deltaPosition = 0f;
Speed = deltaPosition / deltaTime;
lastPosition = transform.position;
lastTimestamp = Time.time;
}
}