diff --git a/assets/shaders/skybox.fs b/assets/shaders/skybox.fs new file mode 100644 index 0000000..d71fef0 --- /dev/null +++ b/assets/shaders/skybox.fs @@ -0,0 +1,30 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; + +// Input uniform values +uniform samplerCube environmentMap; +uniform bool vflipped; +uniform bool doGamma; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + // Fetch color from texture map + vec3 color = vec3(0.0); + + if (vflipped) color = texture(environmentMap, vec3(fragPosition.x, -fragPosition.y, fragPosition.z)).rgb; + else color = texture(environmentMap, fragPosition).rgb; + + if (doGamma)// Apply gamma correction + { + color = color/(color + vec3(1.0)); + color = pow(color, vec3(1.0/2.2)); + } + + // Calculate final fragment color + finalColor = vec4(color, 1.0); +} diff --git a/assets/shaders/skybox.vs b/assets/shaders/skybox.vs new file mode 100644 index 0000000..f41d469 --- /dev/null +++ b/assets/shaders/skybox.vs @@ -0,0 +1,24 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; + +// Input uniform values +uniform mat4 matProjection; +uniform mat4 matView; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; + +void main() +{ + // Calculate fragment position based on model transformations + fragPosition = vertexPosition; + + // Remove translation from the view matrix + mat4 rotView = mat4(mat3(matView)); + vec4 clipPos = matProjection*rotView*vec4(vertexPosition, 1.0); + + // Calculate final vertex position + gl_Position = clipPos; +} diff --git a/assets/textures/Grass_01.png b/assets/textures/Grass_01.png new file mode 100644 index 0000000..44d33b1 Binary files /dev/null and b/assets/textures/Grass_01.png differ diff --git a/assets/textures/cubemaps/back.png b/assets/textures/cubemaps/back.png new file mode 100644 index 0000000..ad4bfb1 Binary files /dev/null and b/assets/textures/cubemaps/back.png differ diff --git a/assets/textures/cubemaps/bottom.png b/assets/textures/cubemaps/bottom.png new file mode 100644 index 0000000..7806f64 Binary files /dev/null and b/assets/textures/cubemaps/bottom.png differ diff --git a/assets/textures/cubemaps/cubemap.png b/assets/textures/cubemaps/cubemap.png new file mode 100644 index 0000000..6f30378 Binary files /dev/null and b/assets/textures/cubemaps/cubemap.png differ diff --git a/assets/textures/cubemaps/front.png b/assets/textures/cubemaps/front.png new file mode 100644 index 0000000..1d0ea9a Binary files /dev/null and b/assets/textures/cubemaps/front.png differ diff --git a/assets/textures/cubemaps/left.png b/assets/textures/cubemaps/left.png new file mode 100644 index 0000000..aeef23b Binary files /dev/null and b/assets/textures/cubemaps/left.png differ diff --git a/assets/textures/cubemaps/right.png b/assets/textures/cubemaps/right.png new file mode 100644 index 0000000..e6bcb90 Binary files /dev/null and b/assets/textures/cubemaps/right.png differ diff --git a/assets/textures/cubemaps/top.png b/assets/textures/cubemaps/top.png new file mode 100644 index 0000000..85257d3 Binary files /dev/null and b/assets/textures/cubemaps/top.png differ diff --git a/src/main.c b/src/main.c index e65fa02..050dbb3 100644 --- a/src/main.c +++ b/src/main.c @@ -1,23 +1,12 @@ -/******************************************************************************************* -* -* raylib [core] example - 3d camera fps -* -* Example complexity rating: [★★★☆] 3/4 -* -* Example originally created with raylib 5.5, last time updated with raylib 5.5 -* -* Example contributed by Agnis Aldins (@nezvers) and reviewed by Ramon Santamaria (@raysan5) -* -* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified, -* BSD-like license that allows static linking with closed source software -* -* Copyright (c) 2025 Agnis Aldins (@nezvers) -* -********************************************************************************************/ - #include "raylib.h" - +#include "rcamera.h" #include "raymath.h" +#include "stdbool.h" +#include "stddef.h" +#include "stdlib.h" +#include "stdint.h" +#include "rlgl.h" +#include "float.h" //---------------------------------------------------------------------------------- // Defines and Macros @@ -28,47 +17,81 @@ #define CROUCH_SPEED 5.0f #define JUMP_FORCE 12.0f #define MAX_ACCEL 150.0f + // Grounded drag #define FRICTION 0.86f + // Increasing air drag, increases strafing speed #define AIR_DRAG 0.98f + // Responsiveness for turning movement direction to looked direction #define CONTROL 15.0f #define CROUCH_HEIGHT 0.0f -#define STAND_HEIGHT 1.0f +#define STAND_HEIGHT 2.0f #define BOTTOM_HEIGHT 0.5f +// Additional definitions #define NORMALIZE_INPUT 0 +#define ARRLEN(a) (sizeof(a) / sizeof((a)[0])) + +#define FLOOR_EXTENT 25 +#define TILE_SIZE 5.0f + +#define PLAYER_RADIUS 0.5f +#define PLAYER_HEIGHT 1.8f + +enum game_state { + STATE_MENU, // 0 by default + STATE_GAME, // 1 +}; //---------------------------------------------------------------------------------- -// Types and Structures Definition +//Defining program structure //---------------------------------------------------------------------------------- -// Body structure -typedef struct { - Vector3 position; +typedef struct +{ + Camera camera; // <- now part of the game state + Model model; // you can keep model & its position here too + Vector3 position; Vector3 velocity; Vector3 dir; + Vector2 sensitivity; + Vector2 lookRotation; + Vector2 lean; + float headTimer; + float walkLerp; + float headLerp; bool isGrounded; -} Body; + int cameraMode; +} Player; -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static Vector2 sensitivity = { 0.001f, 0.001f }; +typedef struct +{ + int index; + enum game_state state; + int shouldExit; + Player player; + int nearAcorn; + int isJumpscared; + float jumpscareTimer; -static Body player = { 0 }; -static Vector2 lookRotation = { 0 }; -static float headTimer = 0.0f; -static float walkLerp = 0.0f; -static float headLerp = STAND_HEIGHT; -static Vector2 lean = { 0 }; + Sound jumpScare; + Music bgm; +} Master; -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -static void DrawLevel(void); -static void UpdateCameraFPS(Camera *camera); -static void UpdateBody(Body *body, float rot, char side, char forward, bool jumpPressed, bool crouchHold); +//------------------------------------------------------------------------------------ +// Function Initation +//------------------------------------------------------------------------------------ +void Simple_Center_Box(double percent_verticle_gap, double percent_horizontal_gap, int screenWidth, int screenHeight, Color color); +void Thick_Center_Box(double percent_verticle_gap, double percent_horizontal_gap, float line_width, int screenWidth, int screenHeight, Color color); +void Simple_Menu(const char *array[], int count, int index, int x1, int y1, int total_width, int total_height, int line_thickess, int font_size, Color color, Color alt_color); +void UpdateBody(Master* g, float rot, char side, char forward, bool jumpPressed, bool crouchHold); +static void UpdateCameraAngle(Master* g); +static void DrawLevel(Model mdlTile); +static void CenterMouseAndFlush(void); +int Random(int x); + +float square(float num); //------------------------------------------------------------------------------------ // Program main entry point @@ -77,105 +100,363 @@ int main(void) { // Initialization //-------------------------------------------------------------------------------------- - const int screenWidth = 1980; - const int screenHeight = 1080; - InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera fps"); + // Before InitWindow + SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE | FLAG_MSAA_4X_HINT | FLAG_FULLSCREEN_MODE); - // Initialize camera variables - // NOTE: UpdateCameraFPS() takes care of the rest - Camera camera = { 0 }; - camera.fovy = 60.0f; - camera.projection = CAMERA_PERSPECTIVE; - camera.position = (Vector3){ - player.position.x, - player.position.y + (BOTTOM_HEIGHT + headLerp), - player.position.z, + InitWindow(0, 0, "raylib"); + + int screenWidth = GetRenderWidth(); + int screenHeight = GetRenderHeight(); + + DisableCursor(); + CenterMouseAndFlush(); + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + + //Define menu characteristics + const char *menu[] = {"Game", "Option 2", "Exit"}; + int index_length = ARRLEN(menu); + + //General game state initiation + Master g = (Master){0}; + g.index = 0; + g.state = STATE_MENU; + g.shouldExit = 0; + g.nearAcorn = 0; + g.isJumpscared = 0; + + //Define player values + g.player.sensitivity = (Vector2){ 0.001f, 0.001f }; + g.player.lookRotation = (Vector2){ 0 }; + g.player.headTimer = 0.0f; + g.player.walkLerp = 0.0f; + g.player.headLerp = STAND_HEIGHT; + g.player.lean = (Vector2){ 0 }; + + //Define the player camera + g.player.camera = (Camera){0}; + g.player.camera.position = (Vector3){ + g.player.position.x, + g.player.position.y + (BOTTOM_HEIGHT + g.player.headLerp), + g.player.position.z, + }; + g.player.camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; + g.player.camera.fovy = 60.0f; + g.player.camera.projection = CAMERA_PERSPECTIVE; + g.player.cameraMode = CAMERA_FIRST_PERSON; + + g.player.position.x = 15.0; + g.player.position.z = 15.0; + + UpdateCameraAngle(&g); + + // Grass tile setup + Texture2D texGrass = LoadTexture("assets/textures/Grass_01.png"); + GenTextureMipmaps(&texGrass); + SetTextureFilter(texGrass, TEXTURE_FILTER_TRILINEAR); // nicer at angles + SetTextureWrap(texGrass, TEXTURE_WRAP_REPEAT); + + // A 3D plane (centered at origin) of size tileSize x tileSize + const float tileSize = TILE_SIZE; + Mesh meshTile = GenMeshPlane(tileSize, tileSize, 1, 1); + Model mdlTile = LoadModelFromMesh(meshTile); + mdlTile.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = texGrass; + + + // --- Skybox setup using 6 face images --- + Mesh cube = GenMeshCube(1.0f, 1.0f, 1.0f); + Model skybox = LoadModelFromMesh(cube); + + // Load skybox shader + Shader skyboxShader = LoadShader( + "assets/shaders/skybox.vs", + "assets/shaders/skybox.fs" + ); + skybox.materials[0].shader = skyboxShader; + + // Load the 6 faces (+X, -X, +Y, -Y, +Z, -Z) + const char* facePaths[6] = { + "assets/textures/cubemaps/right.png", // +X + "assets/textures/cubemaps/left.png", // -X + "assets/textures/cubemaps/top.png", // +Y + "assets/textures/cubemaps/bottom.png", // -Y + "assets/textures/cubemaps/front.png", // +Z + "assets/textures/cubemaps/back.png" // -Z }; - UpdateCameraFPS(&camera); // Update camera parameters + Image faces[6]; + for (int i = 0; i < 6; i++) { + faces[i] = LoadImage(facePaths[i]); + // Ensure consistent format + if (faces[i].format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) + ImageFormat(&faces[i], PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + } - DisableCursor(); // Limit cursor to relative movement inside the window + // Verify same size + int fw = faces[0].width, fh = faces[0].height; + for (int i = 1; i < 6; i++) { + if (faces[i].width != fw || faces[i].height != fh) { + TraceLog(LOG_ERROR, "Cubemap face sizes differ"); + // (optional) handle error/cleanup here + } + } + + // Stitch into a vertical strip (CUBEMAP_LAYOUT_LINE_VERTICAL) + Image strip = GenImageColor(fw, fh*6, BLANK); + for (int i = 0; i < 6; i++) { + ImageDraw(&strip, faces[i], + (Rectangle){0,0,(float)fw,(float)fh}, + (Rectangle){0,(float)(i*fh),(float)fw,(float)fh}, + WHITE); + UnloadImage(faces[i]); // free each face once copied + } + + // IMPORTANT: skip CPU mipmap generation to avoid the buggy path + strip.mipmaps = 1; + + // Load cubemap from the vertical strip + TextureCubemap cubeTex = LoadTextureCubemap(strip, CUBEMAP_LAYOUT_LINE_VERTICAL); + UnloadImage(strip); + + // Assign to material & use a non-mipmap filter (skyboxes don't need mips) + skybox.materials[0].maps[MATERIAL_MAP_CUBEMAP].texture = cubeTex; + SetTextureFilter(cubeTex, TEXTURE_FILTER_BILINEAR); + + // Tell the shader which material map is the environmentMap + int mapType = MATERIAL_MAP_CUBEMAP; + SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "environmentMap"), + &mapType, SHADER_UNIFORM_INT); + + // Optional flags (keep as you had) + int vflipped = 0, doGamma = 0; + SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "vflipped"), + &vflipped, SHADER_UNIFORM_INT); + SetShaderValue(skyboxShader, GetShaderLocation(skyboxShader, "doGamma"), + &doGamma, SHADER_UNIFORM_INT); - SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + //-------------------------------------------------------------------------------------- + while (!g.shouldExit && !WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- - 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.isGrounded && ((forward != 0) || (sideway != 0))) + switch (g.state) { - 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); - } + case STATE_MENU: + { + if (IsKeyPressed(KEY_UP) && g.index > 0) + { + g.index -= 1; + break; + }; - lean.x = Lerp(lean.x, sideway*0.02f, 10.0f*delta); - lean.y = Lerp(lean.y, forward*0.015f, 10.0f*delta); + if (IsKeyPressed(KEY_DOWN) && g.index < index_length - 1) + { + g.index += 1; + break; + }; + + if (IsKeyPressed(KEY_ENTER)) + { + switch (g.index) + { + case 0: + { + g.state = 1; + CenterMouseAndFlush(); + break; + } - UpdateCameraFPS(&camera); + case 1: + { + break; + } + + case 2: + { + g.shouldExit = 1; + break; + } + } + }; + break; + }; + case STATE_GAME: + { + Vector2 mouseDelta = GetMouseDelta(); + g.player.lookRotation.x -= mouseDelta.x*g.player.sensitivity.x; + g.player.lookRotation.y += mouseDelta.y*g.player.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(&g, g.player.lookRotation.x, sideway, forward, IsKeyDown(KEY_SPACE), crouching); + + float delta = GetFrameTime(); + g.player.headLerp = Lerp(g.player.headLerp, (crouching ? CROUCH_HEIGHT : STAND_HEIGHT), 20.0f*delta); + g.player.camera.position = (Vector3){ + g.player.position.x, + g.player.position.y + (BOTTOM_HEIGHT + g.player.headLerp), + g.player.position.z, + }; + + if (g.player.isGrounded && ((forward != 0) || (sideway != 0))) + { + g.player.headTimer += delta*3.0f; + g.player.walkLerp = Lerp(g.player.walkLerp, 1.0f, 10.0f*delta); + g.player.camera.fovy = Lerp(g.player.camera.fovy, 55.0f, 5.0f*delta); + } + else + { + g.player.walkLerp = Lerp(g.player.walkLerp, 0.0f, 10.0f*delta); + g.player.camera.fovy = Lerp(g.player.camera.fovy, 60.0f, 5.0f*delta); + } + + g.player.lean.x = Lerp(g.player.lean.x, sideway*0.02f, 10.0f*delta); + g.player.lean.y = Lerp(g.player.lean.y, forward*0.015f, 10.0f*delta); + + UpdateCameraAngle(&g); + break; + }; + } //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); + switch (g.state) + { + case STATE_MENU: + { + ClearBackground(BLACK); - ClearBackground(RAYWHITE); + Simple_Menu(menu, ARRLEN(menu), g.index, screenWidth * 0.15, screenHeight * 0.15, 500, screenHeight * 0.7, 10, 50, GREEN, LIGHTGRAY); - BeginMode3D(camera); - DrawLevel(); - EndMode3D(); + Thick_Center_Box(0.1, 0.1, 10, screenWidth, screenHeight, GREEN); + break; + } + case STATE_GAME: + { + ClearBackground(BLACK); + + Vector3 camPos = g.player.camera.position; + Vector3 camFwd = Vector3Normalize(Vector3Subtract(g.player.camera.target, camPos)); - // Draw info box - DrawRectangle(5, 5, 330, 75, Fade(SKYBLUE, 0.5f)); - DrawRectangleLines(5, 5, 330, 75, BLUE); + // Camera forward (normalize target - position) + Vector3 forward = Vector3Normalize(Vector3Subtract(g.player.camera.target, g.player.camera.position)); - DrawText("Camera controls:", 15, 15, 10, BLACK); - DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 10, BLACK); - DrawText("- Look around: arrow keys or mouse", 15, 45, 10, BLACK); - DrawText(TextFormat("- Velocity Len: (%06.3f)", Vector2Length((Vector2){ player.velocity.x, player.velocity.z })), 15, 60, 10, BLACK); + BeginMode3D(g.player.camera); + rlDisableBackfaceCulling(); + rlDisableDepthMask(); + + // keep it centered on the camera + skybox.transform = MatrixTranslate( + g.player.camera.position.x, + g.player.camera.position.y, + g.player.camera.position.z + ); + + DrawModel(skybox, (Vector3){0}, 1.0f, WHITE); + + rlEnableDepthMask(); + rlEnableBackfaceCulling(); + + DrawLevel(mdlTile); + + EndMode3D(); + + // Draw info box + DrawRectangle(5, 5, 330*1.5, 75*1.25, Fade(SKYBLUE, 0.5f)); + DrawRectangleLines(5, 5, 330*1.5, 75*1.25, BLUE); + + DrawText("Camera controls:", 15, 15, 20, BLACK); + DrawText("- Move keys: W, A, S, D, Space, Left-Ctrl", 15, 30, 20, BLACK); + DrawText("- Look around: arrow keys or mouse", 15, 45, 20, BLACK); + DrawText(TextFormat("- Velocity Len: (%06.3f)", Vector2Length((Vector2){ g.player.velocity.x, g.player.velocity.z })), 15, 60, 20, BLACK); + + break; + } + } EndDrawing(); //---------------------------------------------------------------------------------- - } + }; + //-------------------------------------------------------------------------------------- // De-Initialization //-------------------------------------------------------------------------------------- + // Detach the texture from the model so UnloadModel won't try to free it. + mdlTile.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = (Texture2D){0}; + + // Now free resources you loaded: + UnloadModel(mdlTile); // frees the model and its mesh/VBOs + UnloadTexture(texGrass); // frees the grass texture you loaded + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- - return 0; +}; + +//------------------------------------------------------------------------------------ +// Function Definitions +//------------------------------------------------------------------------------------ +//Function creates a simple box outline centered in the screen with a symetric ofset from the screen borders. +void Simple_Center_Box(double percent_verticle_gap, double percent_horizontal_gap, int screenWidth, int screenHeight, Color color) +{ + int x1 = percent_horizontal_gap * screenWidth; + int y1 = percent_verticle_gap * screenHeight; + + int w = screenWidth * (1 - (2 * percent_horizontal_gap)); + int h = screenHeight * (1 - (2 * percent_verticle_gap)); + + DrawRectangleLines(x1, y1, w, h, color); } -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- -// Update body considering current world state -void UpdateBody(Body *body, float rot, char side, char forward, bool jumpPressed, bool crouchHold) +//Function creates a thick walled box outline centered in the screen with a symetric ofset from the screen borders. +void Thick_Center_Box(double percent_verticle_gap, double percent_horizontal_gap, float line_width, int screenWidth, int screenHeight, Color color) +{ + int x1 = percent_horizontal_gap * screenWidth; + int y1 = percent_verticle_gap * screenHeight; + + int w = screenWidth * (1 - (2 * percent_horizontal_gap)); + int h = screenHeight * (1 - (2 * percent_verticle_gap)); + + struct Rectangle rec = {x1,y1,w,h}; + + DrawRectangleLinesEx(rec, line_width, color); +} + +//Make a simple menu with selection features +void Simple_Menu(const char *array[], int count, int index, int x1, int y1, int total_width, int total_height, int line_thickess, int font_size, Color color, Color alt_color) +{ + float height = 0.8f * total_height; + int space = 0.2 * total_height / (count - 1); + + struct Rectangle rec = {x1,y1,total_width,(float)height/count}; + + for (int i = 0; i < count; ++i) + { + int text_width = MeasureText(array[i], font_size); + + if(i == index) + { + DrawRectangleLinesEx(rec, line_thickess, alt_color); + DrawText(array[i], rec.x + (((total_width - 2.0 * line_thickess) - text_width)/2), rec.y + (height/count/2) - font_size/2.0f, font_size, alt_color); + } + else + { + DrawRectangleLinesEx(rec, line_thickess, color); + DrawText(array[i], rec.x + (((total_width - 2.0 * line_thickess) - text_width)/2), rec.y + (height/count/2) - font_size/2.0f, font_size, color); + } + + rec.y = rec.y + (float)height/count + space; + } +} + +void UpdateBody(Master* g, float rot, char side, char forward, bool jumpPressed, bool crouchHold) { Vector2 input = (Vector2){ (float)side, (float)-forward }; @@ -186,12 +467,12 @@ void UpdateBody(Body *body, float rot, char side, char forward, bool jumpPressed float delta = GetFrameTime(); - if (!body->isGrounded) body->velocity.y -= GRAVITY*delta; + if (!g->player.isGrounded) g->player.velocity.y -= GRAVITY*delta; - if (body->isGrounded && jumpPressed) + if (g->player.isGrounded && jumpPressed) { - body->velocity.y = JUMP_FORCE; - body->isGrounded = false; + g->player.velocity.y = JUMP_FORCE; + g->player.isGrounded = false; // Sound can be played at this moment //SetSoundPitch(fxJump, 1.0f + (GetRandomValue(-100, 100)*0.001)); @@ -202,91 +483,92 @@ void UpdateBody(Body *body, float rot, char side, char forward, bool jumpPressed Vector3 right = (Vector3){ cos(-rot), 0.f, sin(-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); + g->player.dir = Vector3Lerp(g->player.dir, desiredDir, CONTROL*delta); - float decel = (body->isGrounded ? FRICTION : AIR_DRAG); - Vector3 hvel = (Vector3){ body->velocity.x*decel, 0.0f, body->velocity.z*decel }; + float decel = (g->player.isGrounded ? FRICTION : AIR_DRAG); + Vector3 hvel = (Vector3){ g->player.velocity.x*decel, 0.0f, g->player.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 speed = Vector3DotProduct(hvel, g->player.dir); // Whenever the amount of acceleration to add is clamped by the maximum acceleration constant, // a Player can make the speed faster by bringing the direction closer to horizontal velocity angle // More info here: https://youtu.be/v3zT3Z5apaM?t=165 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; + hvel.x += g->player.dir.x*accel; + hvel.z += g->player.dir.z*accel; - body->velocity.x = hvel.x; - body->velocity.z = hvel.z; + g->player.velocity.x = hvel.x; + g->player.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; + g->player.position.x += g->player.velocity.x*delta; + g->player.position.y += g->player.velocity.y*delta; + g->player.position.z += g->player.velocity.z*delta; // Fancy collision system against the floor - if (body->position.y <= 0.0f) + if (g->player.position.y <= 0.0f) { - body->position.y = 0.0f; - body->velocity.y = 0.0f; - body->isGrounded = true; // Enable jumping + g->player.position.y = 0.0f; + g->player.velocity.y = 0.0f; + g->player.isGrounded = true; // Enable jumping } } -// Update camera for FPS behaviour -static void UpdateCameraFPS(Camera *camera) +// Update camera +static void UpdateCameraAngle(Master* g) { const Vector3 up = (Vector3){ 0.0f, 1.0f, 0.0f }; const Vector3 targetOffset = (Vector3){ 0.0f, 0.0f, -1.0f }; // Left and right - Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, lookRotation.x); + Vector3 yaw = Vector3RotateByAxisAngle(targetOffset, up, g->player.lookRotation.x); // Clamp view up float maxAngleUp = Vector3Angle(up, yaw); maxAngleUp -= 0.001f; // Avoid numerical errors - if ( -(lookRotation.y) > maxAngleUp) { lookRotation.y = -maxAngleUp; } + if ( -(g->player.lookRotation.y) > maxAngleUp) { g->player.lookRotation.y = -maxAngleUp; } // Clamp view down float maxAngleDown = Vector3Angle(Vector3Negate(up), yaw); maxAngleDown *= -1.0f; // Downwards angle is negative maxAngleDown += 0.001f; // Avoid numerical errors - if ( -(lookRotation.y) < maxAngleDown) { lookRotation.y = -maxAngleDown; } + if ( -(g->player.lookRotation.y) < maxAngleDown) { g->player.lookRotation.y = -maxAngleDown; } // Up and down Vector3 right = Vector3Normalize(Vector3CrossProduct(yaw, up)); // Rotate view vector around right axis - float pitchAngle = -lookRotation.y - lean.y; - pitchAngle = Clamp(pitchAngle, -PI/2 + 0.0001f, PI/2 - 0.0001f); // Clamp angle so it doesn't go past straight up or straight down + float pitchAngle = -g->player.lookRotation.y - + g->player.lean.y; + pitchAngle = Clamp(pitchAngle, -PI / 2 + 0.0001f, PI / 2 - 0.0001f); // Clamp angle so it doesn't go past straight up or straight down Vector3 pitch = Vector3RotateByAxisAngle(yaw, right, pitchAngle); // Head animation // Rotate up direction around forward axis - float headSin = sin(headTimer*PI); - float headCos = cos(headTimer*PI); - const float stepRotation = 0.01f; - camera->up = Vector3RotateByAxisAngle(up, pitch, headSin*stepRotation + lean.x); + float headSin = sin(g->player.headTimer*PI); + float headCos = cos(g->player.headTimer*PI); + const float stepRotation = 0.005f; + g->player.camera.up = Vector3RotateByAxisAngle(up, pitch, headSin*stepRotation + g->player.lean.x); // Camera BOB - const float bobSide = 0.1f; - const float bobUp = 0.15f; + const float bobSide = 0.01f; + const float bobUp = 0.01f; 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); + g->player.camera.position = Vector3Add(g->player.camera.position, Vector3Scale(bobbing, g->player.walkLerp)); + g->player.camera.target = Vector3Add(g->player.camera.position, pitch); } // Draw game level -static void DrawLevel(void) +static void DrawLevel(Model mdlTile) { - const int floorExtent = 25; - const float tileSize = 5.0f; + const int floorExtent = FLOOR_EXTENT; + const float tileSize = TILE_SIZE; const Color tileColor1 = (Color){ 150, 200, 200, 255 }; // Floor tiles @@ -294,6 +576,7 @@ static void DrawLevel(void) { for (int x = -floorExtent; x < floorExtent; x++) { + /* if ((y & 1) && (x & 1)) { DrawPlane((Vector3){ x*tileSize, 0.0f, y*tileSize}, (Vector2){ tileSize, tileSize }, tileColor1); @@ -302,9 +585,15 @@ static void DrawLevel(void) { DrawPlane((Vector3){ x*tileSize, 0.0f, y*tileSize}, (Vector2){ tileSize, tileSize }, LIGHTGRAY); } + */ + Vector3 pos = (Vector3){ x*tileSize, 0.0f, y*tileSize }; + // mdlTile must be accessible here: make it global/static or pass it in + DrawModel(mdlTile, pos, 1.0f, WHITE); + } } + /* const Vector3 towerSize = (Vector3){ 16.0f, 32.0f, 16.0f }; const Color towerColor = (Color){ 150, 200, 200, 255 }; @@ -326,4 +615,25 @@ static void DrawLevel(void) // Red sun DrawSphere((Vector3){ 300.0f, 300.0f, 0.0f }, 100.0f, (Color){ 255, 0, 0, 255 }); + */ +} + +//fix mouse +static void CenterMouseAndFlush() +{ + SetMousePosition(GetRenderWidth()/2, GetRenderHeight()/2); + (void)GetMouseDelta(); +} + +//Random number gen +int Random(int x) +{ + int r = (rand() % x) + 1; // 1-40 + return r; +} + +float square(float num) +{ + float out = num * num; + return out; } \ No newline at end of file