summaryrefslogtreecommitdiff
path: root/src/game_v0.c
diff options
context:
space:
mode:
authortalha <->2024-08-12 19:39:04 +0500
committertalha <->2024-08-12 19:39:04 +0500
commit0cb9fa1c023033c250fd0bf33c2cee49fc85f178 (patch)
tree73a5e945c55998b9dc7acb0eba5a5f40c8252ee6 /src/game_v0.c
Added files to git tracking
Diffstat (limited to 'src/game_v0.c')
-rw-r--r--src/game_v0.c512
1 files changed, 512 insertions, 0 deletions
diff --git a/src/game_v0.c b/src/game_v0.c
new file mode 100644
index 0000000..62141f6
--- /dev/null
+++ b/src/game_v0.c
@@ -0,0 +1,512 @@
+#include "raylib.h"
+#include "raymath.h"
+
+#if defined(PLATFORM_WEB)
+ #include <emscripten/emscripten.h>
+#endif
+
+typedef enum {
+ O = 0, // nothing
+ //P = 1, // player
+ t = 2, // tree
+ T = 3, // troll area
+ B = 4, // bandit area
+ T_B = 5, // troll base
+ B_B = 6, // bandit base
+ //G = 7, // gate (exit)
+} MapSymbol;
+
+typedef enum {
+ AA_IDLE = 0,
+ AA_CHARGE = 1,
+ AA_ATTACK = 2,
+} AttackAnimState;
+
+typedef enum {
+ T_IDLE = 0,
+ T_FOLLOW = 1,
+ T_AGGRO = 2,
+} TrollState;
+
+typedef enum {
+ HA_IDLE = 0,
+ HA_PLAY = 1,
+} HitAnimState;
+
+typedef struct ScuffString {
+ char *buffer;
+ int len;
+ int capacity;
+} String;
+
+typedef struct State {
+ // how much scaling to apply from original asset resolution
+ float render_scale;
+ // game positions
+ bool is_player_hit;
+ Vector2 pixels_per_gridbox;
+ Vector2 mouse_position;
+ Vector2 player_position;
+ Color player_tint;
+ // @note: normally when we place a texture, the coordinates
+ // are the top left coordinates. This will cause a disconnect
+ // when moving the player with a point and click motion.
+ // To fix that we calculate a new position so the player_coordinates
+ // are in the center. This will make it so when the player clicks on the
+ // ground somewhere, the character sprite will be properly centered on that point.
+ Rectangle player_render_rect;
+ Vector2 player_position_target;
+
+ Vector2 bandit_position;
+ // troll state
+ int troll_state;
+ float troll_move_delta;
+ Vector2 troll_position;
+ Vector2 troll_last_player_position;
+ Vector2 troll_move_dir;
+ Vector2 troll_position_target;
+ Rectangle troll_render_rect;
+ Color troll_tint_base;
+ Color troll_tint;
+ // - troll attack
+ bool troll_anim_attack_play;
+ int troll_attack_anime_state;
+ double t_troll_charge_anim_start;
+ float t_troll_charge_anim_duration;
+ float t_troll_anim_freq;
+ float troll_attack_offset_max;
+ float t_troll_attack_anim_start;
+ float t_troll_attack_anim_duration;
+
+ // player movement
+ bool is_player_move;
+ Vector2 player_move_dir;
+ // @todo
+ // direction player is being hit from, incorporate that into the gameplay code
+ // For now, just update the player_move_dir to the player_hit_dir
+ // Vector2 player_hit_dir;
+ float player_move_delta; // amount player will move
+ // target position player will move to
+ // 1. the player can move intentionally, in which case carry forward from player position target
+ // 2. the player can move from feedback of being hit, NOT IMPLEMENTED YET
+ int player_hit_anim_state;
+ float player_hit_anim_speed;
+ float t_player_hit_anim_duration;
+ float t_player_hit_anim_start;
+ Vector2 player_move_target;
+
+ // game sprites
+ Texture2D *grass_sprite;
+ Texture2D *player_sprite;
+
+ Texture2D *troll_sprite;
+ Texture2D *troll_weapon_sprite;
+ Texture2D *bandit_sprite;
+ Texture2D *bandit_weapon_sprite;
+
+ Texture2D *troll_area_floor_sprite;
+ Texture2D *bandit_area_floor_sprite;
+
+ Texture2D *troll_base_sprite;
+ Texture2D *bandit_base_sprite;
+
+ String *action_log;
+} State;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+const int screenWidth = 1280;
+const int screenHeight = 1024;
+State mega_state = {};
+// layer ground
+int floor_grid_map[8][8] = {{O, O, O, O, O, O, O, O},
+ {O, O, O, O, T, T, T, T},
+ {B, B, B, B, T, T, T, T},
+ {B, B, B, B, T, T, T, T},
+ {B, B, B, B, T, T, T, T},
+ {B, B, B, B, T, T, T, T},
+ {B, B, B, B, T, T, T, T},
+ {B, B, B, B, T, T, T, T}};
+// vegetation grid
+int floor_cover_grid_map[8][8] = {{O, O, O, O, O, O, O, O},
+ {O, O, O, O, O, O, O, O},
+ {O, O, O, O, O, O, O, O},
+ {O, O, O, O, O, O, O, O},
+ {O, O, O, O, O, O, O, T_B},
+ {O, B_B, O, O, O, O, O, O},
+ {O, O, O, O, O, O, O, O},
+ {O, O, O, O, O, O, O, O}};
+Vector2 grid_dims = {8, 8};
+//----------------------------------------------------------------------------------
+// Module functions declaration
+//----------------------------------------------------------------------------------
+void UpdateDrawFrame(); // Update and Draw one frame
+
+int main(void)
+{
+ InitWindow(screenWidth, screenHeight, "raylib browser example");
+ SetTargetFPS(60);
+ Texture2D grass_sprite = LoadTexture("./assets/dungeon/floor/grass/grass_flowers_blue_1_new.png");
+ Texture2D player_sprite = LoadTexture("./assets/player/base/human_male.png");
+ Texture2D troll_sprite = LoadTexture("./assets/monster/hill_giant_old.png");
+ Texture2D bandit_sprite = LoadTexture("./assets/monster/unique/maurice_new.png");
+ Texture2D troll_area_floor_sprite = LoadTexture("./assets/dungeon/floor/dirt_northeast_new.png");
+ Texture2D bandit_area_floor_sprite = LoadTexture("./assets/dungeon/floor/dirt_east_new.png");
+ Texture2D bandit_base_sprite = LoadTexture("./assets/dungeon/floor/hive_3.png");
+ Texture2D troll_base_sprite = LoadTexture("./assets/dungeon/floor/dirt_2_old.png");
+ Texture2D troll_weapon_sprite = LoadTexture("./assets/item/weapon/club_old.png");
+
+ mega_state.render_scale = 2.0f;
+ mega_state.grass_sprite = &grass_sprite;
+ mega_state.player_sprite = &player_sprite;
+ mega_state.troll_sprite = &troll_sprite;
+ mega_state.bandit_sprite = &bandit_sprite;
+ mega_state.troll_area_floor_sprite = &troll_area_floor_sprite;
+ mega_state.bandit_area_floor_sprite = &bandit_area_floor_sprite;
+ mega_state.bandit_base_sprite = &bandit_base_sprite;
+ mega_state.troll_base_sprite = &troll_base_sprite;
+ mega_state.troll_weapon_sprite = &troll_weapon_sprite;
+ mega_state.player_position = (Vector2){50.0f, 50.0f};
+ mega_state.player_hit_anim_speed = 50.0f; // pixels per second;
+ mega_state.t_player_hit_anim_duration = 0.2f;
+ mega_state.player_render_rect = (Rectangle){.x=0,.y=0,.width=player_sprite.width,.height=player_sprite.height*mega_state.render_scale};
+ mega_state.player_move_delta = 5.0f;
+ mega_state.pixels_per_gridbox = (Vector2){screenWidth/grid_dims.x, screenHeight/grid_dims.y};
+ mega_state.player_tint = (Color){255, 255, 255, 255};
+ mega_state.troll_state = T_IDLE;
+
+ mega_state.bandit_position = (Vector2){64.0f, 800.0f};
+ mega_state.troll_position = (Vector2){1024.0f, 600.0f};
+ mega_state.troll_move_delta = 2.0f;
+ mega_state.t_troll_charge_anim_duration = 1.0f;
+ mega_state.troll_tint_base = (Color){255, 255, 255, 255};
+ mega_state.troll_tint = mega_state.troll_tint_base;
+ mega_state.t_troll_attack_anim_duration = 0.4f;
+ mega_state.troll_attack_offset_max = 100.0f;
+ mega_state.troll_render_rect = (Rectangle){.x=0,.y=0,.width=troll_sprite.width*mega_state.render_scale,.height=troll_sprite.height*mega_state.render_scale};
+
+ char *str_buffer = (char*)MemAlloc(512*sizeof(char));
+ mega_state.action_log = &(String){.buffer=str_buffer, .capacity=512, .len=0};
+
+ #if defined(PLATFORM_WEB)
+ emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
+ #else
+ SetTargetFPS(60);
+
+ while(!WindowShouldClose())
+ {
+ UpdateDrawFrame();
+ }
+ #endif
+
+ CloseWindow();
+
+ return 0;
+}
+
+void DrawMapFloorTiles(float scale)
+{
+ // @note: testing this, might need lighting
+ Color BlackTint = {128,128,128,255};
+ Texture2D grass = *mega_state.grass_sprite;
+ float winc = (float)grass.width * scale;
+ float hinc = (float)grass.height * scale;
+ Vector2 grid_pos = {0, 0};
+ for (int ypos=0; ypos<screenHeight; ypos+=hinc)
+ {
+ grid_pos.y = ((float)ypos) / ((float)mega_state.pixels_per_gridbox.y);
+ for (int xpos=0; xpos<screenWidth; xpos+=winc)
+ {
+ grid_pos.x = ((float)xpos) / ((float)mega_state.pixels_per_gridbox.x);
+ Vector2 pixel_pos = {xpos, ypos};
+ int grid_ele = floor_grid_map[(int)grid_pos.y][(int)grid_pos.x];
+ Texture2D render_tex;
+ switch (grid_ele) {
+ case (O):
+ {
+ render_tex = *mega_state.grass_sprite;
+ } break;
+ case (B):
+ {
+ render_tex = *mega_state.bandit_area_floor_sprite;
+ } break;
+ case (T):
+ {
+ render_tex = *mega_state.troll_area_floor_sprite;
+ } break;
+ default:
+ {
+ } break;
+ }
+ DrawTextureEx(render_tex, pixel_pos, 0, scale, BlackTint);
+ }
+ }
+}
+
+void DrawFloorCoverTiles(float scale)
+{
+ // @note: testing this, might need lighting
+ Color BlackTint = {128,128,128,255};
+ Texture2D null_tex = *mega_state.player_sprite;
+ float winc = (float)null_tex.width * scale;
+ float hinc = (float)null_tex.height * scale;
+
+ Vector2 grid_pos = {0, 0};
+ for (int ypos=0; ypos<screenHeight; ypos+=hinc)
+ {
+ grid_pos.y = ((float)ypos) / ((float)mega_state.pixels_per_gridbox.y);
+ for (int xpos=0; xpos<screenWidth; xpos+=winc)
+ {
+ grid_pos.x = ((float)xpos) / ((float)mega_state.pixels_per_gridbox.x);
+ Vector2 pixel_pos = {xpos, ypos};
+ int grid_ele = floor_cover_grid_map[(int)grid_pos.y][(int)grid_pos.x];
+ Texture2D render_tex;
+ switch (grid_ele) {
+ case (B_B):
+ {
+ render_tex = *mega_state.bandit_base_sprite;
+ } break;
+ case (T_B):
+ {
+ render_tex = *mega_state.troll_base_sprite;
+ } break;
+ default:
+ {
+ render_tex = null_tex;
+ } continue;
+ }
+ DrawTextureEx(render_tex, pixel_pos, 0, scale, BlackTint);
+ }
+ }
+}
+
+Vector2 GetSpriteCenterPosition(Texture2D sprite, Vector2 position, float render_scale)
+{
+ float centered_x = position.x - ((float)sprite.width)*render_scale/2.0f;
+ float centered_y = position.y - ((float)sprite.height)*render_scale/2.0f;
+
+ return (Vector2){.x = centered_x, .y = centered_y};
+}
+
+Vector2 GetRenderCenterFromTL(Rectangle render_rect, Vector2 position)
+{
+ float centered_x = position.x - ((float)render_rect.width)/2.0f;
+ float centered_y = position.y - ((float)render_rect.height)/2.0f;
+
+ return (Vector2){.x = centered_x, .y = centered_y};
+}
+
+void DrawCharacters(float scale)
+{
+ Rectangle src_rect, dest_rect;
+ // draw Troll
+ // - troll weapon
+ Vector2 troll_weapon_centered = GetSpriteCenterPosition(*mega_state.troll_weapon_sprite, mega_state.troll_position, 1.0f);
+ // move to left hand
+ troll_weapon_centered.x -= mega_state.troll_sprite->width;
+ src_rect = (Rectangle){.x=0, .y=0, .width=-mega_state.troll_weapon_sprite->width, .height=mega_state.troll_weapon_sprite->height};
+ dest_rect = (Rectangle){.x=troll_weapon_centered.x, .y=troll_weapon_centered.y,
+ .width=0.5f*scale*mega_state.troll_weapon_sprite->width,
+ .height=0.5f*scale*mega_state.troll_weapon_sprite->height};
+ DrawTexturePro(*mega_state.troll_weapon_sprite, src_rect, dest_rect,
+ (Vector2){0,0}, 0, RAYWHITE);
+ // - troll sprite
+ DrawTextureEx(*mega_state.troll_sprite, (Vector2){mega_state.troll_render_rect.x, mega_state.troll_render_rect.y}, 0, scale, mega_state.troll_tint);
+ // draw collision box
+ DrawRectangleLines(mega_state.troll_render_rect.x, mega_state.troll_render_rect.y, mega_state.troll_render_rect.width, mega_state.troll_render_rect.height, RED);
+
+ // draw Bandit
+ Vector2 bandit_center = GetSpriteCenterPosition(*mega_state.bandit_sprite, mega_state.bandit_position, scale);
+ src_rect = (Rectangle){.x=0, .y=0, .width=-mega_state.bandit_sprite->width, .height=mega_state.bandit_sprite->height};
+ dest_rect = (Rectangle){.x=bandit_center.x, .y=bandit_center.y,
+ .width=scale*mega_state.bandit_sprite->width,
+ .height=scale*mega_state.bandit_sprite->height};
+ DrawTexturePro(*mega_state.bandit_sprite, src_rect, dest_rect,
+ (Vector2){0,0}, 0, (Color){255, 128, 128, 255});
+ // draw player
+ Vector2 player_center = GetSpriteCenterPosition(*mega_state.player_sprite, mega_state.player_position, scale);
+ DrawTextureEx(*mega_state.player_sprite, player_center, 0, scale, mega_state.player_tint);
+ //DrawTextureEx(*mega_state.player_sprite, (Vector2){mega_state.player_render_rect.x, mega_state.player_render_rect.y}, 0, scale, RAYWHITE);
+ DrawRectangleLines(mega_state.player_render_rect.x, mega_state.player_render_rect.y, mega_state.player_render_rect.width, mega_state.player_render_rect.height, RED);
+}
+
+void UpdateDrawFrame(void)
+{
+ BeginDrawing();
+ {
+ // INPUT
+ mega_state.mouse_position = GetMousePosition();
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && mega_state.player_hit_anim_state != HA_PLAY)
+ {
+ mega_state.is_player_move = true;
+ mega_state.player_position_target = mega_state.mouse_position;
+ mega_state.player_move_dir = Vector2Normalize(Vector2Subtract(mega_state.player_position_target, mega_state.player_position));
+ }
+ if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT))
+ {
+ // @debug: cleaning up troll collision state
+ mega_state.troll_attack_anime_state = AA_IDLE;
+ mega_state.troll_tint = WHITE;
+ mega_state.is_player_hit = false;
+ }
+
+ // PROCESSING
+ if (mega_state.player_hit_anim_state == HA_PLAY)
+ {
+ float anim_length = GetTime() - mega_state.t_player_hit_anim_start;
+ float ft = GetFrameTime();
+ float pixel_per_second_per_ft = ft*mega_state.player_hit_anim_speed/mega_state.t_player_hit_anim_duration;
+ mega_state.player_position = Vector2Add(mega_state.player_position, Vector2Scale(mega_state.player_move_dir, pixel_per_second_per_ft));
+ mega_state.player_tint = (Color){255, 128, 128, 255};
+ if (anim_length >= mega_state.t_player_hit_anim_duration)
+ {
+ mega_state.player_hit_anim_state = HA_IDLE;
+ mega_state.player_tint = (Color){255, 255, 255, 255};
+ }
+ }
+ if (mega_state.is_player_move)
+ {
+ mega_state.player_position = Vector2Add(mega_state.player_position, Vector2Scale(mega_state.player_move_dir, mega_state.player_move_delta));
+ if (Vector2Distance(mega_state.player_position, mega_state.player_position_target) <= 5.0f)
+ {
+ mega_state.is_player_move = false;
+ }
+ }
+ // calculate center positions
+ Vector2 player_centered = GetRenderCenterFromTL(mega_state.player_render_rect, mega_state.player_position);
+ mega_state.player_render_rect.x = player_centered.x;
+ mega_state.player_render_rect.y = player_centered.y;
+
+ // process enemies detecting the player
+ // troll
+ // get player location on map
+ // map_world_to_grid
+ Vector2 grid_pos = Vector2Divide(Vector2Multiply(mega_state.player_position, grid_dims), (Vector2){screenWidth, screenHeight});
+ int tile_at_player = floor_grid_map[(int)grid_pos.y][(int)grid_pos.x];
+ bool in_troll_area = true;
+ bool troll_persue_player = true;
+ if (tile_at_player != T)
+ {
+ in_troll_area = false;
+ if (mega_state.troll_state != T_AGGRO)
+ {
+ mega_state.troll_attack_anime_state = AA_IDLE;
+ troll_persue_player = false;
+ }
+ }
+
+ float player_troll_dist = Vector2Distance(mega_state.player_position, mega_state.troll_position);
+ bool troll_detect = false;
+ bool troll_attack_start = false;
+ float slow_multiplier = mega_state.troll_attack_anime_state == AA_CHARGE ? 0.2f : 1.0f;
+ if (player_troll_dist < 200 && troll_persue_player)
+ {
+ troll_detect = true;
+ mega_state.troll_state = T_FOLLOW;
+ if (player_troll_dist < 80 && mega_state.troll_attack_anime_state == AA_IDLE)
+ {
+ troll_attack_start = true;
+ }
+ }
+ if (troll_detect && mega_state.troll_attack_anime_state != AA_ATTACK)
+ {
+ mega_state.troll_last_player_position = mega_state.player_position;
+ mega_state.troll_position_target = mega_state.troll_last_player_position;
+ mega_state.troll_move_dir = Vector2Normalize(Vector2Subtract(mega_state.troll_position_target, mega_state.troll_position));
+ if (player_troll_dist > 10.0f)
+ {
+ // @note: this actually might not even be needed
+ // move only if both are more than 10pixels apart.
+ // it becomes jarring other wise
+ mega_state.troll_position = Vector2Add(mega_state.troll_position, Vector2Scale(mega_state.troll_move_dir, slow_multiplier*mega_state.troll_move_delta));
+ }
+ }
+ Vector2 troll_centered = GetSpriteCenterPosition(*mega_state.troll_sprite, mega_state.troll_position, mega_state.render_scale);
+ mega_state.troll_render_rect.x = troll_centered.x;
+ mega_state.troll_render_rect.y = troll_centered.y;
+ if (troll_attack_start)
+ {
+ // start attack animation
+ mega_state.troll_anim_attack_play = true;
+ mega_state.t_troll_charge_anim_start = GetTime();
+ mega_state.troll_attack_anime_state = AA_CHARGE;
+ }
+ float charge_time = 0.0f;
+ float charge_color_delta = 0.0f;
+ if (mega_state.troll_attack_anime_state == AA_CHARGE)
+ {
+ // get color based on time
+ float charge_progress = (GetTime() - mega_state.t_troll_charge_anim_start) / mega_state.t_troll_charge_anim_duration;
+ mega_state.troll_tint.r = Clamp(mega_state.troll_tint_base.r - (charge_progress*mega_state.troll_tint_base.r), 0, 255);
+ if (charge_progress >= 1.0f)
+ {
+ mega_state.troll_attack_anime_state = AA_ATTACK;
+ mega_state.t_troll_attack_anim_start = GetTime();
+ }
+ }
+ else if (mega_state.troll_attack_anime_state == AA_ATTACK)
+ {
+ // maximum distance to attack jump in
+ // mega_state.troll_attack_offset_max = 10.0f;
+ // mega_state.troll_attack_anim_duration = 1.0f;
+ float anim_length = GetTime() - mega_state.t_troll_attack_anim_start;
+ float ft = GetFrameTime();
+ float pixel_per_second_per_ft = ft*mega_state.troll_attack_offset_max/mega_state.t_troll_attack_anim_duration;
+ mega_state.troll_position = Vector2Add(mega_state.troll_position, Vector2Scale(mega_state.troll_move_dir, pixel_per_second_per_ft));
+ mega_state.troll_tint = (Color){255, 128, 255, 255};
+ // get troll center position and check for collision with player
+ // now check if colliding with player
+ bool is_colliding = CheckCollisionRecs(mega_state.player_render_rect, mega_state.troll_render_rect);
+ if (is_colliding)
+ {
+ mega_state.is_player_hit = true;
+ }
+ if (anim_length >= mega_state.t_troll_attack_anim_duration || is_colliding)
+ {
+ mega_state.troll_attack_anime_state = AA_IDLE;
+ mega_state.troll_tint = mega_state.troll_tint_base;
+ if (is_colliding)
+ {
+ // make player get hit
+ mega_state.player_hit_anim_state = HA_PLAY;
+ mega_state.t_player_hit_anim_start = GetTime();
+ mega_state.player_move_dir = mega_state.troll_move_dir;
+ mega_state.is_player_move = false; // disable walk check, stuff been thrown off
+ }
+ }
+ }
+
+ float player_bandit_delta = Vector2Distance(mega_state.player_position, mega_state.bandit_position);
+ bool bandit_detect = false;
+ if (player_bandit_delta < 200)
+ {
+ bandit_detect = true;
+ }
+ // RENDERING
+ ClearBackground(RAYWHITE);
+ DrawMapFloorTiles(2.0f);
+ DrawFloorCoverTiles(2.0f);
+ DrawCharacters(2.0f);
+
+ // do text rendering at the end
+ // draw mouse position for debugging
+ if (mega_state.is_player_hit)
+ {
+ DrawText("player hit", 500, 20, 20, GREEN);
+ }
+ if (troll_detect)
+ {
+ DrawText("Detecting", mega_state.troll_position.x, mega_state.troll_position.y + mega_state.troll_sprite->height + 20, 20, GREEN);
+ }
+ if (bandit_detect)
+ {
+ DrawText("Detecting", mega_state.bandit_position.x, mega_state.bandit_position.y + mega_state.bandit_sprite->height + 20, 20, GREEN);
+ }
+ DrawText(TextFormat("FPS: %d", GetFPS()), 1200, 20, 20, GREEN);
+ DrawText(TextFormat("Player Tile: %d", tile_at_player), 20, 20, 20, GREEN);
+ }
+ EndDrawing();
+}
+
+