game.c (11545B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include "../lib/raylib.h" 6 #include "../include/entity.h" 7 #include "../include/game.h" 8 #include "../include/tile.h" 9 #include "../include/util.h" 10 #include "../include/player.h" 11 #include "../include/const.h" 12 #include "../include/level.h" 13 14 game_t *game_create(void) { 15 game_t *game = malloc(sizeof(game_t)); 16 *game = (game_t) { 17 .state = STATE_GAME, 18 .level = NULL, 19 .quit = false, 20 .defeat = false, 21 .victory = false, 22 .menu = menu_create(), 23 .player = NULL, 24 .tiles = NULL, 25 .tiles_len = 0, 26 .entities = NULL, 27 .entities_len = 0, 28 .effects = NULL, 29 .effects_len = 0, 30 .assets.tiles = texture_load("assets/tiles.png", SCALE), 31 .assets.entities = texture_load("assets/entities.png", SCALE), 32 .assets.font = texture_load("assets/font.png", SCALE - 1), 33 .assets.images = texture_load("assets/images.png", SCALE), 34 .assets.background = texture_load("assets/background.png", SCALE), 35 .assets.track = LoadSound("assets/song.wav"), 36 .assets.win = LoadSound("assets/win.wav"), 37 .assets.lose = LoadSound("assets/lose.wav"), 38 .assets.locked = LoadSound("assets/locked.wav"), 39 .camera = (Camera2D) { 40 .offset = (pos_t) { 0.0, 0.0 }, 41 .zoom = 1, 42 }, 43 .xp = 0, 44 .sceen_timer = 0, 45 .door = NULL, 46 .overlay = LoadRenderTexture(WINDOW_WIDTH, WINDOW_HEIGHT), 47 .is_muted = false, 48 }; 49 level_load(game, LEVEL_1); 50 SetSoundVolume(game->assets.track, GAME_MUSIC_VOLUME); 51 SetSoundVolume(game->assets.win, GAME_SOUND_VOLUME); 52 SetSoundVolume(game->assets.lose, GAME_SOUND_VOLUME); 53 SetSoundVolume(game->assets.locked, GAME_SOUND_VOLUME); 54 return game; 55 } 56 57 void game_update(game_t *game) { 58 bool do_toggle_mute = false; 59 if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) { 60 pos_t mouse_pos = GetMousePosition(); 61 rect_t mouse_rect = { 62 .x = mouse_pos.x, 63 .y = mouse_pos.y, 64 .width = 1, 65 .height = 1, 66 }; 67 rect_t mute_button_rect = { 68 .x = TILE_WIDTH / 2.0, 69 .y = WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0, 70 .width = TILE_WIDTH, 71 .height = TILE_HEIGHT, 72 }; 73 rect_t pause_button_rect = { 74 .x = WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0, 75 .y = WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0, 76 .width = TILE_WIDTH, 77 .height = TILE_HEIGHT, 78 }; 79 if (rect_collide(mouse_rect, mute_button_rect)) { 80 do_toggle_mute = true; 81 } 82 if (!game->victory && !game->defeat) { 83 if (rect_collide(mouse_rect, pause_button_rect)) { 84 switch (game->state) { 85 case STATE_GAME: 86 game->state = STATE_MENU; 87 break; 88 case STATE_MENU: 89 game->state = STATE_GAME; 90 break; 91 } 92 } 93 } 94 } 95 if (IsKeyPressed(KEY_M)) { 96 do_toggle_mute = true; 97 } 98 if (do_toggle_mute) { 99 game->is_muted = !game->is_muted; 100 if (game->is_muted) { 101 SetSoundVolume(game->assets.track, 0.0f); 102 SetSoundVolume(game->assets.win, 0.0f); 103 SetSoundVolume(game->assets.lose, 0.0f); 104 SetSoundVolume(game->assets.locked, 0.0f); 105 } 106 else { 107 SetSoundVolume(game->assets.track, GAME_MUSIC_VOLUME); 108 SetSoundVolume(game->assets.win, GAME_SOUND_VOLUME); 109 SetSoundVolume(game->assets.lose, GAME_SOUND_VOLUME); 110 SetSoundVolume(game->assets.locked, GAME_SOUND_VOLUME); 111 } 112 } 113 if (!IsSoundPlaying(game->assets.track) && !game->victory && !game->defeat) { 114 PlaySound(game->assets.track); 115 } 116 switch (game->state) { 117 case STATE_MENU: { 118 menu_update(game->menu, game); 119 break; 120 } 121 case STATE_GAME: { 122 if (!game->victory && !game->defeat) { 123 if (IsKeyPressed(KEY_ESCAPE)) { 124 game->state = STATE_MENU; 125 game->menu->idx = 0; 126 } 127 } 128 if (game->level != NULL) { 129 // defeat 130 if (game->defeat) { 131 if (game->sceen_timer == 0) { 132 StopSound(game->assets.track); 133 } 134 if (game->sceen_timer == 20) { 135 PlaySound(game->assets.lose); 136 } 137 if (game->sceen_timer == GAME_SCEEN_TIMER) { 138 level_e level = game->level->type; 139 int max_health = game->player->max_health; 140 max_health -= 2; 141 if (max_health <= 0) { 142 level = LEVEL_1; 143 max_health = PLAYER_MAX_HEALTH; 144 } 145 level_unload(game); 146 level_load(game, level); 147 game->player->max_health = max_health; 148 game->player->health = max_health; 149 game->defeat = false; 150 game->xp = 0; 151 game->sceen_timer = 0; 152 } 153 else { 154 game->sceen_timer++; 155 } 156 } 157 // victory 158 if (game->victory) { 159 if (game->sceen_timer == 0) { 160 StopSound(game->assets.track); 161 } 162 if (game->sceen_timer == 20) { 163 PlaySound(game->assets.win); 164 } 165 if (game->sceen_timer == GAME_SCEEN_TIMER) { 166 if (game->level->type < LEVELS) { 167 level_e level = game->level->type; 168 int max_health = game->player->max_health; 169 level++; 170 level_unload(game); 171 level_load(game, level); 172 game->player->max_health = max_health; 173 game->player->health = max_health; 174 } 175 game->victory = false; 176 game->sceen_timer = 0; 177 } 178 else { 179 if (game->sceen_timer == 125) { 180 game->door->is_locked = true; 181 } 182 game->sceen_timer++; 183 } 184 } 185 if (!game->victory && !game->defeat) { 186 player_update(game->player, game); 187 } 188 for (int i = 0; i < game->tiles_len; i++) { 189 tile_update(game->tiles[i], game); 190 } 191 for (int i = 0; i < game->entities_len; i++) { 192 int len = game->entities_len; 193 entity_update(&game->entities[i], game); 194 // check if entity was removed 195 if (game->entities_len < len) { 196 i--; 197 } 198 } 199 for (int i = 0; i < game->effects_len; i++) { 200 int len = game->effects_len; 201 effect_update(game->effects[i], game); 202 // check if enemy was removed 203 if (game->effects_len < len) { 204 i--; 205 } 206 } 207 pos_t camera_pos = (pos_t) { 208 .x = WINDOW_WIDTH / 2.0 - game->player->pos.x - PLAYER_WIDTH / 2.0, 209 .y = WINDOW_HEIGHT / 2.0 - game->player->pos.y, 210 }; 211 if (camera_pos.x > 0.0) { 212 camera_pos.x = 0.0; 213 } 214 if (camera_pos.x + TILE_WIDTH * game->level->width < WINDOW_WIDTH) { 215 camera_pos.x = WINDOW_WIDTH - TILE_WIDTH * game->level->width; 216 } 217 if (camera_pos.y > 0.0) { 218 camera_pos.y = 0.0; 219 } 220 if (camera_pos.y + TILE_HEIGHT * game->level->height < WINDOW_HEIGHT) { 221 camera_pos.y = WINDOW_HEIGHT - TILE_HEIGHT * game->level->height; 222 } 223 game->camera.offset = pos_snap(camera_pos); 224 } 225 break; 226 } 227 } 228 } 229 230 void game_draw(game_t *game) { 231 // render overlay 232 BeginTextureMode(game->overlay); 233 ClearBackground(BLACK); 234 DrawRectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, BLACK); 235 BeginBlendMode(BLEND_SUBTRACT_COLORS); 236 int radius = WINDOW_WIDTH; 237 radius -= radius / 80.0 * game->sceen_timer; 238 if (radius < PLAYER_HEIGHT) { 239 radius = PLAYER_HEIGHT; 240 } 241 DrawCircle(game->player->pos.x + PLAYER_WIDTH / 2.0, WINDOW_HEIGHT - (game->player->pos.y + PLAYER_HEIGHT / 2.0), radius, WHITE); 242 EndBlendMode(); 243 EndTextureMode(); 244 // render sceen 245 BeginDrawing(); 246 ClearBackground((Color) { 5, 5, 5, 255 }); 247 if (game->level != LEVEL_NULL) { 248 BeginMode2D(game->camera); 249 for (int i = 0; i < game->tiles_len; i++) { 250 tile_draw(game->tiles[i], game); 251 } 252 for (int i = 0; i < game->entities_len; i++) { 253 entity_t *entity = &game->entities[i]; 254 if (entity->type == ENTITY_GATE || entity->type == ENTITY_DOOR) { 255 entity_draw(entity, game); 256 } 257 } 258 for (int i = 0; i < game->entities_len; i++) { 259 entity_t *entity = &game->entities[i]; 260 if (entity->type != ENTITY_GATE && entity->type != ENTITY_DOOR) { 261 entity_draw(entity, game); 262 } 263 } 264 if (game->sceen_timer < 100) { 265 player_draw(game->player, game); 266 } 267 for (int i = 0; i < game->effects_len; i++) { 268 effect_draw(game->effects[i], game); 269 } 270 // draw overlay 271 DrawTexture(game->overlay.texture, 0, 0, WHITE); 272 EndMode2D(); 273 // draw interface 274 int i = 0; 275 for (i = 0; i < game->player->health / 2; i++) { 276 DrawTextureRec(game->assets.tiles, texture_rect(0, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0 + i * (TILE_WIDTH + TILE_WIDTH / 4.0), TILE_WIDTH / 2.0 }, WHITE); 277 } 278 if (game->player->health % 2 != 0) { 279 DrawTextureRec(game->assets.tiles, texture_rect(1, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0 + i * (TILE_WIDTH + TILE_WIDTH / 4.0), TILE_WIDTH / 2.0 }, WHITE); 280 i++; 281 } 282 for (; i < game->player->max_health / 2; i++) { 283 DrawTextureRec(game->assets.tiles, texture_rect(2, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0 + i * (TILE_WIDTH + TILE_WIDTH / 4.0), TILE_WIDTH / 2.0 }, WHITE); 284 } 285 char xp_text[10]; 286 snprintf(xp_text, 10, "%dXP", game->xp); 287 pos_t xp_pos = (pos_t) { 288 .x = WINDOW_WIDTH - TILE_WIDTH / 2.0, 289 .y = TILE_WIDTH / 1.5, 290 }; 291 text_draw(xp_pos, xp_text, TEXT_ALIGNMENT_RIGHT, game); 292 char level_text[10]; 293 snprintf(level_text, 10, "L%d", game->level->type); 294 pos_t level_pos = (pos_t) { 295 .x = WINDOW_WIDTH - TILE_WIDTH / 2.0, 296 .y = TILE_WIDTH / 1.5 + 25, 297 }; 298 text_draw(level_pos, level_text, TEXT_ALIGNMENT_RIGHT, game); 299 } 300 if (game->state == STATE_MENU) { 301 menu_draw(game->menu, game); 302 } 303 if (game->is_muted) { 304 DrawTextureRec(game->assets.tiles, texture_rect(5, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE); 305 } 306 else { 307 DrawTextureRec(game->assets.tiles, texture_rect(4, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE); 308 } 309 if (game->state == STATE_GAME) { 310 if (game->victory || game->defeat) { 311 DrawTextureRec(game->assets.tiles, texture_rect(8, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE); 312 } 313 else { 314 DrawTextureRec(game->assets.tiles, texture_rect(6, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE); 315 } 316 } 317 else { 318 DrawTextureRec(game->assets.tiles, texture_rect(7, 1, TILE_WIDTH, TILE_HEIGHT), (pos_t) { WINDOW_WIDTH - TILE_WIDTH - TILE_WIDTH / 2.0, WINDOW_HEIGHT - TILE_HEIGHT - TILE_HEIGHT / 2.0 }, WHITE); 319 } 320 EndDrawing(); 321 } 322 323 void game_free(game_t *game) { 324 menu_free(game->menu); 325 if (game->level != LEVEL_NULL) { 326 level_unload(game); 327 } 328 UnloadTexture(game->assets.tiles); 329 UnloadTexture(game->assets.entities); 330 UnloadTexture(game->assets.font); 331 UnloadTexture(game->assets.images); 332 UnloadTexture(game->assets.background); 333 UnloadSound(game->assets.track); 334 UnloadSound(game->assets.win); 335 UnloadSound(game->assets.lose); 336 UnloadSound(game->assets.locked); 337 UnloadRenderTexture(game->overlay); 338 free(game); 339 }