+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>
#include "./player.h"
#include "./platforms.h"
+#include "./point.h"
+#include "./error.h"
#define PLAYER_WIDTH 50.0f
#define PLAYER_HEIGHT 50.0f
#define PLAYER_SPEED 500.0f
#define PLAYER_GRAVITY 1500.0f
+#define PLAYER_INFLATION 100.0f
struct player_t {
- float x, y;
- float dx, dy;
+ vec_t position;
+ vec_t velocity;
+ vec_t movement;
+ float height;
+ float width;
};
-struct player_t *create_player(float x, float y)
+static const vec_t opposing_rect_side_forces[RECT_SIDE_N] = {
+ { .x = 1.0f, .y = 0.0f }, /* RECT_SIDE_LEFT = 0, */
+ { .x = -1.0f, .y = 0.0f }, /* RECT_SIDE_RIGHT, */
+ { .x = 0.0f, .y = 1.0f, }, /* RECT_SIDE_TOP, */
+ { .x = 0.0f, .y = -1.0f, } /* RECT_SIDE_BOTTOM, */
+};
+
+static vec_t opposing_force_by_sides(int sides[RECT_SIDE_N])
+{
+ vec_t opposing_force = {
+ .x = 0.0f,
+ .y = 0.0f
+ };
+
+ for (rect_side_t side = 0; side < RECT_SIDE_N; ++side) {
+ if (sides[side]) {
+ vec_add(
+ &opposing_force,
+ opposing_rect_side_forces[side]);
+ }
+ }
+
+ return opposing_force;
+}
+
+static int squishing_horizontal_force(int sides[RECT_SIDE_N])
{
- struct player_t *player = malloc(sizeof(struct player_t));
+ return sides[RECT_SIDE_LEFT] && sides[RECT_SIDE_RIGHT];
+}
+
+static int squishing_vertical_force(int sides[RECT_SIDE_N])
+{
+ return sides[RECT_SIDE_TOP] && sides[RECT_SIDE_BOTTOM];
+}
+
+player_t *create_player(float x, float y)
+{
+ player_t *player = malloc(sizeof(player_t));
if (player == NULL) {
+ throw_error(ERROR_TYPE_LIBC);
return NULL;
}
- player->x = x;
- player->y = y;
- player->dx = 0.0f;
- player->dy = 0.0f;
+ player->position.x = x;
+ player->position.y = y;
+ player->velocity.x = 0.0f;
+ player->velocity.y = 0.0f;
+ player->movement.x = 0.0f;
+ player->movement.y = 0.0f;
+ player->height = PLAYER_HEIGHT;
+ player->width = PLAYER_WIDTH;
return player;
}
-void destroy_player(struct player_t * player)
+void destroy_player(player_t * player)
{
free(player);
}
-int render_player(const struct player_t * player,
- SDL_Renderer *renderer)
+rect_t player_hitbox(const player_t *player)
{
- if (SDL_SetRenderDrawColor(renderer, 96, 255, 96, 255) < 0) {
- return -1;
- }
+ rect_t hitbox = {
+ .x = player->position.x - player->width / 2,
+ .y = player->position.y - player->height,
+ .w = player->width,
+ .h = player->height
+ };
- SDL_Rect rect;
- rect.x = roundf(player->x);
- rect.y = roundf(player->y);
- rect.w = roundf(PLAYER_WIDTH);
- rect.h = roundf(PLAYER_HEIGHT);
+ return hitbox;
+}
+
+int render_player(const player_t * player,
+ SDL_Renderer *renderer,
+ const camera_t *camera)
+{
+ assert(player);
+ assert(renderer);
+ assert(camera);
- if (SDL_RenderFillRect(renderer, &rect) < 0) {
+ if (SDL_SetRenderDrawColor(renderer, 96, 255, 96, 255) < 0) {
+ throw_error(ERROR_TYPE_SDL2);
return -1;
}
+ rect_t player_object = player_hitbox(player);
+
- return 0;
+ return camera_fill_rect(camera, renderer, &player_object);
}
-void update_player(struct player_t * player,
- const struct platforms_t *platforms,
- int delta_time)
+void update_player(player_t *player,
+ const platforms_t *platforms,
+ Uint32 delta_time)
{
- float d = delta_time / 1000.0;
+ assert(player);
+ assert(platforms);
- float dx = player->dx;
- float dy = player->dy + PLAYER_GRAVITY * d;
+ float d = (float) delta_time / 1000.0f;
- float x = player->x + dx * d;
- float y = fmod(player->y + dy * d, 600.0f);
+ player->velocity.y += PLAYER_GRAVITY * d;
+ player->position = vec_sum(
+ player->position,
+ vec_scala_mult(
+ vec_sum(
+ player->velocity,
+ player->movement),
+ d));
+ player->position.y = fmodf(player->position.y, 800.0f);
- struct rect_t player_object = {
- .x = x,
- .y = y,
- .w = PLAYER_WIDTH,
- .h = PLAYER_HEIGHT
- };
+ player->height = fminf(player->height + PLAYER_INFLATION * d, PLAYER_HEIGHT);
+ player->width = (PLAYER_WIDTH * PLAYER_HEIGHT) / player->height;
+
+
+ int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
+
+ platforms_rect_object_collide(platforms, player_hitbox(player), sides);
+ vec_t opposing_force = opposing_force_by_sides(sides);
- /* TODO(#6): Implement collision for the left/right sides */
- if (platforms_rect_object_collide(platforms, &player_object)) {
- dy = -player->dy * 0.75;
- x = player->x + dx * d;
- y = fmod(player->y + dy * d, 600.0f);
+ if (opposing_force.y < 0.0f && (player->velocity.y + player->movement.y) > 800.0f) {
+ player->height = PLAYER_HEIGHT / 2;
}
- player->dx = dx;
- player->dy = dy;
- player->x = x;
- player->y = y;
+ for (int i = 0; i < 1000
+ && (vec_length(opposing_force) > 1e-6
+ || squishing_vertical_force(sides)
+ || squishing_horizontal_force(sides)); ++i) {
+ player->position = vec_sum(
+ player->position,
+ vec_scala_mult(
+ opposing_force,
+ 1e-2f));
+
+ if (fabs(opposing_force.x) > 1e-6 && (opposing_force.x < 0.0f) != ((player->velocity.x + player->movement.x) < 0.0f)) {
+ player->velocity.x = 0.0f;
+ player->movement.x = 0.0f;
+ }
+
+ if (fabs(opposing_force.y) > 1e-6 && (opposing_force.y < 0.0f) != ((player->velocity.y + player->movement.y) < 0.0f)) {
+ player->velocity.y = 0.0f;
+ player->movement.y = 0.0f;
+ }
+
+ if (squishing_vertical_force(sides)) {
+ player->height -= 1e-2f;
+ /* player->width = (PLAYER_WIDTH * PLAYER_HEIGHT) / player->height; */
+ }
+
+ if (squishing_horizontal_force(sides)) {
+ player->width -= 1e-2f;
+ /* player->height = (PLAYER_WIDTH * PLAYER_HEIGHT) / player->width; */
+ }
+
+ platforms_rect_object_collide(
+ platforms,
+ player_hitbox(player),
+ sides);
+ opposing_force = opposing_force_by_sides(sides);
+ }
}
-void player_move_left(struct player_t *player)
+void player_move_left(player_t *player)
{
- player->dx = -PLAYER_SPEED;
+ assert(player);
+
+ player->movement.x = -PLAYER_SPEED;
+ player->movement.y = 0.0f;
}
-void player_move_right(struct player_t *player)
+void player_move_right(player_t *player)
{
- player->dx = PLAYER_SPEED;
+ assert(player);
+
+ player->movement.x = PLAYER_SPEED;
+ player->movement.y = 0.0f;
}
-void player_stop(struct player_t *player)
+void player_stop(player_t *player)
{
- player->dx = 0.0f;
+ assert(player);
+
+ player->movement.x = 0.0f;
+ player->movement.y = 0.0f;
}
-void player_jump(struct player_t *player)
+void player_jump(player_t *player)
{
- player->dy = -500.0f;
+ assert(player);
+
+ player->velocity.y = -500.0f;
+}
+
+void player_focus_camera(player_t *player,
+ camera_t *camera)
+{
+ assert(player);
+ assert(camera);
+
+ camera_center_at(camera, player->position);
}