mapcreator git · master
SDL3 2.5D game and engine using assets, with map editor
C++ 99.3%git clone https://git.christianimmanuel.de/sdl-graphics/mapcreator.gitwget https://git.christianimmanuel.de/sdl-graphics/mapcreator/archive/mapcreator.tar.gzsrc/game/game.cpp raw
#include "game/game.hpp"
#include <iostream>
#include <cmath>
#include <vector>
#include <unordered_map>
#include <fstream>
#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<StatePlaying>();
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<StateModify>();
break;
case GameState_e::STATE_MENU_MAIN:
SDL_ShowCursor();
state_temp = std::make_unique<StateMenuMain>();
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<const char*>(&Default::game_scale), sizeof(Default::game_scale));
// Map namespace
file.write(reinterpret_cast<const char*>(&Map::offset.x), sizeof(Map::offset.x));
file.write(reinterpret_cast<const char*>(&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<char*>(&Default::game_scale), sizeof(Default::game_scale));
// Map namespace
file.read(reinterpret_cast<char*>(&Map::offset.x), sizeof(Map::offset.x));
file.read(reinterpret_cast<char*>(&Map::offset.y), sizeof(Map::offset.y));
state_playing->Load(renderer, path);
return file.good();
}