Attempts at fixing object collision, implement checkpoint

This commit is contained in:
Lucas S. Vieira 2024-10-13 23:29:02 -03:00
parent 07539bfb32
commit 1568a7cd9f
8 changed files with 82 additions and 59 deletions

View file

@ -163,7 +163,7 @@ loopback = 0
[[checkpoint.fragment.animations]]
name = "active"
id = 1
duration = 2
duration = 4
frames = [
[0, 48, 16, 16],
[16, 48, 16, 16],
@ -185,7 +185,7 @@ loopback = 0
[[spring_yellow.animations]]
name = "bounce"
id = 1
duration = 2
duration = 4
frames = [
[80, 32, 32, 8],
[80, 40, 32, 40],
@ -206,7 +206,7 @@ loopback = 0
[[spring_red.animations]]
name = "bounce"
id = 1
duration = 2
duration = 4
frames = [
[48, 32, 32, 8],
[48, 40, 32, 40],
@ -227,7 +227,7 @@ loopback = 0
[[spring_yellow_diagonal.animations]]
name = "bounce"
id = 1
duration = 2
duration = 4
frames = [
[144, 80, 32, 32],
[176, 80, 48, 48],
@ -248,7 +248,7 @@ loopback = 0
[[spring_red_diagonal.animations]]
name = "bounce"
id = 1
duration = 2
duration = 4
frames = [
[144, 32, 32, 32],
[176, 32, 48, 48],

BIN
assets/sfx/CHEK.ogg Normal file

Binary file not shown.

View file

@ -16,6 +16,8 @@ typedef enum {
OBJ_FLAG_DESTROYED = 0x1,
OBJ_FLAG_INVISIBLE = 0x2,
OBJ_FLAG_ANIM_LOCK = 0x4,
OBJ_FLAG_CHECKPOINT_ACTIVE = 0x8,
} ObjectGeneralFlag;
typedef struct {

View file

@ -175,6 +175,9 @@
<file name="SPRN.VAG"
type="data"
source="${PROJECT_SOURCE_DIR}/assets/sfx/SPRN.VAG" />
<file name="CHEK.VAG"
type="data"
source="${PROJECT_SOURCE_DIR}/assets/sfx/CHEK.VAG" />
</dir>
<dir name="BGM">

View file

@ -208,20 +208,6 @@ linecast(LevelData *lvl, TileMap128 *map128, TileMap16 *map16,
return ev;
}
int
aabb_intersects(int32_t a_vx, int32_t a_vy, int32_t aw, int32_t ah,
int32_t b_vx, int32_t b_vy, int32_t bw, int32_t bh)
{
int32_t a_right = a_vx + aw;
int32_t a_bottom = a_vy + ah;
int32_t b_right = b_vx + bw;
int32_t b_bottom = b_vy + bh;
return !((a_vx > b_right) || (a_right < b_vx) ||
(a_bottom < b_vy) || (a_vy > b_bottom));
}
void
_draw_collision_hitbox(int32_t vx, int32_t vy, int32_t w, int32_t h)
{
@ -237,12 +223,28 @@ _draw_collision_hitbox(int32_t vx, int32_t vy, int32_t w, int32_t h)
sort_prim(hitbox, 3); // Object layer
}
int
aabb_intersects(int32_t a_vx, int32_t a_vy, int32_t aw, int32_t ah,
int32_t b_vx, int32_t b_vy, int32_t bw, int32_t bh)
{
if(debug_mode > 1) _draw_collision_hitbox(b_vx, b_vy, bw, bh);
int32_t a_right = a_vx + aw;
int32_t a_bottom = a_vy + ah;
int32_t b_right = b_vx + bw;
int32_t b_bottom = b_vy + bh;
return !((a_vx > b_right) || (a_right < b_vx) ||
(a_bottom < b_vy) || (a_vy > b_bottom));
}
ObjectCollision
hitbox_collision(int32_t p_vx, int32_t p_vy, int32_t pw, int32_t ph,
int32_t o_vx, int32_t o_vy, int32_t ow, int32_t oh)
{
int32_t player_x = p_vx + (pw >> 1);
int32_t player_y = p_vy + (ph >> 1);
int32_t obj_x = o_vx + (ow >> 1);
int32_t obj_y = o_vy + (oh >> 1);
@ -252,8 +254,8 @@ hitbox_collision(int32_t p_vx, int32_t p_vy, int32_t pw, int32_t ph,
int32_t combined_x_radius = (ow >> 1) + (pw >> 1) + 1;
int32_t combined_y_radius = (oh >> 1) + (ph >> 1);
int32_t combined_x_diameter = combined_x_radius << 1;
int32_t combined_y_diameter = combined_y_radius << 1;
int32_t combined_x_diameter = ow + pw + 1;
int32_t combined_y_diameter = oh + ph;
int32_t left_difference = player_x - obj_x + combined_x_radius;
if((left_difference < 0) || (left_difference > combined_x_diameter))
@ -266,14 +268,14 @@ hitbox_collision(int32_t p_vx, int32_t p_vy, int32_t pw, int32_t ph,
uint8_t is_right = player_x > obj_x;
uint8_t is_bottom = player_y > obj_y;
int32_t x_distance = left_difference - (is_right ? ow : 0);
int32_t x_distance = left_difference - (is_right ? ow : 0) + 1;
int32_t y_distance = top_difference - (is_bottom ? (4 + oh) : 0);
ObjectCollision col;
y_distance -= (oh >> 1);
x_distance -= (ow >> 1);
if(abs(x_distance) > abs(y_distance)) {
col = (y_distance < 0) ? OBJ_SIDE_TOP : OBJ_SIDE_BOTTOM;
col = (y_distance > 0) ? OBJ_SIDE_TOP : OBJ_SIDE_BOTTOM;
}
else {
col = (x_distance < 0) ? OBJ_SIDE_LEFT : OBJ_SIDE_RIGHT;

View file

@ -422,12 +422,8 @@ _render_obj(ObjectState *obj, ObjectTableEntry *typedata,
setPolyF4(poly);
increment_prim(sizeof(POLY_F4));
setSemiTrans(poly, 1);
if(obj->id == 0)
setRGB0(poly, 128, 128, 0);
else setRGB0(poly, 128, 0, 0);
if(obj->id == 0)
setXYWH(poly, px - 4, py - 4 - 32, 8, 8);
else setXYWH(poly, px - 4, py - 4, 8, 8);
setRGB0(poly, 128, 0, 0);
setXYWH(poly, px - 4, py - 4, 8, 8);
sort_prim(poly, 3); // 3 = front sprite and character layer
}

View file

@ -22,6 +22,7 @@ extern Camera camera;
extern SoundEffect sfx_ring;
extern SoundEffect sfx_pop;
extern SoundEffect sfx_sprn;
extern SoundEffect sfx_chek;
extern int debug_mode;
// Update functions
@ -29,6 +30,7 @@ static void _ring_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR
static void _goal_sign_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos);
static void _monitor_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos);
static void _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_red);
static void _checkpoint_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos);
// Player hitbox information. Calculated once per frame.
static int32_t player_vx, player_vy; // Top left corner of player hitbox
@ -70,7 +72,7 @@ object_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos)
player_height = (player_attacking
? HEIGHT_RADIUS_ROLLING
: HEIGHT_RADIUS_NORMAL) << 1;
player_vy = (player.pos.vy >> 12) - (player_height >> 1);
player_vy = (player.pos.vy >> 12) - (player_height >> 1) - 1;
if(debug_mode > 1) {
_draw_player_hitbox();
@ -83,6 +85,7 @@ object_update(ObjectState *state, ObjectTableEntry *typedata, VECTOR *pos)
case OBJ_MONITOR: _monitor_update(state, typedata, pos); break;
case OBJ_SPRING_YELLOW: _spring_update(state, typedata, pos, 0); break;
case OBJ_SPRING_RED: _spring_update(state, typedata, pos, 1); break;
case OBJ_CHECKPOINT: _checkpoint_update(state, typedata, pos); break;
}
}
@ -98,8 +101,8 @@ _ring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
// Calculate actual top left corner of ring AABB
pos->vx -= 8; pos->vy -= (8 + 32);
if(aabb_intersects(pos->vx, pos->vy, 16, 16,
player_vx, player_vy, player_width, player_height))
if(aabb_intersects(player_vx, player_vy, player_width, player_height,
pos->vx, pos->vy, 16, 16))
{
state->anim_state.animation = 1;
state->anim_state.frame = 0;
@ -160,11 +163,11 @@ _monitor_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
int32_t hitbox_vy = pos->vy - 32; // Monitor hitbox is a 28x32 solid box
// Perform collision detection
if(aabb_intersects(solidity_vx, solidity_vy, 32, 32,
player_vx, player_vy, player_width, player_height))
if(aabb_intersects(player_vx, player_vy, player_width, player_height,
solidity_vx, solidity_vy, 32, 32))
{
if(aabb_intersects(hitbox_vx, hitbox_vy, 28, 32,
player_vx, player_vy, player_width, player_height)
if(aabb_intersects(player_vx, player_vy, player_width, player_height,
hitbox_vx, hitbox_vy, 28, 32)
&& player_attacking) {
state->anim_state.animation = 1;
state->anim_state.frame = 0;
@ -219,7 +222,7 @@ _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_r
solidity_w = 16;
solidity_h = 32;
} else if(state->flipmask & MASK_FLIP_FLIPY) {
solidity_vy -= 32;
solidity_vy -= 48;
}
ObjectCollision collision_side =
@ -231,7 +234,7 @@ _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_r
case OBJ_SIDE_LEFT:
if(state->flipmask & MASK_FLIP_ROTCT) {
if(player.grnd) player.vel.vz = is_red ? -0x10000 : -0xa000;
else player.vel.vy = is_red ? -0x10000 : -0xa000;
else player.vel.vx = is_red ? -0x10000 : -0xa000;
player.ctrllock = 16;
player.anim_dir = -1;
state->anim_state.animation = 1;
@ -239,7 +242,7 @@ _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_r
} else {
player.ev_right = (CollisionEvent) {
.collided = 1,
.coord = solidity_vx + 2,
.coord = solidity_vx + 1,
.angle = 0
};
}
@ -247,7 +250,7 @@ _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_r
case OBJ_SIDE_RIGHT:
if(state->flipmask & MASK_FLIP_ROTCW) {
if(player.grnd) player.vel.vz = is_red ? 0x10000 : 0xa000;
else player.vel.vy = is_red ? 0x10000 : 0xa000;
else player.vel.vx = is_red ? 0x10000 : 0xa000;
player.ctrllock = 16;
player.anim_dir = 1;
state->anim_state.animation = 1;
@ -262,15 +265,13 @@ _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_r
break;
case OBJ_SIDE_TOP:
if(state->flipmask == 0) {
if(player.vel.vy > 0) {
player.grnd = 0;
player.vel.vy = is_red ? -0x10000 : -0xa000;
player.angle = 0;
player.action = 0;
state->anim_state.animation = 1;
player_set_animation_direct(&player, ANIM_WALKING);
sound_play_vag(sfx_sprn, 0);
}
player.grnd = 0;
player.vel.vy = is_red ? -0x10000 : -0xa000;
player.angle = 0;
player.action = 0;
state->anim_state.animation = 1;
player_set_animation_direct(&player, ANIM_WALKING);
sound_play_vag(sfx_sprn, 0);
} else {
player.ev_grnd1 = player.ev_grnd2 = (CollisionEvent) {
.collided = 1,
@ -281,15 +282,13 @@ _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_r
break;
case OBJ_SIDE_BOTTOM:
if(state->flipmask & MASK_FLIP_FLIPY) {
if(player.vel.vy > 0) {
player.grnd = 0;
player.vel.vy = is_red ? 0x10000 : 0xa000;
player.angle = 0;
player.action = 0;
state->anim_state.animation = 1;
player_set_animation_direct(&player, ANIM_WALKING);
sound_play_vag(sfx_sprn, 0);
}
player.grnd = 0;
player.vel.vy = is_red ? 0x10000 : 0xa000;
player.angle = 0;
player.action = 0;
state->anim_state.animation = 1;
player_set_animation_direct(&player, ANIM_WALKING);
sound_play_vag(sfx_sprn, 0);
} else {
player.ev_ceil1 = player.ev_ceil2 = (CollisionEvent) {
.collided = 1,
@ -304,3 +303,22 @@ _spring_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos, uint8_t is_r
state->anim_state.frame = 0;
}
}
static void
_checkpoint_update(ObjectState *state, ObjectTableEntry *, VECTOR *pos)
{
if(!(state->props & OBJ_FLAG_CHECKPOINT_ACTIVE)) {
int32_t hitbox_vx = pos->vx - 8;
int32_t hitbox_vy = pos->vy - 48;
if(aabb_intersects(player_vx, player_vy, player_width, player_height,
hitbox_vx, hitbox_vy, 16, 48))
{
state->props |= OBJ_FLAG_CHECKPOINT_ACTIVE;
state->frag_anim_state->animation = 1;
state->frag_anim_state->frame = 0;
sound_play_vag(sfx_chek, 0);
}
}
}

View file

@ -36,6 +36,7 @@ SoundEffect sfx_dropd = { 0 };
SoundEffect sfx_ring = { 0 };
SoundEffect sfx_pop = { 0 };
SoundEffect sfx_sprn = { 0 };
SoundEffect sfx_chek = { 0 };
// TODO: Maybe shouldn't be extern?
extern TileMap16 map16;
@ -80,7 +81,8 @@ load_player(Player *player,
if(sfx_dropd.addr == 0) sfx_dropd = sound_load_vag("\\SFX\\DROPD.VAG;1");
if(sfx_ring.addr == 0) sfx_ring = sound_load_vag("\\SFX\\RING.VAG;1");
if(sfx_pop.addr == 0) sfx_pop = sound_load_vag("\\SFX\\POP.VAG;1");
if(sfx_sprn.addr == 0) sfx_sprn = sound_load_vag("\\SFX\\SPRN.VAG;1");
if(sfx_sprn.addr == 0) sfx_sprn = sound_load_vag("\\SFX\\SPRN.VAG;1");
if(sfx_chek.addr == 0) sfx_chek = sound_load_vag("\\SFX\\CHEK.VAG;1");
}
void