Fix misc math bugs
This commit is contained in:
parent
5f522abcb5
commit
c5c677320b
@ -9,29 +9,50 @@ bool game_collision_is_occlusive(sys_maptile tile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// c's modulus can produce a negative result. don't allow that!
|
||||
#define modulus(x, mod) ((x) % (mod) + (mod)) % (mod)
|
||||
#define round_down(x, incr) (x) - modulus(x, incr)
|
||||
#define round_up(x, incr) round_down((x) + (incr) - 1, incr)
|
||||
|
||||
bool game_collision_can_move(game_bbox body, sys_i32 dx, sys_i32 dy) {
|
||||
// First: place the body in space.
|
||||
// Align its top-left corner to the pixel boundary
|
||||
sys_i32 x = body.x + dx;
|
||||
sys_i32 y = body.y + dy;
|
||||
|
||||
// the player can never leave the map
|
||||
if (x < 0) { return false; }
|
||||
if (y < 0) { return false; }
|
||||
if (x + body.w > map_game_map.width * TILE_SZ_MICROPIXEL) {
|
||||
return false;
|
||||
}
|
||||
if (y + body.h > map_game_map.height * TILE_SZ_MICROPIXEL) {
|
||||
return false;
|
||||
}
|
||||
// this is extremely similar to the logic in move_to_contact
|
||||
// but has different rounding behavior
|
||||
// (because a body at a fractional position must not actually collide
|
||||
// with fractional pixels)
|
||||
sys_i32 body_x0 = round_down(x, PIXEL_SZ_MICROPIXEL);
|
||||
sys_i32 body_y0 = round_down(y, PIXEL_SZ_MICROPIXEL);
|
||||
sys_i32 body_x1 = body_x0 + body.w;
|
||||
sys_i32 body_y1 = body_y0 + body.h;
|
||||
|
||||
sys_i32 tile_x0 = round_down(body_x0, TILE_SZ_MICROPIXEL);
|
||||
sys_i32 tile_y0 = round_down(body_y0, TILE_SZ_MICROPIXEL);
|
||||
sys_i32 tile_x1 = round_up(body_x1, TILE_SZ_MICROPIXEL);
|
||||
sys_i32 tile_y1 = round_up(body_y1, TILE_SZ_MICROPIXEL);
|
||||
|
||||
// now convert to tile coords instead of pixels
|
||||
tile_x0 /= TILE_SZ_MICROPIXEL;
|
||||
tile_y0 /= TILE_SZ_MICROPIXEL;
|
||||
tile_x1 /= TILE_SZ_MICROPIXEL;
|
||||
tile_y1 /= TILE_SZ_MICROPIXEL;
|
||||
|
||||
for (sys_i32 y = tile_y0; y < tile_y1; y++) {
|
||||
for (sys_i32 x = tile_x0; x < tile_x1; x++) {
|
||||
bool invalid;
|
||||
sys_maptile tile = sys_map_get(map_game_map, x, y, &invalid);
|
||||
if (invalid || game_collision_is_occlusive(tile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Collide with blocks
|
||||
// If two collides with a block, check if one collides with it.
|
||||
// The collision only matters if one doesn't.
|
||||
return true;
|
||||
}
|
||||
|
||||
#define round_down(x, incr) (x) - (x) % (incr)
|
||||
#define round_up(x, incr) round_down((x) + (incr) - 1, incr)
|
||||
|
||||
game_collision game_collision_move_to_contact(
|
||||
game_bbox* body, sys_i32 total_dx, sys_i32 total_dy
|
||||
) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "sys/sys.h"
|
||||
|
||||
#define TILE_SZ_MICROPIXEL 0x800
|
||||
#define PIXEL_SZ_MICROPIXEL 0x100
|
||||
|
||||
typedef struct {
|
||||
sys_i32 x;
|
||||
@ -24,4 +25,4 @@ bool game_collision_is_occlusive(sys_maptile tile);
|
||||
bool game_collision_can_move(game_bbox body, sys_i32 dx, sys_i32 dy);
|
||||
game_collision game_collision_move_to_contact(game_bbox* body, sys_i32 x, sys_i32 y);
|
||||
|
||||
#endif
|
||||
#endif // GAME_COLLISION_H
|
@ -5,12 +5,15 @@
|
||||
#include "game.h"
|
||||
#include "sys/sys.h"
|
||||
|
||||
#define GAME_PLAYER_ORIGIN_X 4
|
||||
#define GAME_PLAYER_ORIGIN_Y 4
|
||||
|
||||
game_bbox game_player_bbox = {
|
||||
.x=0x9000,
|
||||
// .y=0x5800,
|
||||
.y=0x0000,
|
||||
.w=0x1000,
|
||||
.h=0x1000,
|
||||
.w=0x0800,
|
||||
.h=0x0c00,
|
||||
};
|
||||
bool game_player_grounded = false;
|
||||
sys_i32 game_player_jump_frames = 0;
|
||||
@ -44,7 +47,9 @@ void game_player_update() {
|
||||
if (collision.collided_x) { game_player_dx = 0; }
|
||||
if (collision.collided_y) { game_player_dy = 0; }
|
||||
|
||||
game_player_grounded = !game_collision_can_move(game_player_bbox, 0, 1);
|
||||
game_player_grounded = !game_collision_can_move(
|
||||
game_player_bbox, 0, PIXEL_SZ_MICROPIXEL
|
||||
);
|
||||
|
||||
{
|
||||
sys_i32 fric_numerator = game_player_grounded ? 0x70 : 0x7f;
|
||||
@ -63,8 +68,11 @@ void game_player_update() {
|
||||
|
||||
// allow this if grounded or if it's not a change of direction
|
||||
if (
|
||||
/*
|
||||
game_player_grounded ||
|
||||
(sys_sgn_i32(wanted_dx) == sys_sgn_i32(game_player_dx))
|
||||
*/
|
||||
true
|
||||
) {
|
||||
game_player_dx = wanted_dx;
|
||||
} else {
|
||||
@ -74,19 +82,20 @@ void game_player_update() {
|
||||
}
|
||||
|
||||
if (game_player_grounded || game_player_coyote_frames > 0) {
|
||||
if (sys_btn(DEVICE_BUTTON_U)) {
|
||||
if (sys_btnp(DEVICE_BUTTON_U, false)) {
|
||||
game_player_dy = -0x300;
|
||||
game_player_jump_frames = 15;
|
||||
game_player_grounded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (game_player_dx < 0) { game_player_faceleft = true; }
|
||||
if (game_player_dx > 0) { game_player_faceleft = false; }
|
||||
|
||||
bool wants_to_go_higher = false;
|
||||
if (game_player_grounded) {
|
||||
game_player_coyote_frames = 5;
|
||||
if (game_player_dy > 0) { game_player_dy = 0; }
|
||||
if (game_player_dx < 0) { game_player_faceleft = true; }
|
||||
if (game_player_dx > 0) { game_player_faceleft = false; }
|
||||
if (sys_abs_i32(game_player_dx) < 0x20) { game_player_dx = 0; }
|
||||
}
|
||||
else {
|
||||
@ -108,7 +117,7 @@ void game_player_update() {
|
||||
} else {
|
||||
game_player_anim_transition(GAME_PLAYER_ANIM_WALKING);
|
||||
game_player_anim_add_progress(
|
||||
sys_min_i32(sys_abs_i32(game_player_dx) / 0x10, 0x8)
|
||||
sys_min_i32(sys_abs_i32(game_player_dx) / 0x10, 0x20)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -138,8 +147,8 @@ void game_player_draw() {
|
||||
sys_sprite_draw_ext(
|
||||
spr_game_player,
|
||||
game_player_image,
|
||||
game_player_bbox.x / 0x100,
|
||||
game_player_bbox.y / 0x100,
|
||||
game_player_bbox.x / 0x100 - GAME_PLAYER_ORIGIN_X,
|
||||
game_player_bbox.y / 0x100 - GAME_PLAYER_ORIGIN_Y,
|
||||
2, 2,
|
||||
game_player_faceleft, false
|
||||
);
|
||||
|
@ -295,6 +295,24 @@ void sys_map_draw(
|
||||
}
|
||||
}
|
||||
|
||||
sys_maptile sys_map_get(
|
||||
sys_map map,
|
||||
sys_i32 tile_x, sys_i32 tile_y,
|
||||
bool* flag_invalid
|
||||
) {
|
||||
if (flag_invalid != NULL) { *flag_invalid = false; }
|
||||
|
||||
if (
|
||||
tile_x < 0 || tile_y < 0 ||
|
||||
tile_x >= map.width || tile_y >= map.height
|
||||
) {
|
||||
if (flag_invalid != NULL) { *flag_invalid = true; }
|
||||
return 255;
|
||||
}
|
||||
|
||||
return map.tiles[tile_x + map.width * tile_y];
|
||||
}
|
||||
|
||||
// == internal primitives ==
|
||||
void sys_pixel_internal_set(sys_i32 x, sys_i32 y, sys_color c) {
|
||||
sys_color realc = sys_dpal[c];
|
||||
|
@ -179,4 +179,16 @@ void sys_map_draw(
|
||||
// TODO: Layers?
|
||||
);
|
||||
|
||||
/**
|
||||
* Get a single map tile, putting whether the coords were invalid into
|
||||
* flag_invalid.
|
||||
*
|
||||
* (flag_invalid may be null)
|
||||
*/
|
||||
sys_maptile sys_map_get(
|
||||
sys_map map,
|
||||
sys_i32 tile_x, sys_i32 tile_y,
|
||||
bool* flag_invalid
|
||||
);
|
||||
|
||||
#endif // CROCPARTY_SYS_GRAPHICS_H
|
||||
|
@ -25,9 +25,10 @@ bool sys_btn(DeviceButton button) {
|
||||
return sys_input_down_frames[button] >= 1;
|
||||
}
|
||||
|
||||
bool sys_btnp(DeviceButton button) {
|
||||
bool sys_btnp(DeviceButton button, bool repeat) {
|
||||
if (button >= DEVICE_BUTTON_N) { return false; }
|
||||
if (sys_input_down_frames[button] == 1) { return true; }
|
||||
if (!repeat) { return false; }
|
||||
// 31 and every 8 frames after that
|
||||
if (sys_input_down_frames[button] >= 31 && (sys_input_down_frames[button] - 31) % 8 == 0) {
|
||||
return true;
|
||||
|
@ -26,8 +26,9 @@ bool sys_btn(DeviceButton button);
|
||||
/**
|
||||
* Return whether a button was just pressed.
|
||||
*
|
||||
* Repeats after 30 frames, returning true every 8 frames after that.
|
||||
* If `repeat`, then this repeats after 30 frames, returning true every 8
|
||||
* frames after that.
|
||||
*/
|
||||
bool sys_btnp(DeviceButton button);
|
||||
bool sys_btnp(DeviceButton button, bool repeat);
|
||||
|
||||
#endif // SYS_INPUT_H
|
Loading…
Reference in New Issue
Block a user