From 81eacdb7e6a65f0f63115bbd8cef1d315f625f21 Mon Sep 17 00:00:00 2001 From: jowen005 Date: Tue, 14 Jul 2026 18:07:45 -0400 Subject: [PATCH] Fixed Minimap Updating --- .gitignore | 1 + CMakeLists.txt | 21 ++++++++++++++++++++- concreteGuiManager.cpp | 15 ++++++++++++++- gameManager.cpp | 9 ++++++++- main.cpp | 7 +++++-- map.cpp | 42 ++++++++++++++++++++++++++++++++++++------ map.h | 4 ++-- playButton.cpp | 7 ++++++- util.cpp | 2 ++ 9 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13850f8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +\build \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 554c9c1..a60931b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pedantic") endif() -set(CMAKE_CXX_STANDART 17) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_POLICY_VERSION_MINIMUM 3.5) set(CMAKE_BUILD_TYPE Debug) set(BUILD_TESTS OFF) @@ -50,6 +50,16 @@ set(GAME_BASE_DIR external/gameBase) add_executable(${GAME_NAME} main.cpp ${GAME_SRC}) +# Do this for Windows +if(MSVC) + target_compile_options(${GAME_NAME} PRIVATE + /bigobj + # /utf-8 + # /UUNICODE + # /U_UNICODE + ) +endif() + include_directories(external/tinydir) include_directories(external/vb01/external/glm) include_directories(external/vb01/external/glm/glm) @@ -81,6 +91,15 @@ if(BUILD_TESTS) set(TEST_NAME battleshipTests) add_executable(${TEST_NAME} ${TEST_SRC}) + # Do this for Windows + if(MSVC) + target_compile_options(${TEST_NAME} PRIVATE + /bigobj + # /utf-8 + # /UUNICODE + # /U_UNICODE + ) + endif() target_include_directories(${TEST_NAME} PUBLIC ${VB01_DIR}) target_include_directories(${TEST_NAME} PUBLIC ${VB01_GUI_DIR}) target_include_directories(${TEST_NAME} PUBLIC ${GAME_BASE_DIR}) diff --git a/concreteGuiManager.cpp b/concreteGuiManager.cpp index 76c6939..8925958 100644 --- a/concreteGuiManager.cpp +++ b/concreteGuiManager.cpp @@ -49,11 +49,13 @@ namespace battleship{ ConcreteGuiManager::ConcreteGuiManager(){ string assetPath = GameManager::getSingleton()->getPath(); + // These base paths are used for when the LUA GUI entries refer to textures or font texBasePath = assetPath + "Textures/"; fontBasePath = assetPath + "Fonts/"; } ConcreteGuiManager* ConcreteGuiManager::getSingleton(){ + // Return the single already created concreteGui Mangner if(!concreteGuiManager) concreteGuiManager = new ConcreteGuiManager(); @@ -160,6 +162,7 @@ namespace battleship{ case EXPORT: button = new ExportButton(pos, size); break; + // This case begins the gameplay case PLAY:{ int mid = guiTable["dependencies"][1]["id"]; Listbox *mapListbox = (MapListbox*)guiElements[mid].second; @@ -541,7 +544,8 @@ namespace battleship{ return text; } - + + /// @brief Parse the music variables from the Lua script void ConcreteGuiManager::parseMusic(){ sol::state_view SOL_STATE_VIEW = generateView(); sol::optional musicTblOpt = SOL_STATE_VIEW["music"]; @@ -570,6 +574,7 @@ namespace battleship{ sm->play(trackPaths, 100, delay, loop, shuffle); } + // Parses the passed lua script and removes any existing GUI elements (the removal is for switching between screens) void ConcreteGuiManager::readLuaScreenScript( string script, vector buttonExceptions, @@ -606,12 +611,19 @@ namespace battleship{ parseLuaScript(script); } + /// @brief Parses a lua script to display its GUI screen defined in the it + /// @param script + /// @param luaCode void ConcreteGuiManager::parseLuaScript(string script, string luaCode){ guiElements.clear(); string basePath = GameManager::getSingleton()->getPath() + "Scripts/Gui/"; + // Creates a shared lua state if it doesn't exist and wraps it in a state view for convenient C++ access + // It the state exists then it just creates a state view wrapper around the same state sol::state_view SOL_LUA_VIEW = generateView(); + // Set the music to nil since not every screen has a music value to override the one from the last screen SOL_LUA_VIEW.script("music = nil"); + // Loads and executes the passed lua script inside the shared lua state, creating variables from the passed script that can be accessed SOL_LUA_VIEW.script_file(basePath + script); if(luaCode != "") SOL_LUA_VIEW.script(luaCode); @@ -619,6 +631,7 @@ namespace battleship{ SOL_LUA_VIEW.script("numGui = #gui"); int numGuiElements = SOL_LUA_VIEW["numGui"]; + // Go through all the GUI entriies in mainMenu.lua and based on their type add the correspondding element for(int i = 0; i < numGuiElements; i++){ int guiTypeId = SOL_LUA_VIEW["gui"][i + 1]["guiType"]; diff --git a/gameManager.cpp b/gameManager.cpp index 297385e..c899111 100755 --- a/gameManager.cpp +++ b/gameManager.cpp @@ -251,6 +251,8 @@ namespace battleship{ ); } + /// @brief Sets the name of the directory where all the files are located as the passed game directory + /// @param gameDir void GameManager::initLua(string gameDir){ sol::state_view SOL_LUA_STATE = generateView(); @@ -259,7 +261,8 @@ namespace battleship{ for(string f : configData::scripts) SOL_LUA_STATE.script_file(path + f); - + + // Gets the minimap Lua script SOL_LUA_STATE.script_file(path + "Scripts/Gui/_minimap.lua"); sol::table resTable = SOL_LUA_STATE["graphics"]["resolution"]; @@ -267,11 +270,14 @@ namespace battleship{ height = resTable["y"]; } + /// @brief Starts game execution + /// @param gameDir is the game directory all the game files are stored in void GameManager::start(string gameDir) { running = true; registerMembers(); initLua(gameDir); + // I beliieve this sets the game window width and height and name (last variable), I'm not for sure about the path Root *root = Root::getSingleton(); root->start(width, height, path + "../external/vb01/", "Battleship"); @@ -279,6 +285,7 @@ namespace battleship{ inputManager = new InputManager(stateManager, root->getWindow()); } + /// @brief Updates the sound, input, and state manager along with the root of the game engine void GameManager::update() { Root::getSingleton()->update(); SoundManager::getSingleton()->update(); diff --git a/main.cpp b/main.cpp index 064259f..2936bc6 100755 --- a/main.cpp +++ b/main.cpp @@ -15,6 +15,7 @@ using namespace vb01; using namespace std; int main(int argc, char **argv) { + // Get the executable's name as the game path string gamePath = string(argv[0]); for(int i = 0; i < gamePath.length(); i++) @@ -22,14 +23,16 @@ int main(int argc, char **argv) { gamePath[i] = '/'; gamePath = gamePath.substr(0, gamePath.find_last_of("/") + 1) + "../"; - + // Start the game manager and pass the game path to it GameManager *gm = GameManager::getSingleton(); gm->start(gamePath); + // Get the state manager and attach a new Gui app state gm->getStateManager()->attachAppState(new GuiAppState()); AssetManager::getSingleton()->load(gm->getPath() + "Fonts/batang.ttf"); - + // Begin on the main menu GUI ConcreteGuiManager::getSingleton()->readLuaScreenScript("mainMenu.lua"); + // As long as the game manager is running, update it while(gm->isRunning()){ gm->update(); } diff --git a/map.cpp b/map.cpp index 4ba9728..b39efa6 100755 --- a/map.cpp +++ b/map.cpp @@ -42,11 +42,14 @@ namespace battleship{ return minimap; } + // Minimap constructor Map::Minimap::Minimap(){ + // Gets map size Vector3 mapSize = Map::getSingleton()->getMapSize(); float ratio = mapSize.x / mapSize.z; - + sol::state_view SOL_LUA_VIEW = generateView(); + // Set the minimap size SOL_LUA_VIEW.script_file(GameManager::getSingleton()->getPath() + "Scripts/Gui/activeGameState.lua"); sol::table sizeTbl = SOL_LUA_VIEW["minimapSize"]; float initSizeX = sizeTbl["x"], initSizeY = sizeTbl["y"]; @@ -73,7 +76,8 @@ namespace battleship{ string camIconFile = SOL_LUA_VIEW["eyeIcon"]; camIcon = initIcon(Root::getSingleton()->getCamera()->getPosition(), basePath + camIconFile); } - + + // Minimap destructor Map::Minimap::~Minimap(){ Node *guiNode = Root::getSingleton()->getGuiNode(); @@ -88,7 +92,13 @@ namespace battleship{ delete camIcon; } + + /// @brief Initialize an icon for the minimap by passing its path and poition on the map + /// @param posOnMap + /// @param iconPath + /// @return Node* Map::Minimap::initIcon(Vector3 posOnMap, string iconPath){ + // Get the icon image, its size, and texture string p[]{iconPath}; ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(iconPath); Vector3 iconSize = Vector3(asset->width, asset->height, 0); @@ -99,6 +109,7 @@ namespace battleship{ mat->addBoolUniform("texturingEnabled", true); mat->addTexUniform("diffuseMap", tex, false); + // Get the minimap size and position on the screen sol::state_view SOL_LUA_VIEW = generateView(); sol::table posTbl = SOL_LUA_VIEW["minimapPos"], _posTbl = SOL_LUA_VIEW["_minimapPos"], @@ -109,14 +120,16 @@ namespace battleship{ Vector3 minimapPos = Vector3((float)_posTbl["x"], (float)posTbl["y"] + (float)_posTbl["y"], (float)posTbl["z"]); Vector3 mapSize = Map::getSingleton()->getMapSize(); + // Use the minimap size and the map size to place the icon on the minimap in a position corresponding to its position in the real map Vector2 iconPos = Vector2( minimapSize.x * (posOnMap.x + .5 * mapSize.x) / mapSize.x, minimapSize.y * (posOnMap.z + .5 * mapSize.z) / mapSize.z ); + // Create a quad rendering the icon UI element Quad *quad = new Quad(iconSize, false); quad->setMaterial(mat); - + // Attach the quad to a GUI node of the icon's size and position Node *node = new Node(minimapPos + Vector3(iconPos.x, iconPos.y, .05) - .5 * iconSize); node->attachMesh(quad); root->getGuiNode()->attachChild(node); @@ -125,24 +138,29 @@ namespace battleship{ } //TODO add a flag to Player::getUnits* whether to include garrisoned units + /// @brief Updates the minimap according to the real map void Map::Minimap::updateImage(){ GameManager *gm = GameManager::getSingleton(); Map *map = Map::getSingleton(); - + + // Get the entire minimap image string imagePath = gm->getPath() + "Models/Maps/" + map->getMapName() + "/minimap.jpg"; ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(imagePath); int width = asset->width, height = asset->height; Vector3 mapSize = map->getMapSize(); + // Stores the positions of the friendly units vector> unitMinimapPos; - + // Get the current game state ActiveGameState *activeState = (ActiveGameState*)gm->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE); + // Go through all the units on the player's team and get their map position to convert to minimap coordinates to store in the minimap positions for(Player *pl : Game::getSingleton()->getPlayers(true)) if(pl->getTeam() == activeState->getPlayer()->getTeam()){ vector units = pl->getUnits(); for(Unit *u : units){ + // Skip adding all the garrisonable units if(u->isVehicle() && ((Vehicle*)u)->getGarrisonable()) continue; Vector2 coords = Vector2( @@ -156,6 +174,7 @@ namespace battleship{ int pxId = 0, numChannels = asset->numChannels, size = width * height * numChannels; float losFactor = .6; + // Darkens the entire minimap for(u8 *p = asset->image; p != asset->image + size; p += numChannels, pxId += numChannels){ *(p + 0) = losFactor * oldImageData[pxId + 0]; *(p + 1) = losFactor * oldImageData[pxId + 1]; @@ -164,11 +183,13 @@ namespace battleship{ int unitPxRadius = 1; + // Go through all the minimap positions and for(pair unitPair : unitMinimapPos){ Unit *losUnit = unitPair.first; Vector2 losUnitCoords = unitPair.second; float minimapLos = losUnit->getLineOfSight() / mapSize.x * width; + // Restore brightness based on if the units are in the LOS radius for(int x = max(-.5f * width, losUnitCoords.x - minimapLos); x < min(.5f * width, losUnitCoords.x + minimapLos); x++){ for(int y = max(-.5f * height, losUnitCoords.y - minimapLos); y < min(.5f * height, losUnitCoords.y + minimapLos); y++){ int pxId = width * (y + .5 * height) + (x + .5 * width); @@ -178,7 +199,8 @@ namespace battleship{ asset->image[numChannels * pxId + 0] = oldImageData[numChannels * pxId + 0]; asset->image[numChannels * pxId + 1] = oldImageData[numChannels * pxId + 1]; asset->image[numChannels * pxId + 2] = oldImageData[numChannels * pxId + 2]; - + // Color the areas inside visible regions near the friendly unit minimap positions with the current player's color + // This only shows friendly units in the line of sight, should that be the case? for(pair addUnitPair : unitMinimapPos) if(fabs(addUnitPair.second.x - coords.x) < unitPxRadius && fabs(addUnitPair.second.y - coords.y) < unitPxRadius){ Vector3 unitCol = addUnitPair.first->getPlayer()->getColor(); @@ -193,12 +215,15 @@ namespace battleship{ } } + // Load the minimap image data Node *rectNode = ConcreteGuiManager::getSingleton()->getButton("minimap")->getRectNode(); Material *mat = rectNode->getMesh(0)->getMaterial(); Texture *tex = ((Material::TextureUniform*)mat->getUniform("diffuseMap"))->value; tex->loadImageData(asset, false); } + /// @brief Updates the position of the camera positiion icon GUI that goes on the minimap to where the camera is currently in the real map + /// @param minimapButton void Map::Minimap::updateCamFrame(Button *minimapButton){ Vector3 camPos = Root::getSingleton()->getCamera()->getPosition(); Vector3 mapSize = Map::getSingleton()->getMapSize(); @@ -208,14 +233,18 @@ namespace battleship{ minimapSize.y * (camPos.z + .5 * mapSize.z) / mapSize.z ); + // Overlay the icon on the minimap by using the minimap's position camIcon->setPosition(minimapButton->getPos() + Vector3(iconPos.x, iconPos.y, .06)); } + /// @brief Updates the minimap unit positions and cam frame icon as long as the application state is active void Map::Minimap::update(){ Button *mb = ConcreteGuiManager::getSingleton()->getButton("minimap"); if(!(GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE) && mb)) return; + updateImage(); + updateCamFrame(mb); } @@ -279,6 +308,7 @@ namespace battleship{ return edges; } + /// @brief Update the minimap void Map::update(){ Minimap::getSingleton()->update(); } diff --git a/map.h b/map.h index c983f98..635f456 100755 --- a/map.h +++ b/map.h @@ -69,7 +69,7 @@ namespace battleship{ }; static Map* getSingleton(); - ~Map(){} + ~Map(){} // Destructor is public static std::vector generateAdjacentNodeEdges(int, int, int, int, int); void update(); void load(std::string); @@ -111,7 +111,7 @@ namespace battleship{ std::vector lights; std::vector>> regions; - Map(){} + Map(){} // Constructor is private void preprareScene(bool); void loadSpawnPoints(); void loadLights(); diff --git a/playButton.cpp b/playButton.cpp index 903fc74..7d93266 100644 --- a/playButton.cpp +++ b/playButton.cpp @@ -17,6 +17,7 @@ namespace battleship{ PlayButton::PlayButton(Listbox *ml, Vector3 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", GLFW_KEY_P, separate), mapListbox(ml) {} + // Starts the gameplay void PlayButton::onClick() { ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton(); vector factionsListboxes, difficultiesListboxes, colorsListboxes, teamsListboxes; @@ -30,6 +31,7 @@ namespace battleship{ else if(name == "teams") teamsListboxes.push_back(listbox); } + // Initialize the game Game *game = Game::getSingleton(); game->initTechnologies(); @@ -72,7 +74,10 @@ namespace battleship{ string name = (cpuPlayer ? "CPU player #" + to_string(i) : "Player"); game->addPlayer(new Player(difficulty, faction, team, color, cpuPlayer, i, name)); } - + + // HUD GUI for during gameplay + // The loading app state passed is an InGameAppState for the selected map with the inGame.lua script for the screen + // The initial state of the current map is used to populate the HUD GUI here handleLoadingGui(new LoadingAppState(new InGameAppState(mapName), "inGame.lua")); } } diff --git a/util.cpp b/util.cpp index 76e5450..3b66ae4 100755 --- a/util.cpp +++ b/util.cpp @@ -36,6 +36,8 @@ using namespace vb01Gui; namespace battleship{ using namespace configData; + /// @brief Pushes the loadable assets from asset manager as a state to the state manager stack + /// @param loadState void handleLoadingGui(LoadingAppState *loadState){ ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton(); guiManager->readLuaScreenScript("loadingScreen.lua");