handmade.network » Forums » In need of a bit of help with 2D collision.
mojobojo
27 posts
#15092 In need of a bit of help with 2D collision.
1 month ago Edited by mojobojo on April 27, 2018, 6:46 p.m. Reason: Initial post

So I am attempting to write some super simple collision code. The boxes will never be rotated and are able to move in 8 directions (up, down, left, right, +the combination of each). What I am having trouble with is movement diagonally where I would be moving along the side of the box. Movement code is simple position += velocity * dt. I sort of have it, only when corners meet it has some weird side effects.

https://i.imgur.com/N4PpsAz.gifv

To make it clear I purely don't understand what should be doing. Everything I try to look up on 2D collisions just tell me how to check if 2 boxes intersect and never go further. I am trying to fully understand this problem but there appear to be a lack of information on the actual problem and more people just telling each other to use box2d -_-

Here is a snippet of how it works

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
if (player_moved) {
	dv2 ent_rect_pos = { entity->position.x + entity->collision.position.x, entity->position.y + entity->collision.position.y };
	dv2 player_collision_pos = { new_player_position.x + local_player->collision.position.x, new_player_position.y + local_player->collision.position.y };

    f64 left_check = MAX(ent_rect_pos.x, player_collision_pos.x);
    f64 top_check = MAX(ent_rect_pos.y, player_collision_pos.y);
    f64 right_check = MIN(ent_rect_pos.x + entity->collision.dimentions.w, player_collision_pos.x + local_player->collision.dimentions.w);
    f64 bottom_check = MIN(ent_rect_pos.y + entity->collision.dimentions.h, player_collision_pos.y + local_player->collision.dimentions.h);

    f64 col_result_x = left_check - right_check;
    f64 col_result_y = top_check - bottom_check;

    b32 collided = left_check <= right_check && top_check <= bottom_check;

    if (collided) {
        dv2 final_position = new_player_position;

        if (abs(col_result_x) > abs(col_result_y)) {
            if (player_moved_up) {
                final_position.y = ent_rect_pos.y - local_player->collision.dimentions.h - local_player->collision.position.y;
            }
            if (player_moved_down) {
                final_position.y = ent_rect_pos.y + local_player->collision.dimentions.h - local_player->collision.position.y;
            }
        } else {
            if (player_moved_left) {
                final_position.x = ent_rect_pos.x + entity->collision.dimentions.w;
            }
            if (player_moved_right) {
                final_position.x = ent_rect_pos.x - local_player->collision.dimentions.w;
            }
        }

        new_player_position = final_position;
    }
}
mrmixer
Simon Anciaux
371 posts
#15096 In need of a bit of help with 2D collision.
4 weeks, 1 day ago

Shouldn't this line
1
2
3
if (player_moved_down) {
    final_position.y = ent_rect_pos.y + local_player->collision.dimentions.h - local_player->collision.position.y;
}
be
1
2
3
if (player_moved_down) {
    final_position.y = ent_rect_pos.y + entity->collision.dimentions.h - local_player->collision.position.y;
}
And on those lines
1
2
3
4
5
6
if (player_moved_left) {
    final_position.x = ent_rect_pos.x + entity->collision.dimentions.w;
}
if (player_moved_right) {
    final_position.x = ent_rect_pos.x - local_player->collision.dimentions.w;
}
don't you need to account for a local_player->collision.position.x that isn't zero ?

I don't think this would solve the problem though.

The issue seems to be that you detect that you are overlapping col_result_x and col_result_y "units" but are resolving the collision using other values (the values in the ifs (player_moved_x) ). For example, the first glitch in your video: the player is up, and going down left near the left side of the other entity. You detect that you are colliding and that x is the smallest overlap. So you want to correct x, but instead of moving the player using col_result_x (the actual overlap), you move it to the other side (final_position.x = ent_rect_pos.x + entity->collision.dimentions.w;) because he was moving left.

A few things that could help debug this king of bug:
- have the camera fixed instead of following the character to better see what is actually happening;
- since this bug require user input and you can't really put a breakpoint to debug when it's happening, you can use a log to print values and the code path that was taken. Or having a replay input system (like in handmade hero).

A side note: when posting a question like this one, try to give more context about your code. For example, explain what the position of the player represent. Is it the bottom left corner ? Is it the bottom center ? Is it the center ? Also try to describe the problem more precisely: what is happening that isn't what you want. And if you can, provide a simple reproduction code we can compile and debug.