painfull-success-cg/src/player.c

118 lines
3.4 KiB
C

/* SPDX-License-Identifier: MIT
* Copyright (c) 2021 KikooDX
* This file is part of
* [Painfull Success CG](https://git.sr.ht/~kikoodx/painfull-success-cg),
* which is MIT licensed. The MIT license requires this copyright notice to be
* included in all copies and substantial portions of the software. */
#include <gint/display.h>
#include <stdbool.h>
#include "lazyint.h"
#include "player.h"
#include "conf.h"
#include "vec2.h"
#include "level.h"
#include "input.h"
#include "tiles.h"
Player player_init() {
return (Player){
.pos = (Vec2){},
.spd_x = 0.0,
.spd_y = 0.0,
.facing = 1,
.stun = false,
.knocked = false,
.keys_left = 0,
.jump_buffer = 0,
.coyot = 0,
};
}
void player_update(Player *player, Level *level, Input input, u8 *level_id) {
const Vec2 one_px_down = (Vec2){player->pos.x, player->pos.y + 1};
const bool on_ground =
player_collide(*level, one_px_down, SOLID_TILE, 0) ||
player_collide(*level, one_px_down, SEMI_SOLID_TILE, 0);
if (!player->stun) {
/* Get input. */
const i8 move_x =
input_is_down(input, K_RIGHT) -
input_is_down(input, K_LEFT);
const bool fastfall = input_is_down(input, K_DOWN);
const bool jump_pressed = input_is_pressed(input, K_JUMP);
const bool jump_held = input_is_down(input, K_JUMP);
/* Facing direction. */
if (move_x != 0)
player->facing = move_x;
/* Friction. */
if (on_ground)
player->spd_x *= 1 - GROUND_FRICTION;
else
player->spd_x *= 1 - AIR_FRICTION;
/* Acceleration. */
if (on_ground)
player->spd_x += (f32)(move_x) * GROUND_ACCELERATION;
else
player->spd_x += (f32)(move_x) * AIR_ACCELERATION;
/* Move the player. */
player_move(player, *level, round(player->spd_x), 0);
player_move(player, *level, 0, round(player->spd_y));
}
}
void player_draw(Player player) {
/* Draw colored rectangle depending on player state. */
u32 color = 0;
if (player.stun)
color = C_RGB(230/4, 41/4, 55/4); /* Red. */
else
color = C_RGB(0/4, 121/4, 241/4); /* Blue. */
const vec2_int_t x = player.pos.x + DRAW_OFFSET_X;
const vec2_int_t y = player.pos.y + DRAW_OFFSET_Y;
drect(x, y, x + PLAYER_WIDTH - 1, y + PLAYER_HEIGHT - 1, color);
}
/* Helper functions */
bool player_collide(Level level, Vec2 pos, tile_t tile, u8 margin) {
const vec2_int_t left = pos.x + margin;
const vec2_int_t right = pos.x + PLAYER_WIDTH - 1 - margin * 2;
const vec2_int_t up = pos.y + margin;
const vec2_int_t down = pos.y + PLAYER_HEIGHT - 1 - margin * 2;
return ((tile == level_get_tile_at_px(level, (Vec2){left, up})) ||
(tile == level_get_tile_at_px(level, (Vec2){right, up})) ||
(tile == level_get_tile_at_px(level, (Vec2){left, down})) ||
(tile == level_get_tile_at_px(level, (Vec2){right, down})));
}
bool player_move(Player *player, Level level, i8 spd_x, i8 spd_y) {
player->pos.x += spd_x;
player->pos.y += spd_y;
/* If player is in solid, move back until it ain't. */
if (player_collide(level, player->pos, SOLID_TILE, 0)) {
const u8 sign_spd_x = sign(spd_x);
const u8 sign_spd_y = sign(spd_y);
if (sign_spd_x != 0) player->spd_x = 0;
if (sign_spd_y != 0) player->spd_y = 0;
while (player_collide(level, player->pos, SOLID_TILE, 0)) {
player->pos.x -= sign_spd_x;
player->pos.y -= sign_spd_y;
}
return true;
}
return false;
}
i8 sign(i8 value) {
if (value > 0)
return 1;
else if (value < 0)
return -1;
else
return 0;
}
i8 round(f32 value) {
return (i8)value;
}