118 lines
3.4 KiB
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;
|
|
}
|