platformer physics
This commit is contained in:
parent
689044f03b
commit
6f3eda4353
|
@ -11,6 +11,7 @@ include_directories(inc)
|
|||
|
||||
set(SOURCES
|
||||
src/main.c
|
||||
src/util.c
|
||||
src/draw.c
|
||||
src/input.c
|
||||
src/level.c
|
||||
|
|
13
inc/conf.h
13
inc/conf.h
|
@ -1,4 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#define TILE_SIZE 16
|
||||
#define TILE_OOB 0
|
||||
#define TILE_SIZE 16
|
||||
#define PLAYER_WIDTH 12
|
||||
#define PLAYER_HEIGHT 12
|
||||
#define MAX_WALK_SPEED 2.0f
|
||||
#define AIR_ACCELERATION 0.4f
|
||||
#define GROUND_ACCELERATION 0.4f
|
||||
#define AIR_FRICTION (AIR_ACCELERATION / MAX_WALK_SPEED)
|
||||
#define GROUND_FRICTION (GROUND_ACCELERATION / MAX_WALK_SPEED)
|
||||
#define AIR_RESISTANCE 0.02f
|
||||
#define GRAVITY 0.2f
|
||||
#define JUMP_SPEED -4.0f
|
||||
|
|
|
@ -9,3 +9,4 @@ struct Player {
|
|||
void player_init(struct Player *);
|
||||
void player_update(struct Player *);
|
||||
void player_draw(struct Player *);
|
||||
void player_move(struct Player *, struct Vec);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
enum Tile {
|
||||
TILE_AIR,
|
||||
TILE_SOLID,
|
||||
TILE_OOB,
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
int sign(int);
|
|
@ -1,5 +1,6 @@
|
|||
#include "level.h"
|
||||
#include "conf.h"
|
||||
#include "tile.h"
|
||||
#include "visual_data.h"
|
||||
#include <gint/display.h>
|
||||
#include <stdlib.h>
|
||||
|
|
107
src/player.c
107
src/player.c
|
@ -1,33 +1,118 @@
|
|||
#include "player.h"
|
||||
#include "conf.h"
|
||||
#include "draw.h"
|
||||
#include "input.h"
|
||||
#include "level.h"
|
||||
#include "tile.h"
|
||||
#include "util.h"
|
||||
|
||||
static void player_reset_speed(struct Player *);
|
||||
static void reset_speed(struct Player *, int x, int y);
|
||||
static struct Vec update_rem(struct Player *);
|
||||
static int collide_margin(int x, int y, int tile, int margin);
|
||||
static int collide(int x, int y, int tile);
|
||||
static int collide_solid(int x, int y);
|
||||
|
||||
void
|
||||
player_init(struct Player *p)
|
||||
{
|
||||
p->pos.x = 0;
|
||||
p->pos.y = 0;
|
||||
player_reset_speed(p);
|
||||
p->pos.x = TILE_SIZE;
|
||||
p->pos.y = TILE_SIZE;
|
||||
reset_speed(p, 1, 1);
|
||||
}
|
||||
|
||||
void
|
||||
player_update(struct Player *p)
|
||||
{
|
||||
p->pos.x++;
|
||||
const int on_ground = collide_solid(p->pos.x, p->pos.y + 1);
|
||||
const int k_left = input_down(K_LEFT);
|
||||
const int k_right = input_down(K_RIGHT);
|
||||
// const int k_up = input_down(K_UP);
|
||||
// const int k_down = input_down(K_DOWN);
|
||||
const int kp_jump = input_pressed(K_JUMP);
|
||||
const int dir_x = k_right - k_left;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* air resistance & gravity */
|
||||
p->spd.y *= (1 - AIR_RESISTANCE);
|
||||
p->spd.y += GRAVITY;
|
||||
|
||||
/* jump */
|
||||
if (on_ground && kp_jump) p->spd.y = JUMP_SPEED;
|
||||
|
||||
player_move(p, update_rem(p));
|
||||
}
|
||||
|
||||
void
|
||||
player_draw(struct Player *p)
|
||||
{
|
||||
draw_rectangle(C_WHITE, p->pos.x, p->pos.y, 16, 16);
|
||||
draw_rectangle(C_WHITE, p->pos.x, p->pos.y, PLAYER_WIDTH,
|
||||
PLAYER_HEIGHT);
|
||||
}
|
||||
|
||||
void
|
||||
player_move(struct Player *p, struct Vec spd)
|
||||
{
|
||||
float sign_x = sign(spd.x);
|
||||
const float sign_y = sign(spd.y);
|
||||
if (!sign_x && !sign_y) sign_x = 1.0f;
|
||||
|
||||
p->pos.x += spd.x;
|
||||
if (collide_solid(p->pos.x, p->pos.y)) reset_speed(p, 1, 0);
|
||||
while (collide_solid(p->pos.x, p->pos.y))
|
||||
p->pos.x -= sign_x;
|
||||
|
||||
p->pos.y += spd.y;
|
||||
if (collide_solid(p->pos.x, p->pos.y)) reset_speed(p, 0, 1);
|
||||
while (collide_solid(p->pos.x, p->pos.y))
|
||||
p->pos.y -= sign_y;
|
||||
}
|
||||
|
||||
static void
|
||||
player_reset_speed(struct Player *p)
|
||||
reset_speed(struct Player *p, int x, int y)
|
||||
{
|
||||
p->spd.x = 0.0f;
|
||||
p->spd.y = 0.0f;
|
||||
p->rem.x = 0.0f;
|
||||
p->rem.y = 0.0f;
|
||||
if (x) {
|
||||
p->spd.x = 0.0f;
|
||||
p->rem.x = 0.0f;
|
||||
}
|
||||
if (y) {
|
||||
p->spd.y = 0.0f;
|
||||
p->rem.y = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static struct Vec
|
||||
update_rem(struct Player *p)
|
||||
{
|
||||
struct VecF spd_n_rem = {p->spd.x + p->rem.x, p->spd.y + p->rem.y};
|
||||
struct Vec spd_trunc = {spd_n_rem.x, spd_n_rem.y};
|
||||
p->rem.x = spd_n_rem.x - (float)spd_trunc.x;
|
||||
p->rem.y = spd_n_rem.y - (float)spd_trunc.y;
|
||||
return spd_trunc;
|
||||
}
|
||||
|
||||
static int
|
||||
collide_margin(int x, int y, int tile, int margin)
|
||||
{
|
||||
const int x1 = x + margin;
|
||||
const int x2 = x + PLAYER_WIDTH - 1 - margin;
|
||||
const int y1 = y + margin;
|
||||
const int y2 = y + PLAYER_HEIGHT - 1 - margin;
|
||||
return level_get_px(x1, y1) == tile || level_get_px(x2, y1) == tile ||
|
||||
level_get_px(x1, y2) == tile || level_get_px(x2, y2) == tile;
|
||||
}
|
||||
|
||||
static int
|
||||
collide(int x, int y, int tile)
|
||||
{
|
||||
return collide_margin(x, y, tile, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
collide_solid(int x, int y)
|
||||
{
|
||||
return collide(x, y, TILE_SOLID);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include "util.h"
|
||||
|
||||
int
|
||||
sign(int x)
|
||||
{
|
||||
return (x > 0) - (x < 0);
|
||||
}
|
Loading…
Reference in New Issue