gravity is out of their mind

Implements: https://todo.sr.ht/~kikoodx/jtmm2/6
This commit is contained in:
KikooDX 2021-12-18 17:20:00 +01:00
parent 0509f62e2f
commit 7a708c28f9
8 changed files with 68 additions and 18 deletions

View File

@ -25,6 +25,7 @@ set(ASSETS
res/burn.kble
res/bounce.kble
res/worm.kble
res/shake.kble
res/fonts/dina.png
)

View File

@ -18,3 +18,4 @@
#define BURN_DEATH 3
#define BOUNCE_SPEED -2.0f
#define DRAW_OFF_X -2
#define GRAVS_MARGIN 0

View File

@ -4,7 +4,7 @@
enum AirState { AS_NEUTRAL, AS_RISING, AS_BREAKING };
struct Player {
struct Vec pos;
struct Vec pos, gravity;
struct VecF spd, rem;
enum AirState air_state;
int jump_buffer, jump_grace, burn, bouncing;

View File

@ -9,5 +9,9 @@ enum Tile {
TILE_EXIT,
TILE_BURN,
TILE_BOUNCER,
TILE_GRAV_D,
TILE_GRAV_U,
TILE_GRAV_R,
TILE_GRAV_L,
TILE_OOB,
};

BIN
res/shake.kble Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -11,13 +11,11 @@
static struct Level level;
extern bopti_image_t bimg_tileset;
extern struct LevelBin kble_test, kble_burn, kble_bounce, kble_worm;
extern struct LevelBin kble_test, kble_burn, kble_bounce, kble_worm, kble_shake;
static const struct LevelBinNamed levels[] = {
{&kble_test, "gentle introduction"},
{&kble_burn, "these are rare"},
{&kble_bounce, "deceptive road"},
{&kble_worm, "under your skin"},
{NULL, NULL}};
{&kble_test, "gentle introduction"}, {&kble_burn, "these are rare"},
{&kble_bounce, "deceptive road"}, {&kble_worm, "under your skin"},
{&kble_shake, "breaking into reality"}, {NULL, NULL}};
static void level_free(void);

View File

@ -19,6 +19,8 @@ player_spawn(struct Player *p)
struct Vec pos = level_find(TILE_SPAWN);
p->pos.x = pos.x * TILE_SIZE + (TILE_SIZE - PLAYER_WIDTH) / 2;
p->pos.y = pos.y * TILE_SIZE + TILE_SIZE - PLAYER_HEIGHT;
p->gravity.x = 0;
p->gravity.y = 1;
reset_speed(p, 1, 1);
p->air_state = AS_NEUTRAL;
p->jump_buffer = 0;
@ -29,7 +31,8 @@ player_spawn(struct Player *p)
void
player_update(struct Player *p)
{
const int on_ground = collide_solid(p->pos.x, p->pos.y + 1);
const int on_ground =
collide_solid(p->pos.x + p->gravity.x, p->pos.y + p->gravity.y);
const int k_left = input_down(K_LEFT);
const int k_right = input_down(K_RIGHT);
// const int k_up = input_down(K_UP);
@ -38,18 +41,27 @@ player_update(struct Player *p)
const int kp_jump = input_pressed(K_JUMP);
const int kp_polarity = input_pressed(K_POLARITY);
const int dir_x = k_right - k_left;
const struct Vec rem_gravity = p->gravity;
float spd_x, spd_y;
/* speed transformation */
spd_x = p->spd.x;
spd_y = p->spd.y * p->gravity.y;
if (p->gravity.x) {
spd_x = p->spd.y;
spd_y = p->spd.x * p->gravity.x;
}
/* polarity swap */
if (kp_polarity) polarity_invert();
/* horizontal friction & acceleration */
p->spd.x *= on_ground ? (1 - GROUND_FRICTION) : (1 - AIR_FRICTION);
p->spd.x +=
dir_x * (on_ground ? GROUND_ACCELERATION : AIR_ACCELERATION);
spd_x *= on_ground ? (1 - GROUND_FRICTION) : (1 - AIR_FRICTION);
spd_x += dir_x * (on_ground ? GROUND_ACCELERATION : AIR_ACCELERATION);
/* air resistance & gravity */
p->spd.y *= (1 - AIR_RESISTANCE);
p->spd.y +=
spd_y *= (1 - AIR_RESISTANCE);
spd_y +=
(p->air_state == AS_BREAKING) ? (GRAVITY * JUMP_BREAK) : (GRAVITY);
/* air state machine */
@ -59,7 +71,7 @@ player_update(struct Player *p)
if (!k_jump) p->air_state = AS_BREAKING;
/* fallthrough */
case AS_BREAKING:
if (p->spd.y > 0) p->air_state = AS_NEUTRAL;
if (spd_y > 0) p->air_state = AS_NEUTRAL;
break;
case AS_NEUTRAL:
default:
@ -78,7 +90,7 @@ player_update(struct Player *p)
p->jump_grace--;
/* jump */
if (p->jump_grace && p->jump_buffer && k_jump) {
p->spd.y = JUMP_SPEED;
spd_y = JUMP_SPEED;
p->air_state = AS_RISING;
p->jump_buffer = 0;
p->jump_grace = 0;
@ -87,7 +99,7 @@ player_update(struct Player *p)
/* bounce */
if (collide(p->pos.x, p->pos.y, TILE_BOUNCER)) {
if (!p->bouncing) {
p->spd.y = -absf(p->spd.y) + BOUNCE_SPEED;
spd_y = -absf(spd_y) + BOUNCE_SPEED;
p->bouncing = 1;
}
} else {
@ -96,15 +108,49 @@ player_update(struct Player *p)
/* burn and death */
if (collide(p->pos.x, p->pos.y, TILE_BURN)) {
if (++p->burn >= BURN_DEATH) level_reload();
if (++p->burn >= BURN_DEATH) {
level_reload();
return;
}
} else if (p->burn) {
p->burn--;
}
/* next level */
if (collide(p->pos.x, p->pos.y, TILE_EXIT)) level_next();
if (collide(p->pos.x, p->pos.y, TILE_EXIT)) {
level_next();
return;
}
/* speed transformation */
if (rem_gravity.y) {
p->spd.x = spd_x;
p->spd.y = spd_y * p->gravity.y;
}
if (rem_gravity.x) {
p->spd.y = spd_x;
p->spd.x = spd_y * p->gravity.x;
}
player_move(p, update_rem(p));
/* gravity modifiers */
if (collide_margin(p->pos.x, p->pos.y, TILE_GRAV_D, GRAVS_MARGIN)) {
p->gravity.x = 0;
p->gravity.y = 1;
}
if (collide_margin(p->pos.x, p->pos.y, TILE_GRAV_U, GRAVS_MARGIN)) {
p->gravity.x = 0;
p->gravity.y = -1;
}
if (collide_margin(p->pos.x, p->pos.y, TILE_GRAV_R, GRAVS_MARGIN)) {
p->gravity.x = 1;
p->gravity.y = 0;
}
if (collide_margin(p->pos.x, p->pos.y, TILE_GRAV_L, GRAVS_MARGIN)) {
p->gravity.x = -1;
p->gravity.y = 0;
}
}
void