/* * 2D Game Engine * Game.cpp: Base Game engine class * Based on pikuma.com 2D game engine in C++ and Lua course * Copyright (c) 2021 986-Studio. All Right Reserved * * Created by Manoƫl Trapier on 09/02/2021. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include uint32_t Game::windowsWidth = 0; uint32_t Game::windowsHeight = 0; uint32_t Game::mapWidth = 0; uint32_t Game::mapHeight = 0; Game::Game() { this->isRunning = false; this->isDebug = false; this->millisecsPerviousFrame = 0; this->registry = std::make_unique(); this->assetStore = std::make_unique(); this->eventBus = std::make_unique(); } Game::~Game() { } void Game::Initialize() { int ret; SDL_DisplayMode displayMode; ret = SDL_Init(SDL_INIT_EVERYTHING); if (ret) { Logger::Critical("SDL Initialisation error."); return; } ret = TTF_Init(); if (ret) { Logger::Critical("SDL_ttf Initialisation error."); return; } SDL_GetCurrentDisplayMode(0, &displayMode); Game::windowsWidth = 800; //displayMode.w; Game::windowsHeight = 600; //displayMode.h; this->window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Game::windowsWidth, Game::windowsHeight, SDL_WINDOW_BORDERLESS); if (!window) { Logger::Critical("SDL window creation error."); return; } this->renderer = SDL_CreateRenderer(this->window, -1, 0); if (!renderer) { Logger::Critical("SDL renderer creation error."); return; } //SDL_SetWindowFullscreen(this->window, SDL_WINDOW_FULLSCREEN); this->camera.x = 0; this->camera.y = 0; this->camera.w = Game::windowsWidth; this->camera.h = Game::windowsHeight; this->isRunning = true; } void Game::Destroy() { if (this->renderer) { SDL_DestroyRenderer(this->renderer); } if (this->window) { SDL_DestroyWindow(this->window); } SDL_Quit(); } void Game::Run() { this->Setup(); #if 0 for(int i = 0 ; i < 100; i++) { this->ProcessInput(); this->Update(); this->Render(); } #else while(this->isRunning) { this->ProcessInput(); this->Update(); this->Render(); } #endif } void Game::LoadLevel(int level) { this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->registry->addSystem(); this->assetStore->addTexture(this->renderer, "tank-image", "assets/images/tank-panther-right.png"); this->assetStore->addTexture(this->renderer, "truck-image", "assets/images/truck-ford-right.png"); this->assetStore->addTexture(this->renderer, "chopper-image", "assets/images/chopper-spritesheet.png"); this->assetStore->addTexture(this->renderer, "main-tileset", "assets/tilemaps/jungle.png"); this->assetStore->addTexture(this->renderer, "radar-image", "assets/images/radar.png"); this->assetStore->addTexture(this->renderer, "bullet-image", "assets/images/bullet.png"); this->assetStore->addFont("charriot-font", "assets/fonts/charriot.ttf", 20); this->assetStore->addFont("arial-font", "assets/fonts/charriot.ttf", 20); this->assetStore->addFont("pico8-font", "assets/fonts/charriot.ttf", 10); Logger::Debug("struct SpriteComponent size is %d", sizeof(struct SpriteComponent)); // jungle.map int tileSize = 32; double tileScale = 2.0; int mapNumCols = 25; int mapNumRows = 20; std::fstream mapFile; mapFile.open("assets/tilemaps/jungle.map"); assert(mapFile.is_open()); for (int y = 0; y < mapNumRows; y++) { for (int x = 0; x < mapNumCols; x++) { char ch[2] = {0, 0}; mapFile.get(ch[0]); int srcRectY = atoi(ch) * tileSize; mapFile.get(ch[0]); int srcRectX = atoi(ch) * tileSize; mapFile.ignore(); Entity tile = registry->createEntity(); tile.addComponent(glm::vec2(x * (tileScale * tileSize), y * (tileScale * tileSize)), glm::vec2(tileScale, tileScale), 0.0); tile.addComponent("main-tileset", 0, tileSize, tileSize, false, srcRectX, srcRectY); tile.group("tiles"); } } mapFile.close(); Game::mapWidth = mapNumCols * tileSize * tileScale; Game::mapHeight = mapNumRows * tileSize * tileScale; Entity chopper = this->registry->createEntity(); chopper.addComponent(glm::vec2(240, 110), glm::vec2(1, 1), 0); chopper.addComponent("chopper-image", 1, 32, 32); chopper.addComponent(glm::vec2(0, 0)); chopper.addComponent(32, 32); chopper.addComponent(2, 15, true); chopper.addComponent(glm::vec2(0, -80), glm::vec2(80, 0), glm::vec2(0, 80), glm::vec2(-80, 0)); chopper.addComponent(glm::vec2(180, 180), 0, 10000, 10, true); chopper.addComponent(100); chopper.addComponent(); chopper.tag("player"); Entity radar = this->registry->createEntity(); radar.addComponent(glm::vec2(this->windowsWidth - 75, 10), glm::vec2(1, 1), 0); radar.addComponent(glm::vec2(0, 0)); radar.addComponent("radar-image", 3, 64, 64, true); radar.addComponent(8, 5, true); Entity tank = this->registry->createEntity(); tank.addComponent(glm::vec2(500, 500), glm::vec2(1, 1), 0); tank.addComponent(glm::vec2(0, 0)); tank.addComponent("tank-image", 1, 32, 32); tank.addComponent(32, 32); tank.addComponent(glm::vec2(100, 0), 3000, 5000, 10, false); tank.addComponent(100); tank.group("enemies"); Entity truck = this->registry->createEntity(); truck.addComponent(glm::vec2(120, 500), glm::vec2(1, 1), 0); truck.addComponent(glm::vec2(0, 0)); truck.addComponent("truck-image", 2, 32, 32); truck.addComponent(32, 32); truck.addComponent(glm::vec2(0, -100), 2000, 5000, 10, false); truck.addComponent(100); truck.group("enemies"); SDL_Color green = { 64, 255, 127, 255 }; Entity label = this->registry->createEntity(); label.addComponent(glm::vec2(this->windowsWidth/2 - 60, 10), "SUPER CHOPPER BROS 1.0", "charriot-font", green); } void Game::Setup() { LoadLevel(1); } void Game::Update() { uint32_t timeToWait = MILLISECS_PER_FRAME - (SDL_GetTicks() - this->millisecsPerviousFrame); if (timeToWait > 0 && timeToWait <= MILLISECS_PER_FRAME) { SDL_Delay(timeToWait); } double deltaTime = (SDL_GetTicks() - this->millisecsPerviousFrame) / 1000.0; this->millisecsPerviousFrame = SDL_GetTicks(); eventBus->reset(); registry->getSystem().subscriptToEvents(eventBus); registry->getSystem().subscriptToEvents(eventBus); registry->getSystem().subscriptToEvents(eventBus); registry->update(); registry->getSystem().update(deltaTime); registry->getSystem().update(); registry->getSystem().update(this->eventBus); registry->getSystem().update(this->registry); registry->getSystem().update(); registry->getSystem().update(this->camera); } void Game::ProcessInput() { SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: this->isRunning = false; break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { this->isRunning = false; } else if (event.key.keysym.sym == SDLK_d) { this->isDebug = !this->isDebug; } else { this->eventBus->emitEvent(event.key.keysym.sym); } break; default: break; } } } void Game::Render() { SDL_SetRenderDrawColor(this->renderer, 21, 21, 21, 255); SDL_RenderClear(this->renderer); registry->getSystem().update(this->renderer, this->assetStore, this->camera); registry->getSystem().update(this->renderer, this->assetStore, this->camera); registry->getSystem().update(this->renderer, this->assetStore, this->camera); if (this->isDebug) { registry->getSystem().debugRender(this->renderer, this->camera); } SDL_RenderPresent(this->renderer); }