Last active
February 9, 2022 14:15
-
-
Save dyguests/64777abc80824b9842abef9a09d3f4bb to your computer and use it in GitHub Desktop.
GroundHelper, PhysicsObject, grounded checker.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace Utils | |
{ | |
public class GroundHelper | |
{ | |
private const float minMoveDistance = 0.001f; | |
private const float shellRadius = 0.01f; | |
private Rigidbody2D rb; | |
private Config config; | |
private IGroundedStateListener groundedStateListener; | |
// ------------------ runtime variants ------------------ | |
private bool grounded; | |
private Vector2 groundNormal; | |
private Vector2 velocity; | |
private ContactFilter2D contactFilter; | |
private RaycastHit2D[] hitBuffer = new RaycastHit2D[16]; | |
private List<RaycastHit2D> hitBufferList = new List<RaycastHit2D>(16); | |
public GroundHelper(Rigidbody2D rb, Config config, IGroundedStateListener groundedStateListener) | |
{ | |
this.rb = rb; | |
this.config = config; | |
this.groundedStateListener = groundedStateListener; | |
} | |
/// <summary> | |
/// this method should be called in host MonoBehaviour.FixedUpdate. | |
/// </summary> | |
public void FixedUpdate() | |
{ | |
var lastGrounded = grounded; | |
grounded = false; | |
velocity = rb.velocity + Physics2D.gravity * Time.fixedDeltaTime; | |
var deltaPosition = velocity * Time.deltaTime; | |
var moveAlongGround = new Vector2(groundNormal.y, -groundNormal.x); | |
var move = moveAlongGround * deltaPosition.x; | |
CheckMove(move, false); | |
move = Vector2.up * deltaPosition.y; | |
CheckMove(move, true); | |
// grounded changed callback. | |
if (lastGrounded != grounded) | |
{ | |
groundedStateListener.OnGroundedChanged(grounded); | |
} | |
} | |
private void CheckMove(Vector2 move, bool yMovement) | |
{ | |
float distance = move.magnitude; | |
if (distance > minMoveDistance) | |
{ | |
int count = rb.Cast(move, contactFilter, hitBuffer, distance + shellRadius); | |
hitBufferList.Clear(); | |
for (int i = 0; i < count; i++) | |
{ | |
hitBufferList.Add(hitBuffer[i]); | |
} | |
for (int i = 0; i < hitBufferList.Count; i++) | |
{ | |
Vector2 currentNormal = hitBufferList[i].normal; | |
if (currentNormal.y > config.minGroundNormalY) | |
{ | |
grounded = true; | |
if (yMovement) | |
{ | |
groundNormal = currentNormal; | |
currentNormal.x = 0; | |
} | |
} | |
float projection = Vector2.Dot(velocity, currentNormal); | |
if (projection < 0) | |
{ | |
velocity = velocity - projection * currentNormal; | |
} | |
// float modifiedDistance = hitBufferList[i].distance - shellRadius; | |
// distance = modifiedDistance < distance ? modifiedDistance : distance; | |
} | |
} | |
} | |
[Serializable] | |
public class Config | |
{ | |
[SerializeField] internal float minGroundNormalY = .65f; | |
} | |
public interface IGroundedStateListener | |
{ | |
void OnGroundedChanged(bool grounded); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment