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
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions appData/src/gb/include/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extern UBYTE player_moving;
extern actor_t * player_collision_actor;
extern actor_t * emote_actor;
extern UBYTE emote_timer;
extern UBYTE active_solid_actors;

extern UBYTE allocated_hardware_sprites;

Expand Down
13 changes: 13 additions & 0 deletions appData/src/gb/include/collision.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#define COLLISION_LEFT 0x4
#define COLLISION_RIGHT 0x8
#define COLLISION_ALL 0xF
#define COLLISION_X (COLLISION_LEFT | COLLISION_RIGHT)
#define COLLISION_Y (COLLISION_TOP | COLLISION_BOTTOM)
#define TILE_PROP_LADDER 0x10

typedef struct bounding_box_t {
Expand Down Expand Up @@ -55,6 +57,17 @@ inline UBYTE bb_intersects(bounding_box_t *bb_a, upoint16_t *offset_a, bounding_
return TRUE;
}

// optimized function, needs testing and profiling. And why is 0xF the magic number?
inline UBYTE bb_intersects_opt(bounding_box_t *bb_a, upoint16_t *offset_a, bounding_box_t *bb_b, upoint16_t *offset_b) {
BYTE ox = (((offset_b->x) - (offset_a->x) + 0xF) >> 4);
if (((ox + (bb_b->left - bb_a->right)) > 0) ||
((ox + (bb_b->right - bb_a->left)) < 0)) return FALSE;
BYTE oy = (((offset_b->y) - (offset_a->y) + 0xF) >> 4);
if (((oy + (bb_b->top - bb_a->bottom)) > 0) ||
((oy + (bb_b->bottom - bb_a->top)) < 0)) return FALSE;
return TRUE;
}

/**
* Return collision tile value at given tile x,y coordinate.
*
Expand Down
2 changes: 2 additions & 0 deletions appData/src/gb/include/gbs_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ typedef struct actor_t
bool collision_enabled : 1;
bool movement_interrupt : 1;
upoint16_t pos;
point8_t vel;
direction_e dir;
bounding_box_t bounds;
uint8_t base_tile;
Expand All @@ -68,6 +69,7 @@ typedef struct actor_t

// Collisions
collision_group_e collision_group;
uint8_t solid : 4; // direction mask support

// Linked list
struct actor_t *next;
Expand Down
2 changes: 2 additions & 0 deletions appData/src/gb/include/states/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 4 additions & 0 deletions appData/src/gb/src/core/actor.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ UBYTE player_iframes;
actor_t * player_collision_actor;
actor_t * emote_actor;
UBYTE emote_timer;
UBYTE active_solid_actors;

UBYTE allocated_hardware_sprites;

Expand All @@ -60,6 +61,7 @@ void actors_init() BANKED {
player_iframes = 0;
player_collision_actor = NULL;
emote_actor = NULL;
active_solid_actors = 0;

memset(actors, 0, sizeof(actors));
}
Expand Down Expand Up @@ -166,6 +168,7 @@ void deactivate_actor(actor_t *actor) BANKED {
if (!actor->active) return;
if (actor == &PLAYER) return;
actor->active = FALSE;
if (actor->solid) active_solid_actors--;
DL_REMOVE_ITEM(actors_active_head, actor);
DL_PUSH_HEAD(actors_inactive_head, actor);
if ((actor->hscript_update & SCRIPT_TERMINATED) == 0) {
Expand All @@ -189,6 +192,7 @@ void activate_actor(actor_t *actor) BANKED {
if (actor->active || actor->disabled) return;
actor->active = TRUE;
actor_set_anim_idle(actor);
if (actor->solid) active_solid_actors++;
DL_REMOVE_ITEM(actors_inactive_head, actor);
DL_PUSH_HEAD(actors_active_head, actor);
actor->hscript_update = SCRIPT_TERMINATED;
Expand Down
1 change: 1 addition & 0 deletions appData/src/gb/src/core/data_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ UBYTE load_scene(const scene_t * scene, UBYTE bank, UBYTE init_data) BANKED {
// Load actors
actors_active_head = NULL;
actors_inactive_head = NULL;
active_solid_actors = 0;

// Add player to inactive, then activate
PLAYER.active = FALSE;
Expand Down
8 changes: 8 additions & 0 deletions appData/src/gb/src/core/vm_actor.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ void vm_actor_move_to(SCRIPT_CTX * THIS, INT16 idx) OLDCALL BANKED {
// Actor reached destination
if ((actor->pos.x == params->X) && (actor->pos.y == params->Y)) {
THIS->flags = MOVE_INACTIVE;
actor->vel.x = 0;
actor->vel.y = 0;
actor_set_anim_idle(actor);
return;
}
Expand All @@ -139,11 +141,14 @@ void vm_actor_move_to(SCRIPT_CTX * THIS, INT16 idx) OLDCALL BANKED {

// Move actor
point_translate_dir(&actor->pos, new_dir, actor->move_speed);
actor->vel.x = (new_dir == DIR_RIGHT) ? actor->move_speed : -actor->move_speed;

// Check for actor collision
if (CHK_FLAG(params->ATTR, ACTOR_ATTR_CHECK_COLL) && !CHK_FLAG(THIS->flags, MOVE_ALLOW_V) && actor_overlapping_bb(&actor->bounds, &actor->pos, actor, FALSE)) {
point_translate_dir(&actor->pos, FLIPPED_DIR(new_dir), actor->move_speed);
THIS->flags = 0;
actor->vel.x = 0;
actor->vel.y = 0;
actor_set_anim_idle(actor);
return;
}
Expand Down Expand Up @@ -172,11 +177,14 @@ void vm_actor_move_to(SCRIPT_CTX * THIS, INT16 idx) OLDCALL BANKED {

// Move actor
point_translate_dir(&actor->pos, new_dir, actor->move_speed);
actor->vel.y = (new_dir == DIR_DOWN) ? actor->move_speed : -actor->move_speed;

// Check for actor collision
if (CHK_FLAG(params->ATTR, ACTOR_ATTR_CHECK_COLL) && actor_overlapping_bb(&actor->bounds, &actor->pos, actor, FALSE)) {
point_translate_dir(&actor->pos, FLIPPED_DIR(new_dir), actor->move_speed);
THIS->flags = 0;
actor->vel.x = 0;
actor->vel.y = 0;
actor_set_anim_idle(actor);
return;
}
Expand Down
65 changes: 59 additions & 6 deletions appData/src/gb/src/states/adventure.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ void adventure_init() BANKED {
}

void adventure_update() BANKED {
actor_t *hit_actor;
actor_t *hit_actor, *sol_actor;
UBYTE tile_start, tile_end;
UBYTE angle = 0;
direction_e new_dir = DIR_NONE;
upoint16_t new_pos, sol_pos;
point16_t pl_vel;

player_moving = FALSE;

Expand Down Expand Up @@ -71,11 +73,63 @@ void adventure_update() BANKED {
angle = ANGLE_180DEG;
}

hit_actor = NULL;
new_pos.x = PLAYER.pos.x;
new_pos.y = PLAYER.pos.y;
pl_vel.x = 0;
pl_vel.y = 0;
if (player_moving) {
upoint16_t new_pos;
new_pos.x = PLAYER.pos.x;
new_pos.y = PLAYER.pos.y;
point_translate_angle(&new_pos, angle, PLAYER.move_speed);
point_translate_angle_to_delta(&pl_vel, angle, PLAYER.move_speed);
}

sol_actor = PLAYER.prev;
UBYTE solid_count = active_solid_actors;
while (solid_count) {
if (sol_actor->solid) solid_count--;
if (!sol_actor->solid || !sol_actor->collision_enabled ||
((UBYTE)((BYTE)(PLAYER.pos.x >> 8) - (BYTE)(sol_actor->pos.x >> 8) + 2) > 4) ||
((UBYTE)((BYTE)(PLAYER.pos.y >> 8) - (BYTE)(sol_actor->pos.y >> 8) + 2) > 4)) {
// sol_actor->hidden = TRUE;
sol_actor = sol_actor->prev;
continue;
}
// sol_actor->hidden = FALSE;

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

if ((sol_actor->solid & COLLISION_X)) {
if (bb_intersects_opt(&PLAYER.bounds, &sol_pos, &sol_actor->bounds, &sol_actor->pos)) {
if ((sol_actor->solid & COLLISION_LEFT) && ((sol_pos.x) < (sol_actor->pos.x)) && (pl_vel.x >= sol_actor->vel.x)) {
new_pos.x = sol_actor->pos.x + ((sol_actor->bounds.left - PLAYER.bounds.right) << 4) - 1;
hit_actor = sol_actor;
} else if ((sol_actor->solid & COLLISION_RIGHT) && ((sol_pos.x) > (sol_actor->pos.x)) && (pl_vel.x <= sol_actor->vel.x)) {
new_pos.x = sol_actor->pos.x + ((sol_actor->bounds.right - PLAYER.bounds.left + 1) << 4) + 1;
hit_actor = sol_actor;
}
}
}

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

if ((sol_actor->solid & COLLISION_Y) && sol_actor != hit_actor) {
if (bb_intersects_opt(&PLAYER.bounds, &sol_pos, &sol_actor->bounds, &sol_actor->pos)) {
if ((sol_actor->solid & COLLISION_TOP) && ((sol_pos.y) < (sol_actor->pos.y)) && (pl_vel.y <= sol_actor->vel.y)) {
new_pos.y = sol_actor->pos.y + ((sol_actor->bounds.top - PLAYER.bounds.bottom) << 4) - 1;
hit_actor = sol_actor;
} else if ((sol_actor->solid & COLLISION_BOTTOM) && ((sol_pos.y) > (sol_actor->pos.y)) && (pl_vel.y > sol_actor->vel.y)) {
new_pos.y = sol_actor->pos.y + ((sol_actor->bounds.bottom - PLAYER.bounds.top + 1) << 4) + 1;
hit_actor = sol_actor;
}
}
}

sol_actor = sol_actor->prev;
}

if (player_moving || hit_actor != NULL) {

// Step X
tile_start = (((PLAYER.pos.y >> 4) + PLAYER.bounds.top) >> 3);
Expand Down Expand Up @@ -135,7 +189,6 @@ void adventure_update() BANKED {
actor_set_anim_idle(&PLAYER);
}

hit_actor = NULL;
if (IS_FRAME_ODD) {
// Check for trigger collisions
if (trigger_activate_at_intersection(&PLAYER.bounds, &PLAYER.pos, FALSE)) {
Expand All @@ -144,7 +197,7 @@ void adventure_update() BANKED {
}

// Check for actor collisions
hit_actor = actor_overlapping_player(FALSE);
if (hit_actor == NULL) hit_actor = actor_overlapping_player(FALSE);
if (hit_actor != NULL && hit_actor->collision_group) {
player_register_collision_with(hit_actor);
}
Expand Down
Loading