Best way to check collisions with diferent types of platforms on each side of the player in a 2D game.
Hi Unity Community, I'm new to Unity (and C#, but not to Object Oriented Programing, or programing in general). Also, I'm not a native english speaker, so I apologize for any english mistakes I could do.
I'm making a 2D platformer, and I'm wondering what's the best way to detect platforms on each side of my square-shaped player. I've read lots of threads about similar topics but I have some specific questions for which I could not find answers. I will try to quickly describe the gameplay I want to create, then I will ask the question itself.
My game contains both fixed platforms (no rigidbody) and moving/rotating platforms (kinematic rigidbody). These platforms can also be sticky and stop player movement/fall until the jump key is pressed. When the player is against a wall he doesn't loose velocity if he is going upward, but fall speed is reduced, and the player can wall jump. The game also contains water, which slows down movement.
So each time I go through the FixedUpdate function of my player script, I need to know if my player has platforms on each side, and if these platforms are sticky (sticky platforms are on a separate layer and are only detected on the center on each side of the player), and also if the player is under water to decide how to adjust his velocity.
Now the question is : what's the best way to do these repetitive tests? Here are a few ideas and an image to illustrate :
Solution 1 : using Physics2D.OverlapBox in FixedUpdate to update flag properties.
this.OnGround = Physics2D.OverlapBox(worldPosition, boxSize, 0, layerMask);
This is the solution I'm currently using, but I feel like I'm doing unoptimized things I shouldn't do myself because the engine can probably do it better.
Solution 2 : children box colliders.
Here I add children to my player object with only a (non trigger) BoxCollider2D and no Rigidbody2D. I set the size of these children so they are perfectly aligned with the border of the player objet.
Solution 3 : children box triggers.
Here I do almost the same thing than in solution 2, except that the children go beyond the edges of the player object and their BoxCollider2D is set to trigger. These children actually test the same areas that I'm testing with solution 1.
In solution 2 and 3, I let the engine detect collisions (player Rigidbody2D has "Collision Detection" set to "Continuous"), but I'm wondering if this technique could fail, especially with solution 2. Also, in this case, do I have to increment/decrement a property for each collider each time On[Collision/Trigger][Enter/Exit]2D fires, or does this property already exist somewhere?
I've read about PhysicsMaterial2D and Friction, but since the physics in my game are not really realistic (especially wall slides), I didn't opt for that option. I've also read about PlatformEffector2D, but I doubt it would work well with rotating platforms.
What solution would you use? 1, 2, 3, something else, maybe totally different? why?
have you come across performance issues? have you ran the unity profiler on all three versions?
If performance is fine, don't bother of it works.
No, I don't have performance issues yet. A scene can contain at most two players, so there should be no problem. That's why I stick to solution 1 for now. I was just wondering if someone knew a better way to do this. It could be useful if I have more entities with that kind of behavior in the future. It could also help someone else with a similar problem. :)
Answer by Relan42 · May 11 at 05:55 PM
There's a function called OnCollisionEnter2D that is triggered whenever the player is touching anything and allows you to get information about the collision. This is what I would do.
public bool isGrounded;
//an array of contact points
ContactPoint2D[] contacts;
//Fill the array of contact points
private void OnCollisionStay2D(Collision2D collision)
{
contacts = collision.contacts;
}
void Update()
{
if (contacts != null)
{
//this checks every contact point and sees if it is touching a horizontal surface from bellow
foreach (ContactPoint2D contact in contacts)
{
if (contact.normal == new Vector2(0, 1))
{
isGrounded = true;
break;
}
else
{
isGrounded = false;
}
//if there are no contact points it isn't grounded
if (rb.GetContacts(contacts) == 0)
{
isGrounded = false;
}
}
}