From 54a2775f28a3108f5d0d687fc6dfef35bb3c1606 Mon Sep 17 00:00:00 2001 From: bossy Date: Sun, 5 Jul 2026 12:42:34 +0300 Subject: [PATCH] add fps camera --- src/level00.c | 24 ++++--------- src/main.c | 64 +++++++++++++++++++++++++++++---- src/player.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/player.h | 29 +++++++++++++++ src/screen.h | 1 + 5 files changed, 192 insertions(+), 24 deletions(-) create mode 100644 src/player.c create mode 100644 src/player.h diff --git a/src/level00.c b/src/level00.c index ffd2f7f..3d57c79 100644 --- a/src/level00.c +++ b/src/level00.c @@ -5,7 +5,8 @@ void DrawLevel00() { const int floorExtent = 25; const float tileSize = 5.0f; - + + // Draw floor for (int y = -floorExtent; y < floorExtent; y++) { for (int x = -floorExtent; x < floorExtent; x++) { if ((y & 1) ^ (x & 1)) { @@ -14,21 +15,8 @@ void DrawLevel00() } } - const Vector3 towerSize = (Vector3){ 16.0f, 32.0f, 16.0f }; - - Vector3 towerPos = (Vector3){ 16.0f, 16.0f, 16.0f }; - DrawCubeV(towerPos, towerSize, RED); - DrawCubeWiresV(towerPos, towerSize, BLACK); - - towerPos.x *= -1; - DrawCubeV(towerPos, towerSize, RED); - DrawCubeWiresV(towerPos, towerSize, BLACK); - - towerPos.z *= -1; - DrawCubeV(towerPos, towerSize, RED); - DrawCubeWiresV(towerPos, towerSize, BLACK); - - towerPos.x *= -1; - DrawCubeV(towerPos, towerSize, RED); - DrawCubeWiresV(towerPos, towerSize, BLACK); + DrawPlane((Vector3){ 0.0f, 0.0f, 0.0f }, (Vector2){ 32.0f, 32.0f }, LIGHTGRAY); // Draw ground + DrawCube((Vector3){ -16.0f, 2.5f, 0.0f }, 1.0f, 5.0f, 32.0f, BLUE); // Draw a blue wall + DrawCube((Vector3){ 16.0f, 2.5f, 0.0f }, 1.0f, 5.0f, 32.0f, GREEN); // Draw a green wall + DrawCube((Vector3){ 0.0f, 2.5f, 16.0f }, 32.0f, 5.0f, 1.0f, YELLOW); // Draw a yellow wall } diff --git a/src/main.c b/src/main.c index 224f618..4abd4cc 100644 --- a/src/main.c +++ b/src/main.c @@ -1,21 +1,73 @@ #include "raylib.h" +#include "raymath.h" #include "screen.h" +#include "player.h" + +extern Vector2 lookRotation; +extern Vector2 lean; +extern float headTimer; +extern float walkLerp; + +static float heights[MAX_COLUMNS] = {0}; +static Vector3 positions[MAX_COLUMNS] = {0}; +static Color colors[MAX_COLUMNS] = {0}; int main() { InitWindow(800, 600, "Super cool game"); - SetTargetFPS(GAME_FPS); + + Body player = {0}; + Vector2 sensitivity = { 0.001f, 0.001f }; + + float headLerp = STAND_HEIGHT; Camera3D camera = { 0 }; - camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; - camera.target = (Vector3){ 0.0f, 12.0f, 0.0f }; - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.fovy = 60.0f; camera.projection = CAMERA_PERSPECTIVE; + camera.position = (Vector3) { + player.position.x, + player.position.y + (BOTTOM_HEIGHT + headLerp), + player.position.z, + }; + + UpdateFpsCamera(&camera); + + DisableCursor(); + SetTargetFPS(GAME_FPS); while (!WindowShouldClose()) { - UpdateCamera(&camera, CAMERA_FREE); - DisableCursor(); + Vector2 mouseDelta = GetMouseDelta(); + lookRotation.x -= mouseDelta.x*sensitivity.x; + lookRotation.y += mouseDelta.y*sensitivity.y; + + char sideway = (IsKeyDown(KEY_D) - IsKeyDown(KEY_A)); + char forward = (IsKeyDown(KEY_W) - IsKeyDown(KEY_S)); + + bool crouching = IsKeyDown(KEY_LEFT_CONTROL); + UpdateBody(&player, lookRotation.x, sideway, forward, IsKeyPressed(KEY_SPACE), crouching); + + float delta = GetFrameTime(); + headLerp = Lerp(headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f*delta); + camera.position = (Vector3){ + player.position.x, + player.position.y + (BOTTOM_HEIGHT + headLerp), + player.position.z, + }; + + if (player.grounded && ((forward != 0) || (sideway != 0))) { + headTimer += delta*3.0f; + walkLerp = Lerp(walkLerp, 1.0f, 10.0f*delta); + camera.fovy = Lerp(camera.fovy, 55.0f, 5.0f*delta); + } + else { + walkLerp = Lerp(walkLerp, 0.0f, 10.0f*delta); + camera.fovy = Lerp(camera.fovy, 60.0f, 5.0f*delta); + } + + lean.x = Lerp(lean.x, sideway*0.02f, 10.0f*delta); + lean.y = Lerp(lean.y, forward*0.015f, 10.0f*delta); + + UpdateFpsCamera(&camera); BeginDrawing(); ClearBackground(RAYWHITE); diff --git a/src/player.c b/src/player.c new file mode 100644 index 0000000..4045834 --- /dev/null +++ b/src/player.c @@ -0,0 +1,98 @@ +#include "raylib.h" +#include "raymath.h" +#include "player.h" + +Vector2 lookRotation = {0}; +Vector2 lean = {0}; +float headTimer = 0.0f; +float walkLerp = 0.0f; + +void UpdateFpsCamera(Camera *camera) +{ + const Vector3 up = (Vector3){ 0.0f, 1.0f, 0.0f }; + const Vector3 targetOffset = (Vector3){ 0.0f, 0.0f, -1.0f }; + + Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, lookRotation.x); + + float maxAngleUp = Vector3Angle(up, yaw); + maxAngleUp -= 0.001f; + if ( -(lookRotation.y) > maxAngleUp) { lookRotation.y = -maxAngleUp; } + + Vector3 right = Vector3Normalize(Vector3CrossProduct(yaw, up)); + + float pitchAngle = -lookRotation.y - lean.y; + pitchAngle = Clamp(pitchAngle, -PI/2 + 0.0001f, PI/2 - 0.0001f); + Vector3 pitch = Vector3RotateByAxisAngle(yaw, right, pitchAngle); + + float headSin = sinf(headTimer*PI); + float headCos = cosf(headTimer*PI); + const float stepRotation = 0.01f; + camera->up = Vector3RotateByAxisAngle(up, pitch, headSin*stepRotation + lean.x); + + const float bobSide = 0.1f; + const float bobUp = 0.15f; + Vector3 bobbing = Vector3Scale(right, headSin*bobSide); + bobbing.y = fabsf(headCos*bobUp); + + camera->position = Vector3Add(camera->position, Vector3Scale(bobbing, walkLerp)); + camera->target = Vector3Add(camera->position, pitch); +} + +void UpdateBody(Body *body, float rot, char side, char forward, bool jumpPressed, bool crouchHold) +{ + Vector2 input = (Vector2){ (float)side, (float)-forward }; + +#if defined(NORMALIZE_INPUT) + // Slow down diagonal movement + if ((side != 0) && (forward != 0)) input = Vector2Normalize(input); +#endif + + float delta = GetFrameTime(); + + if (!body->grounded) body->velocity.y -= GRAVITY*delta; + + if (body->grounded && jumpPressed) + { + body->velocity.y = JUMP_FORCE; + body->grounded = false; + + // Sound can be played at this moment + //SetSoundPitch(fxJump, 1.0f + (GetRandomValue(-100, 100)*0.001)); + //PlaySound(fxJump); + } + + Vector3 front = (Vector3){ sinf(rot), 0.f, cosf(rot) }; + Vector3 right = (Vector3){ cosf(-rot), 0.f, sinf(-rot) }; + + Vector3 desiredDir = (Vector3){ input.x*right.x + input.y*front.x, 0.0f, input.x*right.z + input.y*front.z, }; + body->dir = Vector3Lerp(body->dir, desiredDir, CONTROL*delta); + + float decel = (body->grounded ? FRICTION : AIR_DRAG); + Vector3 hvel = (Vector3){ body->velocity.x*decel, 0.0f, body->velocity.z*decel }; + + float hvelLength = Vector3Length(hvel); // Magnitude + if (hvelLength < (MAX_SPEED*0.01f)) hvel = (Vector3){ 0 }; + + // This is what creates strafing + float speed = Vector3DotProduct(hvel, body->dir); + + float maxSpeed = (crouchHold? CROUCH_SPEED : MAX_SPEED); + float accel = Clamp(maxSpeed - speed, 0.f, MAX_ACCEL*delta); + hvel.x += body->dir.x*accel; + hvel.z += body->dir.z*accel; + + body->velocity.x = hvel.x; + body->velocity.z = hvel.z; + + body->position.x += body->velocity.x*delta; + body->position.y += body->velocity.y*delta; + body->position.z += body->velocity.z*delta; + + // Fancy collision system against the floor + if (body->position.y <= 0.0f) + { + body->position.y = 0.0f; + body->velocity.y = 0.0f; + body->grounded = true; // Enable jumping + } +} diff --git a/src/player.h b/src/player.h new file mode 100644 index 0000000..7a0c87f --- /dev/null +++ b/src/player.h @@ -0,0 +1,29 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include "raylib.h" + +#define GRAVITY 32.0f +#define MAX_SPEED 20.0f +#define CROUCH_SPEED 5.0f +#define JUMP_FORCE 12.0f +#define CONTROL 15.0f +#define MAX_ACCEL 150.0f +#define FRICTION 0.86f +#define AIR_DRAG 0.98f +#define BOTTOM_HEIGHT 0.5f +#define CROUCH_HEIGHT 0.4f +#define STAND_HEIGHT 1.0f + +typedef struct { + Vector3 position; + Vector3 velocity; + Vector3 dir; + bool grounded; +} Body; + +void UpdateFpsCamera(Camera *camera); +void UpdateBody(Body *body, float rot, char side, char forward, bool jump, bool crouch); + +#endif diff --git a/src/screen.h b/src/screen.h index 3608cab..63b2840 100644 --- a/src/screen.h +++ b/src/screen.h @@ -2,6 +2,7 @@ #define SCREEN_H #define GAME_FPS 60 +#define MAX_COLUMNS 20 void DrawLevel00();