]> git.lizzy.rs Git - nothing.git/blobdiff - src/player.c
(#111) Make Lava kill the Player
[nothing.git] / src / player.c
index 2e9476d3a0af9b2039d3b95b3fb9c8790288d2ff..334061763c78d642a24c42911b02f4f9d0505662 100644 (file)
@@ -3,68 +3,80 @@
 #include <stdlib.h>
 #include <SDL2/SDL.h>
 
+#include "./lt.h"
 #include "./player.h"
 #include "./platforms.h"
 #include "./point.h"
 #include "./error.h"
+#include "./rigid_rect.h"
+#include "./dying_rect.h"
 
-#define PLAYER_WIDTH 50.0f
-#define PLAYER_HEIGHT 50.0f
+#define PLAYER_WIDTH 25.0f
+#define PLAYER_HEIGHT 25.0f
 #define PLAYER_SPEED 500.0f
-#define PLAYER_GRAVITY 1500.0f
+#define PLAYER_JUMP 550.0f
+#define PLAYER_DEATH_DURATION 500
+
+typedef enum player_state_t {
+    PLAYER_STATE_ALIVE = 0,
+    PLAYER_STATE_DYING
+} player_state_t;
 
 struct player_t {
-    vec_t position;
-    vec_t velocity;
-    vec_t movement;
-    float height;
-    float width;
+    lt_t *lt;
+    player_state_t state;
+
+    rigid_rect_t *alive_body;
+    dying_rect_t *dying_body;
+
     int jump_count;
-};
+    color_t color;
 
-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, */
+    /* TODO(#110): introduce checkpoints */
+    vec_t checkpoint;
 };
 
-static vec_t opposing_force_by_sides(int sides[RECT_SIDE_N])
+player_t *create_player(float x, float y, color_t color)
 {
-    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;
-}
+    lt_t *lt = create_lt();
 
-player_t *create_player(float x, float y)
-{
-    player_t *player = malloc(sizeof(player_t));
+    if (lt == NULL) {
+        return NULL;
+    }
 
+    player_t *player = PUSH_LT(lt, malloc(sizeof(player_t)), free);
     if (player == NULL) {
         throw_error(ERROR_TYPE_LIBC);
-        return NULL;
+        RETURN_LT(lt, NULL);
+    }
+
+    player->state = PLAYER_STATE_ALIVE;
+
+    player->alive_body = PUSH_LT(
+        lt,
+        create_rigid_rect(
+            rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
+            color),
+        destroy_rigid_rect);
+    if (player->alive_body == NULL) {
+        RETURN_LT(lt, NULL);
     }
 
-    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;
-    player->jump_count = 2;
+    player->dying_body = PUSH_LT(
+        lt,
+        create_dying_rect(
+            rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT),
+            color,
+            PLAYER_DEATH_DURATION),
+        destroy_dying_rect);
+    if (player->dying_body == NULL) {
+        RETURN_LT(lt, NULL);
+    }
+
+    player->lt = lt;
+    player->jump_count = 0;
+    player->color = color;
+    player->checkpoint = vec(x, y);
 
     return player;
 }
@@ -73,32 +85,21 @@ player_t *create_player_from_stream(FILE *stream)
 {
     float x = 0.0f, y = 0.0f;
 
-    if (fscanf(stream, "%f%f", &x, &y) == EOF) {
+    char color[7];
+    if (fscanf(stream, "%f%f%6s", &x, &y, color) == EOF) {
         throw_error(ERROR_TYPE_LIBC);
         return NULL;
     }
 
-    return create_player(x, y);
+    return create_player(x, y, color_from_hexstr(color));
 }
 
 void destroy_player(player_t * player)
 {
-    free(player);
-}
-
-rect_t player_hitbox(const player_t *player)
-{
-    rect_t hitbox = {
-        .x = player->position.x - player->width / 2,
-        .y = player->position.y - player->height,
-        .w = player->width,
-        .h = player->height
-    };
-
-    return hitbox;
+    RETURN_LT0(player->lt);
 }
 
-int render_player(const player_t * player,
+int player_render(const player_t * player,
                   SDL_Renderer *renderer,
                   const camera_t *camera)
 {
@@ -106,100 +107,103 @@ int render_player(const player_t * player,
     assert(renderer);
     assert(camera);
 
-    if (SDL_SetRenderDrawColor(renderer, 96, 255, 96, 255) < 0) {
-        throw_error(ERROR_TYPE_SDL2);
-        return -1;
-    }
-    rect_t player_object = player_hitbox(player);
+    switch (player->state) {
+    case PLAYER_STATE_ALIVE:
+        return rigid_rect_render(player->alive_body, renderer, camera);
+
+    case PLAYER_STATE_DYING:
+        return dying_rect_render(player->dying_body, renderer, camera);
 
+    default: {}
+    }
 
-    return camera_fill_rect(camera, renderer, &player_object);
+    return 0;
 }
 
-void update_player(player_t *player,
+void player_update(player_t *player,
                    const platforms_t *platforms,
                    Uint32 delta_time)
 {
     assert(player);
     assert(platforms);
 
-    float d = (float) delta_time / 1000.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);
-
-    int sides[RECT_SIDE_N] = { 0, 0, 0, 0 };
+    switch (player->state) {
+    case PLAYER_STATE_ALIVE: {
+        rigid_rect_update(player->alive_body, platforms, delta_time);
 
-    platforms_rect_object_collide(platforms, player_hitbox(player), sides);
-    vec_t opposing_force = opposing_force_by_sides(sides);
-
-    if (sides[RECT_SIDE_BOTTOM]) {
-        player->jump_count = 2;
-    }
+        if (rigid_rect_touches_ground(player->alive_body)) {
+            player->jump_count = 0;
+        }
 
-    for (int i = 0; i < 1000 && vec_length(opposing_force) > 1e-6; ++i) {
-        player->position = vec_sum(
-            player->position,
-            vec_scala_mult(
-                opposing_force,
-                1e-2f));
+        const rect_t hitbox = rigid_rect_hitbox(player->alive_body);
 
-        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 (hitbox.y > 1000.0f) {
+            player_die(player);
         }
-
-        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;
+    } break;
+
+    case PLAYER_STATE_DYING: {
+        dying_rect_update(player->dying_body, delta_time);
+
+        if (dying_rect_is_dead(player->dying_body)) {
+            player->alive_body = RESET_LT(
+                player->lt,
+                player->alive_body,
+                create_rigid_rect(
+                    rect_from_vecs(
+                        player->checkpoint,
+                        vec(PLAYER_WIDTH, PLAYER_HEIGHT)),
+                    player->color));
+            player->state = PLAYER_STATE_ALIVE;
         }
+    } break;
 
-        platforms_rect_object_collide(
-            platforms,
-            player_hitbox(player),
-            sides);
-        opposing_force = opposing_force_by_sides(sides);
+    default: {}
     }
 }
 
 void player_move_left(player_t *player)
 {
     assert(player);
-
-    player->movement.x = -PLAYER_SPEED;
-    player->movement.y = 0.0f;
+    rigid_rect_move(player->alive_body, vec(-PLAYER_SPEED, 0.0f));
 }
 
 void player_move_right(player_t *player)
 {
     assert(player);
 
-    player->movement.x = PLAYER_SPEED;
-    player->movement.y = 0.0f;
+    rigid_rect_move(player->alive_body, vec(PLAYER_SPEED, 0.0f));
 }
 
 void player_stop(player_t *player)
 {
     assert(player);
 
-    player->movement.x = 0.0f;
-    player->movement.y = 0.0f;
+    rigid_rect_move(player->alive_body, vec(0.0f, 0.0f));
 }
 
 void player_jump(player_t *player)
+{
+    assert(player);
+    if (player->jump_count < 2) {
+        rigid_rect_jump(player->alive_body, PLAYER_JUMP);
+        player->jump_count++;
+    }
+}
+
+void player_die(player_t *player)
 {
     assert(player);
 
-    if (player->jump_count > 0) {
-        player->velocity.y = -550.0f;
-        --player->jump_count;
+    if (player->state == PLAYER_STATE_ALIVE) {
+        player->dying_body = RESET_LT(
+            player->lt,
+            player->dying_body,
+            create_dying_rect(
+                rigid_rect_hitbox(player->alive_body),
+                player->color,
+                PLAYER_DEATH_DURATION));
+        player->state = PLAYER_STATE_DYING;
     }
 }
 
@@ -209,7 +213,13 @@ void player_focus_camera(player_t *player,
     assert(player);
     assert(camera);
 
-    camera_center_at(camera, vec_sum(player->position, vec(0.0f, -player->height * 0.5f)));
+    const rect_t player_hitbox = rigid_rect_hitbox(player->alive_body);
+
+    camera_center_at(
+        camera,
+        vec_sum(
+            vec(player_hitbox.x, player_hitbox.y),
+            vec(0.0f, -player_hitbox.h * 0.5f)));
 }
 
 void player_hide_goals(const player_t *player,
@@ -217,5 +227,13 @@ void player_hide_goals(const player_t *player,
 {
     assert(player);
     assert(goals);
-    goals_hide(goals, player->position);
+    goals_hide(goals, rigid_rect_hitbox(player->alive_body));
+}
+
+void player_die_from_lava(player_t *player,
+                          const lava_t *lava)
+{
+    if (lava_overlaps_rect(lava, rigid_rect_hitbox(player->alive_body))) {
+        player_die(player);
+    }
 }