spherecast

wip first person shooter engine
Download | Log | Files | Refs

main.c (4472B)


      1 #include <float.h>
      2 #include <math.h>
      3 #include <raylib.h>
      4 #include <raymath.h>
      5 #include <stdlib.h>
      6 
      7 #include "config.h"
      8 #include "physics.h"
      9 #include "player.h"
     10 #define SQR(x) ((x) * (x))
     11 
     12 Triangle *BuildTriangleCache(Model *model, int *outCount) {
     13   int total = 0;
     14   for (int m = 0; m < model->meshCount; m++)
     15     total += model->meshes[m].triangleCount;
     16 
     17   Triangle *tris = malloc(sizeof(Triangle) * total);
     18   int t = 0;
     19 
     20   for (int m = 0; m < model->meshCount; m++) {
     21     Mesh mesh = model->meshes[m];
     22     float *v = mesh.vertices;
     23     unsigned short *idx = mesh.indices;
     24 
     25     for (int i = 0; i < mesh.triangleCount; i++) {
     26       Vector3 a = {v[idx[i * 3 + 0] * 3 + 0], v[idx[i * 3 + 0] * 3 + 1],
     27                    v[idx[i * 3 + 0] * 3 + 2]};
     28       Vector3 b = {v[idx[i * 3 + 1] * 3 + 0], v[idx[i * 3 + 1] * 3 + 1],
     29                    v[idx[i * 3 + 1] * 3 + 2]};
     30       Vector3 c = {v[idx[i * 3 + 2] * 3 + 0], v[idx[i * 3 + 2] * 3 + 1],
     31                    v[idx[i * 3 + 2] * 3 + 2]};
     32 
     33       Vector3 normal = Vector3Normalize(
     34           Vector3CrossProduct(Vector3Subtract(b, a), Vector3Subtract(c, a)));
     35 
     36       Vector3 min = {fminf(a.x, fminf(b.x, c.x)), fminf(a.y, fminf(b.y, c.y)),
     37                      fminf(a.z, fminf(b.z, c.z))};
     38       Vector3 max = {fmaxf(a.x, fmaxf(b.x, c.x)), fmaxf(a.y, fmaxf(b.y, c.y)),
     39                      fmaxf(a.z, fmaxf(b.z, c.z))};
     40 
     41       tris[t++] = (Triangle){a, b, c, normal, min, max};
     42     }
     43   }
     44 
     45   *outCount = total;
     46   return tris;
     47 }
     48 
     49 void UpdatePlayerCamera(Camera3D *c, Player *p, float deltaTime) {
     50   static float smoothHeight = 0.0f;
     51   smoothHeight += (p->height - smoothHeight) * CROUCH_LERP_SPEED * deltaTime;
     52 
     53   Vector3 eyePos = {p->pos.x, p->pos.y + smoothHeight, p->pos.z};
     54   c->position = eyePos;
     55 
     56   Vector3 forward = {cosf(p->rot.y) * sinf(p->rot.z), sinf(p->rot.y),
     57                      cosf(p->rot.y) * cosf(p->rot.z)};
     58 
     59   c->target = Vector3Add(eyePos, forward);
     60 
     61   Vector3 targetUp = Vector3RotateByAxisAngle(UP, forward, p->rot.x);
     62   float upLerpSpeed = 0.1f;
     63   c->up = Vector3Lerp(c->up, targetUp, upLerpSpeed);
     64 }
     65 
     66 int main(void) {
     67   InitWindow(WIDTH, HEIGHT, "Sphere Character Controller");
     68   DisableCursor();
     69   SetTargetFPS(TARGET_FPS);
     70   SetConfigFlags(FLAG_VSYNC_HINT);
     71 
     72   Camera3D camera = {.position = {0, 0, 0},
     73                      .target = {0, 0, 1},
     74                      .up = UP,
     75                      .fovy = BASE_FOV,
     76                      .projection = CAMERA_PERSPECTIVE};
     77 
     78   Model model = LoadModel("assets/level.glb");
     79 
     80   int triCount = 0;
     81   Triangle *triangles = BuildTriangleCache(&model, &triCount);
     82 
     83   static Player player;
     84   static enum Input input;
     85   player.vel = Vector3Zero();
     86   player.pos = Vector3Zero();
     87   player.height = PLAYER_HEIGHT;
     88   player.radius = PLAYER_RADIUS;
     89   player.grounded = false;
     90 
     91   while (!WindowShouldClose()) {
     92     float dt = GetFrameTime();
     93     Vector2 md = GetMouseDelta();
     94 
     95     player.rot.z -= md.x * MOUSE_SENSITIVITY;
     96     player.rot.y -= md.y * MOUSE_SENSITIVITY;
     97     player.rot.y = Clamp(player.rot.y, -MAX_PITCH, MAX_PITCH);
     98 
     99     input = 0;
    100     if (IsKeyDown(KEY_W))
    101       input |= INPUT_FORWARD;
    102     if (IsKeyDown(KEY_S))
    103       input |= INPUT_BACKWARD;
    104     if (IsKeyDown(KEY_A))
    105       input |= INPUT_LEFT;
    106     if (IsKeyDown(KEY_D))
    107       input |= INPUT_RIGHT;
    108     if (IsKeyDown(KEY_C))
    109       input |= INPUT_CROUCH;
    110     if (IsKeyDown(KEY_LEFT_SHIFT))
    111       input |= INPUT_SPRINT;
    112     if (IsKeyDown(KEY_SPACE))
    113       input |= INPUT_JUMP;
    114 
    115     if (IsKeyPressed(KEY_R))
    116       player.pos = player.vel = Vector3Zero();
    117 
    118     PlayerUpdate(&player, input, dt);
    119     player.vel.y -= GRAVITY * dt;
    120     PlayerApplyFriction(&player, dt);
    121     PlayerApplyAcceleration(&player, input, dt);
    122     player.pos = Vector3Add(player.pos, Vector3Scale(player.vel, dt));
    123     ResolveCollisions(&player, triangles, triCount);
    124     UpdatePlayerCamera(&camera, &player, dt);
    125 
    126     BeginDrawing();
    127     ClearBackground(RAYWHITE);
    128     BeginMode3D(camera);
    129 
    130     DrawModel(model, Vector3Zero(), 1.0f, WHITE);
    131 
    132     EndMode3D();
    133 
    134     DrawText(TextFormat("Pos: %.2f %.2f %.2f", player.pos.x, player.pos.y,
    135                         player.pos.z),
    136              10, 10, 20, BLACK);
    137 
    138     DrawText(TextFormat("Vel: %.4f %.4f %.4f", player.vel.x, player.vel.y,
    139                         player.vel.z),
    140              10, 30, 20, BLACK);
    141 
    142     DrawText(TextFormat("Grounded: %b", player.grounded), 10, 50, 20, BLACK);
    143 
    144     EndDrawing();
    145   }
    146 
    147   UnloadModel(model);
    148   free(triangles);
    149   CloseWindow();
    150   return 0;
    151 }