#include "game/game.hpp" #include #include #include #include #include #include "game_state.hpp" #include "state_modify.hpp" #include "state_playing.hpp" #include "defaults/defaults.hpp" #include "character/character.hpp" #include "defaults/ui.hpp" #include "map/tile.hpp" #include "map/map.hpp" #include "inventory/weapon.hpp" #include "building/building.hpp" #include "defaults/icons.hpp" #include "inventory/inventory.hpp" #include "resource/resource_data.hpp" #include "building/research.hpp" #include "defaults/input.hpp" #include "start_screen/start_screen.hpp" #include "cursor/animated_cursor.hpp" #include "end_screen/end_screen.hpp" // Game class encapsulating SDL initialization and loop Game::Game() : running(true) { if (!SDL_Init(SDL_INIT_VIDEO)) { std::cerr << "SDL_Init Error: " << SDL_GetError() << "\n"; running = false; } Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; if (Default::is_fullscreen) { window_flags |= SDL_WINDOW_FULLSCREEN; } window = SDL_CreateWindow("Map creator", win_size.w, win_size.h, window_flags ); if (!window) { std::cout << "Fialed to create window\n"; running = false; return; } SDL_SetHint(SDL_HINT_RENDER_VSYNC, "0"); renderer = SDL_CreateRenderer( window, "opengl" ); if (!renderer) { std::cout << "Fialed to create Renderer\n"; running = false; return; } SDL_SetRenderVSync(renderer, 1); //SDL_SetRenderVSync(renderer, SDL_RENDERER_VSYNC_DISABLED); std::cout << "INIT DONE sdl\n"; lastTicks = SDL_GetTicks(); // INIT Cursor SDL_HideCursor(); cursor = input.cursor = new AnimatedCursor(); cursor->Init(renderer, "Pixel_Crawler/Entities/Characters/Body_A/Animations/Slice_Base/Slice_Up.png"); // Music audio = new Audio(); Animation::audio = audio; /* audio->RegisterSound("character.walk", "music/character.walk.wav"); audio->RegisterSound("character.hit", "music/character.hit.wav"); */ audio->RegisterSound("bird.sing", "music/bird.sing.wav"); audio->RegisterSound("menu.hover", "music/menu.hover.wav"); audio->RegisterSound("character.hae", "music/character.hae.wav"); // INIT Font Ui::init_Font(); // INIT TileSets Tile::Init(renderer); // Icons Icon::Init(renderer); Default::now = SDL_GetPerformanceCounter(); Default::last = 0; Default::delta_time = 0.0; set_State(GameState_e::STATE_PLAYING, NewGameState_e::LOAD); set_State(GameState_e::STATE_MENU_MAIN); } Game::Game(Game&&) { std::cout << "[Game] Move constructor called!" << std::endl; } Game::~Game() { audio->Quit(); Ui::delete_Font(); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); } void Game::set_State(GameState_e new_state, NewGameState_e game_state_e) { // STATE_PLAYING // START CURSOR switch (new_state) { case GameState_e::STATE_MODIFY: cursor->set_State(CursorState::NORMAL); break; case GameState_e::STATE_MENU_MAIN: cursor->set_State(CursorState::ANIMATED); break; case GameState_e::STATE_PLAYING: cursor->set_State(CursorState::HIDDEN); break; } // END CURSOR state_changed = true; if (new_state == GameState_e::STATE_PLAYING) { if (Default::game_time_pause_start != 0) { Default::game_time_paused += (SDL_GetTicksNS() - Default::game_time_pause_start) * 1e-9; Default::game_time_pause_start = 0; } state_temp.reset(); switch (game_state_e) { case NewGameState_e::LOAD: case NewGameState_e::NEW: input.game_restart = false; state_playing = std::make_unique(); state_playing->Init(this); break; default: break; } switch (game_state_e) { case NewGameState_e::LOAD: Load(active_game_dir); break; case NewGameState_e::NEW: Save(active_game_dir); break; default: break; } state_current = state_playing.get(); state_current_e = new_state; return; } if (state_current_e == GameState_e::STATE_PLAYING && Default::game_time_pause_start == 0) Default::game_time_pause_start = SDL_GetTicksNS(); // STATE MODIFY AND MENU switch (new_state) { case GameState_e::STATE_MODIFY: SDL_ShowCursor(); state_temp = std::make_unique(); break; case GameState_e::STATE_MENU_MAIN: SDL_ShowCursor(); state_temp = std::make_unique(); break; default: break; } bool is_set = false; switch (new_state) { case GameState_e::STATE_MODIFY: case GameState_e::STATE_MENU_MAIN: state_current = state_temp.get(); state_current->Init(this); is_set = true; break; default: break; } if (is_set) state_current_e = new_state; } void Game::Run() { if (Default::is_fullscreen) StartScreen_Event::event_Loop(renderer); SDL_GetRenderOutputSize(renderer, &win_size.w, &win_size.h); while (running) { Default::set_DeltaTime(); handle_Events(); if (state_changed) { continue; } //std::cout << "IC " << (int)this->input.click_left << std::endl; Update(); Render(); // FPS calculation Default::fps_counter++; Default::fps_timer += Default::delta_time; if (Default::fps_timer >= 1.0f) { Default::fps = Default::fps_counter; Default::fps_counter = 0; Default::fps_timer -= 1.0f; } } Enemy::shutdown_Workers(); EndScreen_Event::event_Loop(renderer); } void Game::handle_Events() { SDL_Event event; //SDL_GetWindowSize(window, &win_size.w, &win_size.h); Uint32 mouse_buttons = SDL_GetMouseState(&input.mouse_state_raw.x, &input.mouse_state_raw.y); input.mouse_state.x = input.mouse_state_raw.x/Default::game_scale; input.mouse_state.y = input.mouse_state_raw.y/Default::game_scale; input.click_left = (mouse_buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)) != 0; input.click_right = (mouse_buttons & SDL_BUTTON_MASK(SDL_BUTTON_RIGHT)) != 0; input.click_left_released = false; input.click_right_released = false; input.pressed_return_released = false; input.pressed_arrowdown_released = false; input.pressed_arrowup_released = false; input.pressed_c_released = false; state_changed = false; input.mouse_game_offset = {Map::offset.x, Map::offset.y }; // START set input.mouse_tile_position Tile::set_HoveringTileset(input.mouse_state); input.cursor_over_tileset = Tile::hovering_set; // END set input.mouse_tile_position if (input.cursor_over_tileset) { input.mouse_game_offset = {(int)Tile::tileset_offset.x, (int)Tile::tileset_offset.y }; } while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_EVENT_QUIT: running = false; break; case SDL_EVENT_WINDOW_RESIZED: case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: { int w, h; SDL_GetWindowSize(window, &w, &h); win_size.w = w; win_size.h = h; break; } case SDL_EVENT_MOUSE_BUTTON_DOWN: cursor->mouse_OnClick(); break; case SDL_EVENT_MOUSE_BUTTON_UP: input.click_left_released = true; input.click_left = false; input.click_right_released = true; input.click_right = false; break; case SDL_EVENT_MOUSE_WHEEL: if (event.wheel.y > 0) Default::game_scale += 0.2f; else if (event.wheel.y < 0) Default::game_scale -= 0.2f; if (Default::game_scale < 0.5) Default::game_scale = 0.5; if (Default::game_scale > 4.2f) Default::game_scale = 4.2f; break; case SDL_EVENT_KEY_DOWN: switch (event.key.scancode) { case SDL_SCANCODE_ESCAPE: if (state_current_e == GameState_e::STATE_MENU_MAIN) set_State(GameState_e::STATE_PLAYING, NewGameState_e::NONE); else set_State(GameState_e::STATE_MENU_MAIN); return; case SDL_SCANCODE_F9: set_State(GameState_e::STATE_PLAYING, NewGameState_e::NONE); return; case SDL_SCANCODE_F10: set_State(GameState_e::STATE_MODIFY); return; case SDL_SCANCODE_F12: draw_frames = !draw_frames; return; case SDL_SCANCODE_LSHIFT: input.pressed_shift = true; break; case SDL_SCANCODE_LCTRL: input.pressed_ctrl = true; break; case SDL_SCANCODE_RETURN: input.pressed_return = true; break; case SDL_SCANCODE_I: Ui::draw_key_info = !Ui::draw_key_info; break; case SDL_SCANCODE_C: input.pressed_c = true; break; case SDL_SCANCODE_Q: if (input.pressed_ctrl) running = false; break; default: break; } break; case SDL_EVENT_KEY_UP: switch (event.key.scancode) { case SDL_SCANCODE_LCTRL: input.pressed_ctrl = false; break; case SDL_SCANCODE_LSHIFT: input.pressed_shift = false; break; case SDL_SCANCODE_C: input.pressed_c = false; input.pressed_c_released = true; break; case SDL_SCANCODE_RETURN: input.pressed_return = false; input.pressed_return_released = true; break; case SDL_SCANCODE_DOWN: input.pressed_arrowdown_released = true; break; case SDL_SCANCODE_UP: input.pressed_arrowup_released = true; break; default: break; } default: break; } state_current->handle_Events(event, this); } if (!input.game_running) running = false; input.update_Mousetileposition(); } void Game::Update() { state_current->Update(this); cursor->Update(Default::delta_time, input.mouse_state_raw.x, input.mouse_state_raw.y); } void Game::Render() { SDL_SetRenderDrawColor(renderer, 62, 146, 209, 255); SDL_RenderClear(renderer); Map::draw_MapTiles(this); state_current->Render(this); if (draw_frames) Ui::draw_Frames(renderer, win_size); if (Ui::draw_key_info) Ui::draw_KeyInfo(this); cursor->Render(renderer); SDL_RenderPresent(renderer); } bool Game::Save(const std::string &path) const { std::ofstream file(path + "/game", std::ios::binary | std::ios::trunc); std::cout << "Save Game\n"; if (!file) { std::cout << "No file found at: " << path+"/game" << std::endl; return false; } // Default namespace file.write(reinterpret_cast(&Default::game_scale), sizeof(Default::game_scale)); // Map namespace file.write(reinterpret_cast(&Map::offset.x), sizeof(Map::offset.x)); file.write(reinterpret_cast(&Map::offset.y), sizeof(Map::offset.y)); state_playing->Save(path); return file.good(); } bool Game::Load(const std::string &path) { std::ifstream file(path + "/game", std::ios::binary); std::cout << "Load Game\n"; if (!file) { std::cout << "No file found at: " << path+"/game" << std::endl; return false; } // Default namespace file.read(reinterpret_cast(&Default::game_scale), sizeof(Default::game_scale)); // Map namespace file.read(reinterpret_cast(&Map::offset.x), sizeof(Map::offset.x)); file.read(reinterpret_cast(&Map::offset.y), sizeof(Map::offset.y)); state_playing->Load(renderer, path); return file.good(); }