Delay when calculating a players movement direction - unity3d

I am trying to determine the direction of a transform. I originally tried to do this by tracking the rigidbody.velocity but that property seems unreliable so I am having to calculate the direction manually. The yellow line draws fine and it does point in the wrong direction however it appears to be delayed
I am calling the following method in my update method:
void DetermineMovementDirection()
{
currentLoc = (transform.position - prevLoc) / Time.deltaTime;
Vector3 t = (prevLoc + currentLoc).normalized;
Debug.DrawLine(transform.position, transform.position + t * 5, Color.yellow);
}
I would expect the yellow line to always point in the direction the player was moving rather than have a long delay. How can I fix this?
As requested the movement function:
void Update()
{
float inputZ = Input.GetAxis("Horizontal");
float inputX = Input.GetAxis("Vertical");
if (movementAllowed)
if (inputZ != 0 || inputX != 0)
{
transform.eulerAngles = new Vector3(0, Mathf.Atan2(inputZ, inputX) * 180 / Mathf.PI, 0);
transform.Translate(moveSpeed * inputZ * Time.deltaTime, 0f, moveSpeed * inputX * Time.deltaTime, Space.World);
}
}
And I am simply updating at the end of the update method:
prevLoc = transform.position;

Related

Unity Setting Animator Parameters

I'm trying to animate my player in Unity using the animator component but for some reason it seems that my character is stuck in the idle animation and I can't change the animation parameters from my code. I'm using a 2D freeform direction blend tree in unity, and I'm not exactly sure why it's not working. The animations themselves seem to be working fine when I change the parameters using the inspector.
`
void Update()
{
groundedPlayer = characterController.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector2 input = moveAction.ReadValue<Vector2>();
Vector3 move = new Vector3(input.x, 0, input.y);
move = move.x * cameraTransform.right.normalized + move.z * cameraTransform.forward.normalized;
move.y = 0f;
animator.SetFloat(moveXAnimationParameterId, input.x);
animator.SetFloat(moveZAnimationParameterId, input.y);
characterController.Move(move * Time.deltaTime * playerSpeed);
if (jumpAction.triggered && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
if (move != Vector3.zero)
{
animator.Play(runningJumpAnimation);
}
else
{
animator.Play(jumpAnimation);
}
}
playerVelocity.y += gravityValue * Time.deltaTime;
characterController.Move(playerVelocity * Time.deltaTime);
float targetAngle = cameraTransform.eulerAngles.y;
Quaternion targetRotation = Quaternion.Euler(0, targetAngle, 0);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
}
instead of using animator.Play I suggest you use conditions using for example :
_anim.SetBool("isRunning",true);

How can I get this jumping and movement code to work together?

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.

How to prevent tilting over in a unity object

I've got a hover tank and I'm working on a controller for it. The goal is to have the float above the ground, but I don't want it to tilt over more the a degree or two. I want it to basically stay level all the time.
I'm using a Rigidbody on the tank to control it with .MovePosition and .MoveRotation. You can see the FixedUpdate function below. I've got a section below to keep thinks level, where I check if there tank is tipping past its maxTilt amount. If it is, the keep it at the max.
This makes the tank very jittery all the time. It looks like it's bouncing up and down quickly. I think its due to the hover forces, but I'm not sure.
How can I keep the tank level while still letting it hoover?
FixedUdpate
void FixedUpdate () {
if (!isServer) {
return;
}
CheckGrounded ();
Hoover ();
if (_moveForward) {
float moveAmount = moveSpeed * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
}
if (_moveBackward) {
float moveAmount = (-moveSpeed * 0.6f) * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
}
if (_turnLeft) {
Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, -angularSpeed, 0f) * Time.deltaTime);
_rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
}
if (_turnRight) {
Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, angularSpeed, 0f) * Time.deltaTime);
_rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
}
if (_jump && _isGrounded) {
_isJumping = true;
}
if (_isJumping && _jumpTimeLeft > 0) {
float moveAmount = jumpSpeed * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.up * moveAmount);
_jumpTimeLeft -= Time.deltaTime;
} else if (_isJumping) {
_isJumping = false;
_jumpTimeLeft = jumpTime;
}
// Keep things level
Vector3 rotation = _rigidbody.rotation.eulerAngles;
if (rotation.x > maxTilt) {
rotation.x = maxTilt;
} else if (rotation.x < -maxTilt) {
rotation.x = -maxTilt;
}
if (rotation.y > maxTilt) {
rotation.y = maxTilt;
} else if (rotation.y < -maxTilt) {
rotation.y = -maxTilt;
}
if (rotation.z > maxTilt) {
rotation.z = maxTilt;
} else if (rotation.z < -maxTilt) {
rotation.z = -maxTilt;
}
Quaternion q = new Quaternion ();
q.eulerAngles = rotation;
_rigidbody.rotation = q;
}
Hoover
void Hoover() {
foreach (Transform hoverPoint in hooverPoints) {
Ray ray = new Ray (hoverPoint.position, -hoverPoint.up);
RaycastHit hitInfo;
if (Physics.Raycast (ray, out hitInfo, hooverHeight)) {
float distance = Vector3.Distance (hoverPoint.position, hitInfo.point);
if (distance < hooverHeight) {
_rigidbody.AddForceAtPosition (hoverPoint.up * hooverForce * (1f - distance / hooverHeight), hoverPoint.position, ForceMode.Force);
}
}
}
}
I'm thinking that the reason you are seeing 'jitters' is because...
All physics calculations and updates occur immediately after FixedUpdate.
https://docs.unity3d.com/Manual/ExecutionOrder.html
Because you are adjusting the tilt in FixedUpdate(), which is then immediately followed by the Physics Engine running its calculations this will sometimes alter the tilt value giving a 'jitter'. The reason I say sometimes is because FixedUpdate() can run multiple times per frame (FPS dependant), which potentially means the following call order for a single frame:
FixedUpdate() // start frame
PhysicsEngine
FixedUpdate() // end frame
In the case above, there would be no jitter because you re-correct the tilt after the physics engine has done its thing - by complete fluke. However when you don't get a second FixedUpdate() call on a frame, you will have:
FixedUpdate() // start frame
PhysicsEngine // end frame
Which will result in your jitter.
So my suggestion is to break up your FixedUpdate() and offset any tilt corrections to LateUpdate(). Becuase LateUpdate() is always the last update call prior to the rendering of the frame.

Unity BoxCollider2D rotation not the same as GameObject rotation

I'm having a bit of an issue with a BoxCollider2D I have on my GameObject. When I rotate the GameObject, the BoxCollider2D rotates with it, but not as fast. Is there a way to get the BoxCollider2D to move at the same rate as the GameObject? I feel like I'm missing something obvious.
Before Rotation
After Rotation
Below is my code for the movement of the player:
Animator anim;
Rigidbody2D rbody;
float speed = 0f;
public float moveSpeed = 0.6f;
public float acceleration = 0.2f;
public int turnSpeed = 20;
bool sails = false;
// Use this for initialization
void Start () {
anim = GetComponentInChildren<Animator> ();
rbody = GetComponent<Rigidbody2D> ();
}
// Update is called once per frame
void Update () {
if (sails) {
rbody.transform.Translate (transform.right * (speed * Time.deltaTime));
speed += acceleration * Time.deltaTime;
if (speed > moveSpeed)
speed = moveSpeed;
if (Input.GetKey (KeyCode.LeftArrow)) {
rbody.transform.Rotate (0,0,turnSpeed * Time.deltaTime);
}
if (Input.GetKey (KeyCode.RightArrow)) {
rbody.transform.Rotate (0,0,-turnSpeed * Time.deltaTime);
}
}
if (!sails) {
rbody.transform.Translate (transform.right * (speed * Time.deltaTime));
speed += -acceleration * Time.deltaTime;
if (speed < 0f)
speed = 0f;
}
if (Input.GetKeyDown (KeyCode.Space)) {
sails = !sails;
anim.SetBool ("sailsDown", sails);
}
}
The problem is not your rotation, but how you are applying the the movement.
You are using transform.right which is the local right of the object. But then, when applying the translate you apply it to the object locally too.
For example, if your ship is facing down (rotation.Z = -90), transform.right value is (0,-1,0), in World coordinates this is equal to "down".
But then you use rbody.transform.Translate(vector) which will translate the object using local coordinates. This means that if you pass it the "down" vector, it will be moving down locally, which in the case of being rotated -90 inthe Z axis, means moving "left" relative to the world.
You have to change this line:
rbody.transform.Translate(transform.right * (speed * Time.deltaTime));
To:
rbody.transform.Translate(transform.right * (speed * Time.deltaTime),Space.World);
Or:
rbody.transform.Translate(Vector2.right * (speed * Time.deltaTime));

Restrict Direction of rotation in Realtime

have a hand of clock which the player once starts rotating (Dragging) CCW until he completes one full rotation. ( Without lifting drag )
I am trying to lock the rotation to only CCW direction while/once the player starts rotating. I got help from the following links : [Detect Direction][1] by #BobBobson108
Here is gif of what is actually happening: Demo
void OnMouseDrag()
{
//rotation
Vector3 mousePos = Input.mousePosition;
mousePos.z = 5.23f;
Vector3 objectPos = Camera.main.WorldToScreenPoint(transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle - 90f));
hand_vector = transform.up;
cross_product = Vector3.Cross(ref_vector, hand_vector);
dot_product = Vector3.Dot(cross_product, transform.forward*-1);
//Debug.Log("Hand Vector: " + hand_vector);
//Debug.Log("Ref Vector: " + ref_vector);
Debug.Log(cross_product);
Debug.Log(dot_product);
}
I tried to debug the values of the cross product, but the direction of resultant vector seems to be same even when when the player starts backward rotation.
Also the cross product vector changes direction only when the player starts rotation in CW direction from the default position i.e. 12 'o clock.
I have very less experience of working with Quaternions and rotations. Any help will be highly helpful. Thanks !!!
Desired
Use http://docs.unity3d.com/ScriptReference/Vector3.Angle.html function to get the value of the angle. You should get a positive/negative value depending on the direction.
You could then lock the rotation if the sign is not the correct direction you want.
I managed to figure out a solution to above question. Here I am posting my solution in case anyone stumbles across a similar situation in future.
void OnMouseDrag()
{
transform.Rotate(new Vector3(0,0, Mathf.Sqrt(Input.GetAxis("Mouse X") * Input.GetAxis("Mouse X") + Input.GetAxis("Mouse Y") * Input.GetAxis("Mouse Y"))));
/*
Vector3 mousePos = Input.mousePosition;
mousePos.z = 5.23f;
Vector3 objectPos = Camera.main.WorldToScreenPoint(transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
print("Angle is :");
print(Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90f);
if (counter_clockwise)
{
if (Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90f > 0)
{
angle = Mathf.Max(angle, Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90);
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
if (Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90f < 0)
{
angle = Mathf.Max(angle, 360 + (Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg - 90));
transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
}
*/
glow_color.a = 1f;
child_yellowglow.color = glow_color;
}
I am setting the direction bools from using this :
void OnMouseDown()
{
Vector3 mouseDragStartPos = Input.mousePosition;
print("Mouse pos: " + mouseDragStartPos);
print(" ref_vector" + ref_vector);
if (mouseDragStartPos.x < ref_vector.x)
{
clockwise = false;
counter_clockwise = true;
print("Left !!!");
}
if (mouseDragStartPos.x >= ref_vector.x)
{
clockwise = true;
counter_clockwise = false;
print("Right !!!");
}
}
Hope this helps !!!