Just starting out with Unity so please be patient :) We are building a Zelda like game - top down, no physics / gravity, tilemaps for the map. We don't want to use the dynamic rigidbodies because of all the physics behind it.
The tilemap has "Walls" with a CompositeCollider2D and Static rigidbody, our player has a CircleCollider2D and a kinematic rigidbody. Both the player and the walls have a physics material with zero friction.
What is the best way for the collision detection with a kinematic rigibody? We have several concepts like Physics2D.CircleCastAll but ended up with our player stuck in the walls or getting stuck at the corners (the player should move smoothly around the corner) or getting stuck in two overlapping colliders.
The best solution we came up with is this (and the player still runs into the colliders sometimes but at least don't get stuck anymore).
// MoveDirection is the movement input
movement = MoveDirection * Speed * Time.deltaTime;
List<RaycastHit2D> results = new List<RaycastHit2D>();
List<RaycastHit2D> resultsX = new List<RaycastHit2D>();
List<RaycastHit2D> resultsY = new List<RaycastHit2D>();
if (movement.x != 0)
{
actorCollider.Cast(new Vector2(movement.x, 0), filter, resultsX, movement.magnitude);
results.AddRange(resultsX);
}
if (movement.y != 0)
{
actorCollider.Cast(new Vector2(0, movement.y), filter, resultsY, movement.magnitude);
results.AddRange(resultsY);
}
foreach (RaycastHit2D hit in results)
{
Vector2 normal = hit.normal;
float projection = Vector2.Dot(movement, normal);
if (projection < 0)
{
if (hit.distance > 0)
{
projection += Mathf.Max(hit.distance - 0.01f, 0);
}
movement -= projection * normal;
}
}
// move player
newPosition = body.position + movement;
// make sure the player is positioned at pixel perfect positions
newPosition.x = (Mathf.Round(newPosition.x * 16) / 16);
newPosition.y = (Mathf.Round(newPosition.y * 16) / 16);
body.MovePosition(newPosition);
// this part moves the player back in case it is in a collider.
List<Collider2D> colliderList = new List<Collider2D>();
if (actorCollider.OverlapCollider(filter, colliderList) > 0)
{
foreach (Collider2D hit in colliderList)
{
var distance = hit.Distance(actorCollider);
body.MovePosition(body.position + (distance.normal * Mathf.Abs(distance.distance)));
}
}
Player setup:
Walls setup:
Somehow it still feels way too complicated. Is this the best approach to do the collision detections or do we do it completely wrong and there are better / easier ways? Keep in mind we want to be able to walk around the straight corners somehow and not get stuck on them. And there are overlapping colliders or colliders next to each other.
Thank you for your time!