From f39c67793f4ce44daed0b2250ac1103e4d088e19 Mon Sep 17 00:00:00 2001 From: devZoGok Date: Fri, 14 Nov 2025 15:49:05 +0200 Subject: [PATCH] improved turret handling on a hilly surface --- unit.cpp | 2 +- util.cpp | 203 +++------------------------------------------------- util.h | 2 +- vehicle.cpp | 17 +---- weapon.cpp | 55 +++++--------- weapon.h | 2 - 6 files changed, 32 insertions(+), 249 deletions(-) diff --git a/unit.cpp b/unit.cpp index 3c9142b..7f4d295 100755 --- a/unit.cpp +++ b/unit.cpp @@ -524,7 +524,7 @@ namespace battleship{ else if(res[0].mesh->getNode() == map->getNodeParent()->getChild(0)){ float angle = upVec.getAngleBetween(res[0].norm); - if(angle > 0) + //if(angle > 0) model->lookAt(leftVec.cross(res[0].norm), res[0].norm); } } diff --git a/util.cpp b/util.cpp index 9d94310..76e5450 100755 --- a/util.cpp +++ b/util.cpp @@ -56,201 +56,20 @@ namespace battleship{ stateManager->attachAppState(loadState); } - void makeTitlescreenButtons(GuiAppState *state) { - /* - class SpButton : public Button { - public: - SpButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", GLFW_KEY_S, separate) { - this->state = state; - } + Vector3 getVecToPlane(Vector3 pos, Vector3 dirVec, Vector3 upVec){ + float baseAngle = upVec.getAngleBetween(dirVec.norm()); - void onMouseOver(){ - setColor(Vector4(.8, .8, .8, 1)); - } + if(fabs(baseAngle - PI / 2) > .001){ + bool acuteAngle = (baseAngle < PI / 2); - void onMouseOff(){ - setColor(Vector4(.6, .6, .6, 1)); - } + if(acuteAngle) baseAngle = PI / 2 - baseAngle; + else baseAngle -= PI / 2; - void onClick() { - vector difficulties, factions; - - class PlayButton : public Button { - public: - PlayButton(Listbox **difficulties, Listbox **factions, Listbox *mapListbox, int lengths[2], Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", GLFW_KEY_P, separate) { - this->state = ((GuiAppState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::GUI_STATE)); - this->lengths[0] = lengths[0]; - this->lengths[1] = lengths[1]; - - difficultiesListboxes = difficulties; - factionsListboxes = factions; - this->mapListbox = mapListbox; - } - - void onClick() { - GameManager *gm = GameManager::getSingleton(); - std::vector difficulties, factions; - - for(int i = 0; i < lengths[0]; i++) - difficulties.push_back(wstringToString(difficultiesListboxes[i]->getContents()[difficultiesListboxes[i]->getSelectedOption()])); - - for(int i = 0; i < lengths[1]; i++) - factions.push_back(to_string(factionsListboxes[i]->getSelectedOption())); - - - delete[] difficultiesListboxes; - delete[] factionsListboxes; - - StateManager *stateManager = gm->getStateManager(); - int selectedMap = mapListbox->getSelectedOption(); - string mapName = wstringToString(mapListbox->getContents()[selectedMap]); - stateManager->attachAppState(new InGameAppState(difficulties, factions, mapName)); - state->removeAllListboxes(); - state->removeButton("Back"); - state->removeButton("Play"); - } - private: - GuiAppState *state; - Listbox **difficultiesListboxes, **factionsListboxes, *mapListbox = nullptr; - int lengths[2]; - }; - - class ReturnButton : public Button { - public: - - ReturnButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", GLFW_KEY_B, separate) { - this->state = state; - } - - void onClick() { - state->removeAllCheckboxes(); - state->removeAllListboxes(); - state->removeAllSliders(); - state->removeAllTextboxes(); - makeTitlescreenButtons(state); - state->removeButton("Play"); - state->removeButton("Back"); - } - private: - GuiAppState *state; - }; - - GameManager *gm = GameManager::getSingleton(); - Vector2 pos(gm->getWidth() / 8, gm->getHeight() / 8); - difficulties.push_back("Easy"); - difficulties.push_back("Medium"); - difficulties.push_back("Hard"); - factions.push_back("0"); - factions.push_back("1"); - - - string font = gm->getPath() + "Fonts/batang.ttf"; - Listbox *cpuDifficulty = new Listbox(Vector2(pos.x, pos.y + 30), Vector2(100, 20), difficulties, 3, font); - Listbox *cpuFaction = new Listbox(Vector2(pos.x + 110, pos.y + 30), Vector2(100, 20), factions, 2, font); - Listbox *playerFaction = new Listbox(Vector2(pos.x + 110, pos.y), Vector2(100, 20), factions, 2, font); - - vector folders = readDir(gm->getPath() + "Models/Maps", true); - int numMinDirs = 3; - int numShowDirs = folders.size() < numMinDirs ? folders.size() : numMinDirs; - Listbox *map = new Listbox(Vector2(pos.x + 110, pos.y + 100), Vector2(100, 20), folders, numShowDirs, font); - Listbox **difficultyListboxes = new Listbox*[1]; - Listbox **factionListboxes = new Listbox*[2]; - - difficultyListboxes[0] = cpuDifficulty; - factionListboxes[0] = playerFaction; - factionListboxes[1] = cpuFaction; - - int lengths[]{1, 2}; - PlayButton *playButton = new PlayButton(difficultyListboxes, factionListboxes, map, lengths, Vector2(50, gm->getHeight() - 150), Vector2(140, 50), "Play", true); - ReturnButton *returnButton = new ReturnButton(state, Vector2(200, gm->getHeight() - 150), Vector2(140, 50), "Back", true); - state->addButton(playButton); - state->addButton(returnButton); - state->addListbox(cpuDifficulty); - state->addListbox(cpuFaction); - state->addListbox(playerFaction); - state->addListbox(map); - state->removeButton("Options"); - state->removeButton("Exit"); - state->removeButton("Singleplayer"); - - } - private: - GuiAppState *state; - }; - - class MainMenuOptionsButton : public OptionsButton { - public: - - MainMenuOptionsButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : OptionsButton(pos, size, name, separate) { - this->state = state; - } - - void onClick() { - ReturnButton *returnButton = new ReturnButton(state, Vector2(50, GameManager::getSingleton()->getHeight() - 150), Vector2(150, 50), "Back", true); - state->addButton(returnButton); - state->removeButton("Singleplayer"); - state->removeButton("Exit"); - OptionsButton::onClick(); - } - - void onMouseOver(){ - setColor(Vector4(.8, .8, .8, 1)); - } - - void onMouseOff(){ - setColor(Vector4(.6, .6, .6, 1)); - } - private: - GuiAppState *state; - - class ReturnButton : public Button { - public: - - ReturnButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", -1, separate) { - this->state = state; - } - - void onClick() { - state->removeAllCheckboxes(); - state->removeAllListboxes(); - state->removeAllSliders(); - state->removeAllTextboxes(); - state->removeButton("Controls"); - state->removeButton("Mouse"); - state->removeButton("Video"); - state->removeButton("Audio"); - state->removeButton("Multiplayer"); - GameManager *gm = GameManager::getSingleton(); - SpButton *spButton = new SpButton(state, Vector2(gm->getWidth() / 16, gm->getHeight() / 12), Vector2(150, 40), "Singleplayer", true); - MainMenuOptionsButton *optionsButton = new MainMenuOptionsButton(state, Vector2(gm->getWidth() / 16, gm->getHeight() / 12 * 2), Vector2(150, 40), "Options", true); - state->addButton(optionsButton); - ExitButton *exitButton = new ExitButton(Vector2(gm->getWidth() / 16, gm->getHeight() / 12 * 3), Vector2(150, 40)); - state->addButton(spButton); - state->addButton(exitButton); - state->removeButton("Back"); - } - private: - GuiAppState *state; - }; - }; - - GameManager *gm = GameManager::getSingleton(); - string font = gm->getPath() + "Fonts/batang.ttf"; - int width = gm->getWidth(), height = gm->getHeight(); - Vector2 size = Vector2(150, 40); - - AssetManager::getSingleton()->load(font); - - SpButton *spButton = new SpButton(state, Vector2(width / 16, height / 12), size, "Singleplayer", true); - MainMenuOptionsButton *optionsButton = new MainMenuOptionsButton(state, Vector2(width / 16, height / 12 * 2), size, "Options", true); - MapEditorButton *editorButton = new MapEditorButton(Vector2(width / 16, height / 12 * 3), size); - ExitButton *exitButton = new ExitButton(Vector2(width / 16, height / 12 * 4), size); - state->addButton(spButton); - state->addButton(optionsButton); - state->addButton(editorButton); - state->addButton(exitButton); - */ - } + float pointToPlane = dirVec.getLength() * sin(baseAngle); + return (dirVec + upVec * pointToPlane * (acuteAngle ? -1 : 1)).norm(); + } + else return dirVec.norm(); + } vector readDir(string path, bool findFolders){ tinydir_dir dir; diff --git a/util.h b/util.h index 09ddf25..64075a8 100755 --- a/util.h +++ b/util.h @@ -26,7 +26,7 @@ namespace battleship{ class LoadingAppState; void handleLoadingGui(LoadingAppState*); - void makeTitlescreenButtons(GuiAppState*); + vb01::Vector3 getVecToPlane(vb01::Vector3, vb01::Vector3, vb01::Vector3); std::vector readDir(std::string, bool); vb01::Vector2 spaceToScreen(vb01::Vector3); vb01::Vector3 spaceToScreen3d(vb01::Vector3); diff --git a/vehicle.cpp b/vehicle.cpp index ee9faab..3226ecd 100644 --- a/vehicle.cpp +++ b/vehicle.cpp @@ -233,21 +233,8 @@ namespace battleship{ } void Vehicle::navigate(float destOffset){ - Vector3 hypVec = (pathPoints[0] - pos), baseDir; - float baseAngle = upVec.getAngleBetween(hypVec.norm()); - - if(fabs(baseAngle - PI / 2) > .001){ - bool acuteAngle = (baseAngle < PI / 2); - - if(acuteAngle) baseAngle = PI / 2 - baseAngle; - else baseAngle -= PI / 2; - - float pointToPlane = hypVec.getLength() * sin(baseAngle); - baseDir = (pathPoints[0] + upVec * pointToPlane * (acuteAngle ? -1 : 1) - pos).norm(); - } - else - baseDir = hypVec.norm(); - + Vector3 hypVec = (pathPoints[0] - pos); + Vector3 baseDir = getVecToPlane(pos, hypVec, upVec); float angle = baseDir.getAngleBetween(dirVec); if(angle > anglePrecision && pos.getDistanceFrom(pathPoints[0]) > destOffset) diff --git a/weapon.cpp b/weapon.cpp index 83f72c7..f4239df 100644 --- a/weapon.cpp +++ b/weapon.cpp @@ -3,6 +3,7 @@ #include #include "map.h" +#include "util.h" #include "weapon.h" #include "player.h" #include "fxManager.h" @@ -96,27 +97,6 @@ namespace battleship{ if(fireFx) fm->removeFx(fireFx); } - Vector3 Weapon::calcOrientVec(int id){ - Vector3 orientVec; - - switch(id){ - case 0: - orientVec = unit->getDirVec(); - break; - case 1: - orientVec = unit->getLeftVec(); - break; - case 2: - orientVec = unit->getUpVec(); - break; - } - - if(horNode) orientVec = horNode->getOrientation() * orientVec; - if(vertNode) orientVec = vertNode->getOrientation() * orientVec; - - return orientVec; - } - //TODO replace unit pos with absolute weapon pos for withinAngle void Weapon::update(){ if(unit->getCondition() != Unit::Condition::ABLE) return; @@ -130,9 +110,12 @@ namespace battleship{ float targDist = unit->getPos().getDistanceFrom(targPos); bool withinRange = (minRange <= targDist && targDist <= maxRange); + bool withinAngle = true; - Vector3 dirVec = calcOrientVec(0); - bool withinAngle = (horNode ? Vector3(dirVec.x, 0, dirVec.z).norm().getAngleBetween((targPos - unit->getPos()).norm()) <= maxFireAngle : true); + if(horNode){ + Vector3 dirVec = horNode->getGlobalAxis(2); + withinAngle = Vector3(dirVec.x, 0, dirVec.z).norm().getAngleBetween((targPos - unit->getPos()).norm()) <= maxFireAngle; + } if((Order::TYPE)ordTp == Order::TYPE::ATTACK && withinRange && withinAngle) fire(unit->getOrder(0)); @@ -224,26 +207,22 @@ namespace battleship{ } //TODO improve to allow for vertical alignment - void Weapon::alignNode(Vector3 targPos, Node *node, bool horizontal){ - Vector3 targDir = targPos - unit->getPos(); - Vector3 targDirHor = Vector3(targDir.x, 0, targDir.z).norm(), targDirVert; + void Weapon::trackTarget(Vector3 targPos){ + if(!horNode) return; - Vector3 dirVec = calcOrientVec(0); - Vector3 dirVecHor = Vector3(dirVec.x, 0, dirVec.z).norm(), dirVecVert; + Vector3 unitPos = unit->getPos(); + Vector3 targDir = (targPos - unitPos).norm(); + targDir = getVecToPlane(unitPos, targDir, unit->getUpVec()); - Vector3 leftVec = calcOrientVec(1); - bool negate = (Vector3(leftVec.x, 0, leftVec.z).norm().getAngleBetween(targDirHor) < PI / 2); + Vector3 dirVec = getVecToPlane(unitPos, horNode->getGlobalAxis(2), unit->getUpVec()); + Vector3 leftVec = horNode->getGlobalAxis(0); + bool negate = (leftVec.getAngleBetween(targDir) < PI / 2); - float angle = dirVecHor.getAngleBetween(targDirHor); + float angle = dirVec.getAngleBetween(targDir); float rotAngle = (rotSpeed < angle ? rotSpeed : angle); - Quaternion rot = Quaternion((negate ? 1 : -1) * rotAngle, unit->getUpVec()) * node->getOrientation(); - node->setOrientation(rot); - } - - void Weapon::trackTarget(Vector3 targPos){ - if(horNode) alignNode(targPos, horNode, true); - //if(vertNode) alignNode(targPos, vertNode, false); + Quaternion rot = Quaternion((negate ? 1 : -1) * rotAngle, Vector3::VEC_J) * horNode->getOrientation(); + horNode->setOrientation(rot); } CryoGun::CryoGun(Unit *u, sol::table unitTable, int wid) : Weapon(u, unitTable, wid){} diff --git a/weapon.h b/weapon.h index e734b76..31f9ad8 100644 --- a/weapon.h +++ b/weapon.h @@ -45,8 +45,6 @@ namespace battleship{ vb01::Node *horNode = nullptr, *vertNode = nullptr, *projPar = nullptr; static std::string LASER_FLAG; - vb01::Vector3 calcOrientVec(int); - void alignNode(vb01::Vector3, vb01::Node*, bool); void initProjectileData(sol::table); vb01::Node* initNode(sol::table, bool); void useFx(FxManager::Fx*, vb01::Vector3, bool);