Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental: Platformer actor collision #1037

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Solid Collision Refactor
um3k committed Feb 8, 2022
commit d0c690c56220c8f0917108465bace70fdbb682c2
2 changes: 1 addition & 1 deletion appData/src/gb/include/actor.h
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ UBYTE actor_get_frame_offset(actor_t *actor) BANKED;
actor_t *actor_at_tile(UBYTE tx, UBYTE ty, UBYTE inc_noclip) BANKED;
actor_t *actor_in_front_of_player(UBYTE grid_size, UBYTE inc_noclip) BANKED;
actor_t *actor_overlapping_player(UBYTE inc_noclip) BANKED;
actor_t *actor_overlapping_player_solid(UBYTE inc_noclip, actor_t *first_actor) BANKED;
actor_t *actor_overlapping_player_solid(uint16_t new_x, uint16_t new_y, actor_t *first_actor, uint8_t mask) BANKED;
actor_t *actor_overlapping_bb(bounding_box_t *bb, upoint16_t *offset, actor_t *ignore, UBYTE inc_noclip) BANKED;
void actor_set_anim_idle(actor_t *actor) BANKED;
void actor_set_anim_moving(actor_t *actor) BANKED;
2 changes: 2 additions & 0 deletions appData/src/gb/include/states/platform.h
Original file line number Diff line number Diff line change
@@ -20,4 +20,6 @@ extern WORD plat_grav;
extern WORD plat_hold_grav;
extern WORD plat_max_fall_vel;

extern BYTE standing_on_overlap;

#endif
9 changes: 6 additions & 3 deletions appData/src/gb/src/core/actor.c
Original file line number Diff line number Diff line change
@@ -295,16 +295,19 @@ actor_t *actor_overlapping_player(UBYTE inc_noclip) BANKED {
return NULL;
}

actor_t *actor_overlapping_player_solid(UBYTE inc_noclip, actor_t *first_actor) BANKED {
actor_t *actor_overlapping_player_solid(uint16_t new_x, uint16_t new_y, actor_t *first_actor, uint8_t mask) BANKED {
actor_t *actor = first_actor != NULL ? first_actor->prev : PLAYER.prev;
upoint16_t new_pos;
new_pos.x = new_x;
new_pos.y = new_y;

while (actor) {
if (!inc_noclip && !actor->collision_enabled && !actor->solid) {
if (!actor->collision_enabled && !(actor->solid & mask)) {
actor = actor->prev;
continue;
};

if (bb_intersects(&PLAYER.bounds, &PLAYER.pos, &actor->bounds, &actor->pos)) {
if (bb_intersects(&PLAYER.bounds, &new_pos, &actor->bounds, &actor->pos)) {
return actor;
}

150 changes: 74 additions & 76 deletions appData/src/gb/src/states/platform.c
Original file line number Diff line number Diff line change
@@ -90,6 +90,7 @@ void platform_init() BANKED {

void platform_update() BANKED {
UBYTE tile_start, tile_end;
WORD new_y, new_x;
actor_t *hit_actor;
UBYTE p_half_width = (PLAYER.bounds.right - PLAYER.bounds.left) >> 1;

@@ -202,79 +203,56 @@ void platform_update() BANKED {
pl_vel_y += plat_grav;
}

// Step Y
grounded = FALSE;
tile_start = (((PLAYER.pos.x >> 4) + PLAYER.bounds.left) >> 3);
tile_end = (((PLAYER.pos.x >> 4) + PLAYER.bounds.right) >> 3) + 1;
if (pl_vel_y > 0) {
UWORD new_y = PLAYER.pos.y + (pl_vel_y >> 8);
UBYTE tile_y;
PLAYER.pos.y = new_y;
hit_actor = NULL;

while (hit_actor = actor_overlapping_player_solid(FALSE, hit_actor)) {
if ((hit_actor->solid & COLLISION_TOP) && ((hit_actor == standing_on) ||
((PLAYER.pos.y + (PLAYER.bounds.bottom << 4)) - (hit_actor->pos.y + (hit_actor->bounds.top << 4) - hit_actor->vel.y) <= (pl_vel_y >> 8)))) {
standing_on_y_offset = (hit_actor->bounds.top - PLAYER.bounds.bottom) << 4;
new_y = (hit_actor->pos.y + standing_on_y_offset) - 1;
grounded = TRUE;
// standing_on_last_pos_x = hit_actor->pos.x;
// PLAYER.pos.x = PLAYER.pos.x + hit_actor->vel.x;
// new_y = new_y + hit_actor->vel.y;
standing_on = standing_on != NULL ? standing_on : hit_actor;
new_x = PLAYER.pos.x + (pl_vel_x >> 8);
new_y = PLAYER.pos.y + (pl_vel_y >> 8);

hit_actor = PLAYER.prev;
while (hit_actor) {
if (!hit_actor->solid) {
hit_actor = hit_actor->prev;
continue;
};

new_pos.x = new_x;
new_pos.y = PLAYER.pos.y;

if ((hit_actor->solid & (COLLISION_LEFT | COLLISION_RIGHT)) && bb_intersects(&PLAYER.bounds, &new_pos, &hit_actor->bounds, &hit_actor->pos)) {
if ((hit_actor->solid & COLLISION_LEFT) && hit_actor != standing_on && new_x < hit_actor->pos.x && ((pl_vel_x >> 8) >= hit_actor->vel.x)) {
new_x = hit_actor->pos.x + ((hit_actor->bounds.left - PLAYER.bounds.right) << 4) - 1;
pl_vel_x = 0;
} else if ((hit_actor->solid & COLLISION_RIGHT) && (hit_actor != standing_on) && new_x > hit_actor->pos.x && ((pl_vel_x >> 8) <= hit_actor->vel.x)) {
new_x = hit_actor->pos.x + ((hit_actor->bounds.right - PLAYER.bounds.left + 1) << 4);
pl_vel_x = 0;
}
}
if (!grounded) {
standing_on = NULL;
}
// if (standing_on != NULL) {
// PLAYER.pos.x = PLAYER.pos.x + standing_on->vel.x;
// new_y = new_y + standing_on->vel.y;
// }

new_pos.x = new_x;
new_pos.y = new_y;

tile_y = ((new_y >> 4) + PLAYER.bounds.bottom) >> 3;
while (tile_start != tile_end) {
if (tile_at(tile_start, tile_y) & COLLISION_TOP) {
new_y = ((((tile_y) << 3) - PLAYER.bounds.bottom) << 4) - 1;
if ((hit_actor->solid & (COLLISION_TOP | COLLISION_BOTTOM)) && bb_intersects(&PLAYER.bounds, &new_pos, &hit_actor->bounds, &hit_actor->pos)) {
if ((hit_actor->solid & COLLISION_TOP) && ((hit_actor == standing_on) || ((pl_vel_y >> 8) >= hit_actor->vel.y)) &&
(new_y - hit_actor->pos.y + ((PLAYER.bounds.bottom - hit_actor->bounds.top) << 4) <= ((pl_vel_y >> 8) - hit_actor->vel.y))) {
new_y = hit_actor->pos.y + ((hit_actor->bounds.top - PLAYER.bounds.bottom) << 4) - 1;
grounded = TRUE;
break;
standing_on = hit_actor;
} else if ((hit_actor->solid & COLLISION_BOTTOM) && ((pl_vel_y >> 8) < hit_actor->vel.y)
&& (new_y - hit_actor->pos.y + ((PLAYER.bounds.top - hit_actor->bounds.bottom) << 4) >= ((pl_vel_y >> 8) - hit_actor->vel.y))) {
new_y = hit_actor->pos.y + ((hit_actor->bounds.bottom - PLAYER.bounds.top + 1) << 4);
pl_vel_y = hit_actor->vel.y << 8;
}
tile_start++;
}

pl_vel_y = grounded ? 0 : pl_vel_y;

PLAYER.pos.y = new_y;

} else if (pl_vel_y < 0) {
UWORD new_y = PLAYER.pos.y + (pl_vel_y >> 8);
UBYTE tile_y = (((new_y >> 4) + PLAYER.bounds.top) >> 3);
while (tile_start != tile_end) {
if (tile_at(tile_start, tile_y) & COLLISION_BOTTOM) {
new_y = ((((UBYTE)(tile_y + 1) << 3) - PLAYER.bounds.top) << 4) + 1;
pl_vel_y = 0;
break;
}
tile_start++;
}

new_pos.x = PLAYER.pos.x;
new_pos.y = new_y;
hit_actor = actor_overlapping_bb(&PLAYER.bounds, &new_pos, &PLAYER, FALSE);
if (hit_actor != NULL && (hit_actor->solid & COLLISION_BOTTOM)) {
new_y = (((hit_actor->pos.y >> 4) + hit_actor->bounds.bottom - PLAYER.bounds.top + 1) << 4);
pl_vel_y = 0;
}

PLAYER.pos.y = new_y;
hit_actor = hit_actor->prev;
}
if (!grounded) {
standing_on = NULL;
}


// Step X
tile_start = (((PLAYER.pos.y >> 4) + PLAYER.bounds.top) >> 3);
tile_end = (((PLAYER.pos.y >> 4) + PLAYER.bounds.bottom) >> 3) + 1;
if (pl_vel_x > 0) {
UWORD new_x = PLAYER.pos.x + (pl_vel_x >> 8);
UBYTE tile_x = ((new_x >> 4) + PLAYER.bounds.right) >> 3;
while (tile_start != tile_end) {
if (tile_at(tile_x, tile_start) & COLLISION_LEFT) {
@@ -285,17 +263,9 @@ void platform_update() BANKED {
tile_start++;
}

new_pos.x = new_x;
new_pos.y = PLAYER.pos.y;
hit_actor = actor_overlapping_bb(&PLAYER.bounds, &new_pos, &PLAYER, FALSE);
if (hit_actor != NULL && hit_actor != standing_on && (hit_actor->solid & COLLISION_LEFT)) {
new_x = (((hit_actor->pos.x >> 4) + hit_actor->bounds.left - PLAYER.bounds.right) << 4) - 1;
pl_vel_x = 0;
}

PLAYER.pos.x = MIN((image_width - 16) << 4, new_x);
} else if (pl_vel_x < 0) {
WORD new_x = PLAYER.pos.x + (pl_vel_x >> 8);
// WORD new_x = PLAYER.pos.x + (pl_vel_x >> 8);
UBYTE tile_x = ((new_x >> 4) + PLAYER.bounds.left) >> 3;
while (tile_start != tile_end) {
if (tile_at(tile_x, tile_start) & COLLISION_RIGHT) {
@@ -306,17 +276,45 @@ void platform_update() BANKED {
tile_start++;
}

new_pos.x = new_x;
new_pos.y = PLAYER.pos.y;
hit_actor = actor_overlapping_bb(&PLAYER.bounds, &new_pos, &PLAYER, FALSE);
if (hit_actor != NULL && hit_actor != standing_on && (hit_actor->solid & COLLISION_RIGHT)) {
new_x = (((hit_actor->pos.x >> 4) + hit_actor->bounds.right - PLAYER.bounds.left + 1) << 4);
pl_vel_x = 0;
}

PLAYER.pos.x = MAX(0, new_x);
} else {
PLAYER.pos.x = new_x;
}

// Step Y
tile_start = (((PLAYER.pos.x >> 4) + PLAYER.bounds.left) >> 3);
tile_end = (((PLAYER.pos.x >> 4) + PLAYER.bounds.right) >> 3) + 1;
if (pl_vel_y > 0) {
UBYTE tile_y;

tile_y = ((new_y >> 4) + PLAYER.bounds.bottom) >> 3;
while (tile_start != tile_end) {
if (tile_at(tile_start, tile_y) & COLLISION_TOP) {
new_y = ((((tile_y) << 3) - PLAYER.bounds.bottom) << 4) - 1;
grounded = TRUE;
break;
}
tile_start++;
}

} else if (pl_vel_y < 0) {
// UWORD new_y = PLAYER.pos.y + (pl_vel_y >> 8);
UBYTE tile_y = (((new_y >> 4) + PLAYER.bounds.top) >> 3);
while (tile_start != tile_end) {
if (tile_at(tile_start, tile_y) & COLLISION_BOTTOM) {
new_y = ((((UBYTE)(tile_y + 1) << 3) - PLAYER.bounds.top) << 4) + 1;
pl_vel_y = 0;
break;
}
tile_start++;
}
}


pl_vel_y = grounded ? 0 : pl_vel_y;

// PLAYER.pos.x = new_x;
PLAYER.pos.y = new_y;

// Clamp Y Velocity
pl_vel_y = MIN(pl_vel_y, plat_max_fall_vel);