FixedUpdate or Update for collision detection and climbing slopes?
I am learning about unit and trying to figure out how to use the fixed update correctly. I saw that in the platformer kit 2D they used collision detection and movement in fixed update. Thanks in advance.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CustomPhysics : RaycastOrigins
{
protected Vector2 velocity;
private Rigidbody2D rb2d;
private ContactFilter2D contactFilter2D;
private RaycastHit2D[] hitBuffer = new RaycastHit2D[16];
private List<RaycastHit2D> hitList = new List<RaycastHit2D>();
private float shellRadius = 0.015f;
private float minGroundNormalY = 0.0f;
private float minMoveDistance = 0.001f;
bool grounded = false;
private Vector2 groundNormal;
private float gravityModifier = 1f;
protected Animator animator;
protected Vector2 targetVelocity;
private Vector2 currentPosition;
private Vector2 nextPosition;
public Collisions collisons2D;
public float maxClimbingAngle = 60;
public LayerMask groundMask=0;
int facingRight;
private void OnEnable()
{
}
public override void Awake()
{
base.Awake();
rb2d = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
}
// Start is called before the first frame update
public override void Start()
{
base.Start();
contactFilter2D.useTriggers = false;
contactFilter2D.SetLayerMask(Physics2D.GetLayerCollisionMask(gameObject.layer));
contactFilter2D.useLayerMask = true;
Debug.Log("verticalSpacing:" + verticalRaycastSpacing);
}
// Update is called once per frame
void Update()
{
}
private void FixedUpdate()
{
//if (groundNormal.x == 0)
//{
// groundNormal = Vector2.up;
//}
CalculateOrigins();
collisons2D.Reset();
//collisons2D.slopeAngleOld = collisons2D.slopeAngle;
//collisons2D.slopeAngle = 0;
grounded = false;
currentPosition = rb2d.position;
HorizontalCollisions(ref velocity);
VerticalCollisions(ref velocity);
Debug.Log("VELOCITY:"+velocity.y);
Debug.Log("SLOPEANGLE:" + collisons2D.slopeAngle);
nextPosition = currentPosition + velocity;
rb2d.MovePosition(nextPosition);
velocity = Vector2.zero;
Debug.Log("Collisions UP|DOWN:" + collisons2D.up + "|" + collisons2D.down);
Debug.Log("Collisions LEFT|RIGHT:" + collisons2D.left + "|" + collisons2D.right);
Debug.Log("CLIMBINGSLOPE:" + collisons2D.climbingSlope);
//Debug.Log("FacingRight:" + facingRight);
//Debug.Log("velocityY "+ velocity.y);
//animator.SetFloat("velocityX", velocity.x);
animator.SetBool("grounded", grounded);
//Debug.DrawRay(rb2d.position, new Vector2(0, 0.1f) * 10, Color.blue);
//Debug.DrawRay(rb2d.position, moveAlongGround, Color.green);
}
public void Move(Vector2 move)
{
velocity += move;
}
private void HorizontalCollisions(ref Vector2 velocity)
{
float distance = Mathf.Abs(velocity.x) + skinWidth;
float directionX = Mathf.Sign(velocity.x);
for (int i = 0; i < horizontalRaycastsCount; i++)
{
Vector2 rayOrigin = directionX == -1 ? origins.bottomLeft : origins.bottomRight;
rayOrigin += Vector2.up * (i * horizontalRaycastSpacing);
Debug.DrawRay(rayOrigin, Vector2.right * directionX * distance, Color.red);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * directionX, distance, groundMask);
if (hit)
{
Debug.Log("HIT I=" + i);
float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
if (i == 0 && slopeAngle <= maxClimbingAngle)
{
Debug.DrawRay(hit.point, hit.normal.normalized*hit.distance);
//velocity.x -= (hit.distance - skinWidth) * directionX;
float tmp = 0;
if (slopeAngle != collisons2D.slopeAngleOld)
{
Debug.Log("before velocity:" + velocity.x);
//tmp = velocity.x;
Debug.Log("distanceToSlopeStart:" + tmp);
//velocity.x = (hit.distance-skinWidth) * directionX;
//Debug.DrawRay(rb2d.position, velocity, Color.green);
//transform.Translate(new Vector2(directionX * tmp, 0));
//Debug.Log("after velocity:" + velocity.x);
//Debug.Log("HITPOINTX" + hit.point.x);
//Debug.Break();
//slopeAngle -= 5;
}
ClimbingSlope(ref velocity, slopeAngle);
//velocity.x += (hit.distance - skinWidth) * directionX;
//velocity.x +=tmp;
Debug.Log("VELOCITYX I=0:" + velocity.x);
}
Debug.Log("SLOPEANGLE I=" + i + ":" + slopeAngle);
if (!collisons2D.climbingSlope || slopeAngle > maxClimbingAngle)
{
velocity.x = (hit.distance - skinWidth) * directionX;
Debug.Log("VELOCITYX:" + velocity.x);
distance = hit.distance;
if (collisons2D.climbingSlope)
{
velocity.y = Mathf.Tan(collisons2D.slopeAngle * Mathf.Deg2Rad) * Mathf.Abs(velocity.x);
}
collisons2D.left = directionX == -1;
collisons2D.right = directionX == 1;
}
}
}
Debug.DrawRay(rb2d.position, velocity, Color.blue);
}
private void VerticalCollisions(ref Vector2 velocity)
{
float distance = Mathf.Abs(velocity.y)+skinWidth;
float directionY = Mathf.Sign(velocity.y);
for (int i = 0; i < verticalRaycastsCount; i++)
{
Vector2 rayOrigin = directionY == -1 ? origins.bottomLeft : origins.topLeft;
rayOrigin += Vector2.right * (i * verticalRaycastSpacing);
Debug.DrawRay(rayOrigin , Vector2.up * directionY * distance, Color.red);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, distance, groundMask);
if (hit)
{
velocity.y = (hit.distance - skinWidth) * directionY;
distance = hit.distance;
if (collisons2D.climbingSlope)
{
velocity.x = velocity.y / Mathf.Tan(collisons2D.slopeAngle * Mathf.Deg2Rad) * Mathf.Sign(velocity.x);
}
collisons2D.down = directionY == -1;
collisons2D.up = directionY == 1;
}
}
if (collisons2D.climbingSlope)
{
float directionX = Mathf.Sign(velocity.x);
Vector2 rayOrigin = directionX == -1 ? origins.bottomLeft : origins.bottomRight;
Debug.DrawRay(rayOrigin, Vector2.right * directionX * distance, Color.cyan);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * directionX, distance, groundMask);
if(hit)
{
float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
if (slopeAngle != collisons2D.slopeAngle)
{
//Debug.Break();
}
}
}
}
protected virtual void ComputeVelocity()
{
}
private void MoveHorizontal(ref Vector2 move)
{
}
private void MoveVertical(ref Vector2 move)
{
}
private void ClimbingSlope(ref Vector2 velocity,float slopeAngle)
{
float moveDistance = Mathf.Abs(velocity.x);
float climbingVelocityY = Mathf.Sin(slopeAngle * Mathf.Deg2Rad) * moveDistance;
if (velocity.y <= climbingVelocityY)
{
velocity.y = climbingVelocityY;
velocity.x = Mathf.Cos(slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(velocity.x);
//Vector2 rayOrigin = Mathf.Sign(velocity.x) == -1 ? origins.bottomLeft : origins.bottomRight;
//RaycastHit2D hit = Physics2D.Raycast(rayOrigin,velocity,)
collisons2D.down = true;
collisons2D.climbingSlope = true;
collisons2D.slopeAngle = slopeAngle;
//velocity.x -= tmp * directionX;
}
Debug.Log("CLIMBINGVELOCITY VELOCITY:" + velocity);
//Debug.Break();
}
public struct Collisions
{
public bool left, right;
public bool up, down;
public float slopeAngle;
public bool climbingSlope;
public float slopeAngleOld;
public void Reset()
{
left = right = false;
up = down = false;
climbingSlope = false;
slopeAngleOld = slopeAngle;
slopeAngle = 0;
}
}
}
Answer by sztobar · Nov 16, 2020 at 08:22 AM
You can google Update vs FixedUpdate unity
and get a ton of different answers, but since you asked here, let me try to describe it here for you.
yes - FixedUpdate should be used for physics, and your code is correct by calling raycasts and doing stuff with rigidbody2d there.
If you had a simple code like that:
void Update() {
transform.Translate(velocity * Time.deltaTime);
}
void FixedUpdate() {
transform.Translate(velocity * Time.fixedDeltaTime);
}
Update can be called with a different Time.deltaTime
and that means that if a player computer gets slow for a moment, it will lag your game and call Update with a potentially huge Time.deltaTime
. That means that you could by accident overshoot your physics-related code because suddenly rather than moving by eg. one pixel you move by 20 pixels. In the same time, FixedUpdate is always runned with constant Time.fixedDeltaTime
and it can be called multiple times in one frame. So instead of having one long Update frame it would result in multiple FixedUpdate calls. Instead of moving by 20 pixels, you would call 20 times FixedUpdate and your code could react to the changed position of main player for each pixel that he moved.
Hope this example clarified it a little.
@sztobar . Thank you for the answer. Yes, your explanation helped me figure it out.