From 64af255c0e8b5480f47a0d922f0f5d1c56adb1f3 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Sat, 16 Sep 2017 19:51:07 +0800 Subject: [PATCH] Add basic 3D level selection --- CMakeLists.txt | 2 + src/application.cpp | 232 ++++++++++++++++++++---------- src/application.hpp | 36 +++-- src/configuration.hpp.in | 10 +- src/game/level.cpp | 91 +++++++----- src/game/level.hpp | 70 +++++++-- src/states/level-select-state.cpp | 86 +++++++++++ src/states/level-select-state.hpp | 42 ++++++ src/states/play-state.cpp | 21 +-- 9 files changed, 438 insertions(+), 152 deletions(-) create mode 100644 src/states/level-select-state.cpp create mode 100644 src/states/level-select-state.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c97cad..46d7461 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,6 +192,8 @@ set(EXECUTABLE_SOURCES ${EXECUTABLE_SOURCE_DIR}/application-state.cpp ${EXECUTABLE_SOURCE_DIR}/application.hpp ${EXECUTABLE_SOURCE_DIR}/application.cpp + ${EXECUTABLE_SOURCE_DIR}/states/level-select-state.hpp + ${EXECUTABLE_SOURCE_DIR}/states/level-select-state.cpp ${EXECUTABLE_SOURCE_DIR}/states/loading-state.hpp ${EXECUTABLE_SOURCE_DIR}/states/loading-state.cpp ${EXECUTABLE_SOURCE_DIR}/states/splash-state.hpp diff --git a/src/application.cpp b/src/application.cpp index 0c0b1e9..af21471 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -25,12 +25,14 @@ #include "states/splash-state.hpp" #include "states/title-state.hpp" #include "states/main-menu-state.hpp" +#include "states/level-select-state.hpp" #include "states/play-state.hpp" #include "game/colony.hpp" #include "ui/toolbar.hpp" #include "ui/pie-menu.hpp" #include "debug.hpp" #include "camera-controller.hpp" +#include "configuration.hpp" #include #include #include @@ -322,6 +324,7 @@ Application::Application(int argc, char* argv[]): splashState = new SplashState(this); titleState = new TitleState(this); mainMenuState = new MainMenuState(this); + levelSelectState = new LevelSelectState(this); playState = new PlayState(this); // Setup loaders @@ -587,8 +590,9 @@ bool Application::loadModels() antHillModel = modelLoader->load("data/models/ant-hill.mdl"); nestModel = modelLoader->load("data/models/nest.mdl"); forcepsModel = modelLoader->load("data/models/forceps.mdl"); + levelPlaceholderModel = modelLoader->load("data/models/level-placeholder.mdl"); - if (!antModel || !antHillModel || !nestModel) + if (!antModel || !antHillModel || !nestModel || !forcepsModel) { return false; } @@ -600,8 +604,10 @@ bool Application::loadModels() nestModelInstance.setModel(nestModel); forcepsModelInstance.setModel(forcepsModel); - // Create terrain - terrain.create(255, 255, Vector3(50, 20, 50)); + for (int i = 0; i < 5; ++i) + { + levelPlaceholderModelInstances[i].setModel(levelPlaceholderModel); + } return true; } @@ -984,36 +990,6 @@ bool Application::loadUI() quitToDesktopLabel->setTranslation(Vector2(0.0f, menuFont->getMetrics().getHeight() * 2)); pauseMenuContainer->addChild(quitToDesktopLabel); - // Create level selector elements - levelSelectorContainer = new UIContainer(); - levelSelectorContainer->setDimensions(Vector2(levelActiveTexture->getWidth() * 10 + 48 * 9, levelActiveTexture->getHeight())); - levelSelectorContainer->setAnchor(Vector2(0.5f, 1.0f)); - levelSelectorContainer->setTranslation(Vector2(0.0f, -levelActiveTexture->getHeight())); - levelSelectorContainer->setVisible(false); - levelSelectorContainer->setActive(false); - uiRootElement->addChild(levelSelectorContainer); - for (int i = 0; i < 10; ++i) - { - levelSelections[i] = new UIImage(); - levelSelections[i]->setAnchor(Vector2(0.0f, 0.5f)); - levelSelections[i]->setDimensions(Vector2(levelActiveTexture->getWidth(), levelActiveTexture->getHeight())); - levelSelections[i]->setTranslation(Vector2(i * 96.0f, 0.0f)); - levelSelections[i]->setTexture(levelInactiveTexture); - levelSelections[i]->setVisible(true); - levelSelectorContainer->addChild(levelSelections[i]); - - if (i < 9) - { - levelConnectors[i] = new UIImage(); - levelConnectors[i]->setAnchor(Vector2(0.0f, 0.5f)); - levelConnectors[i]->setDimensions(Vector2(levelConnectorTexture->getWidth(), levelConnectorTexture->getHeight())); - levelConnectors[i]->setTranslation(Vector2((i + 1) * 96.0f - 50.0f, 0.0f)); - levelConnectors[i]->setTexture(levelConnectorTexture); - levelConnectors[i]->setVisible(true); - levelSelectorContainer->addChild(levelConnectors[i]); - } - } - // Create pause/play button elements pauseButtonImage = new UIImage(); pauseButtonImage->setAnchor(Vector2(0.0f, 1.0f)); @@ -1145,10 +1121,6 @@ bool Application::loadUI() Vector2 menuSlideInStartTranslation = Vector2(-64.0f, 0.0f); Vector2 menuSlideInDeltaTranslation = Vector2((int)(64.0f + width / 8.0f), 0.0f); - float levelSelectorSlideInDuration = 0.35f; - Vector2 levelSelectorSlideInStartTranslation = Vector2(0.0f, levelActiveTexture->getHeight()); - Vector2 levelSelectorSlideInDeltaTranslation = Vector2(0.0f, -levelActiveTexture->getHeight() * 2.0f); - // Setup main menu tween menuFadeInTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, menuFadeInDuration, menuFadeInStartColor, menuFadeInDeltaColor); tweener->addTween(menuFadeInTween); @@ -1157,10 +1129,6 @@ bool Application::loadUI() menuSlideInTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, menuSlideInDuration, menuSlideInStartTranslation, menuSlideInDeltaTranslation); tweener->addTween(menuSlideInTween); - // Setup level selector tween - levelSelectorSlideInTween = new Tween(EaseFunction::OUT_QUINT, 0.0f, levelSelectorSlideInDuration, levelSelectorSlideInStartTranslation, levelSelectorSlideInDeltaTranslation); - tweener->addTween(levelSelectorSlideInTween); - // Title screen zoom in tween antHillZoomInTween = new Tween(EaseFunction::LINEAR, 0.0f, 2.0f, 50.0f, -49.9f); antHillZoomInTween->setUpdateCallback(std::bind(&SurfaceCameraController::setTargetFocalDistance, surfaceCam, std::placeholders::_1)); @@ -1176,6 +1144,10 @@ bool Application::loadUI() playButtonFadeTween->setEndCallback(std::bind(&UIElement::setVisible, playButtonImage, false)); tweener->addTween(playButtonFadeTween); + // Camera translation tween + cameraTranslationTween = new Tween(EaseFunction::OUT_CUBIC, 0.0f, 0.0f, Vector3(0.0f), Vector3(0.0f)); + tweener->addTween(cameraTranslationTween); + // Build menu system selectedMenuItemIndex = 0; mainMenu = new Menu(); @@ -1286,20 +1258,6 @@ bool Application::loadUI() selectedMenuItemIndex = 0; selectMenuItem(selectedMenuItemIndex); - currentLevel = 0; - levelSelectorMenu = new Menu(); - for (int i = 0; i < 10; ++i) - { - MenuItem* levelSelectionItem = levelSelectorMenu->addItem(); - levelSelectionItem->setSelectedCallback(std::bind(&UIImage::setTexture, levelSelections[i], levelActiveTexture)); - levelSelectionItem->setDeselectedCallback(std::bind(&UIImage::setTexture, levelSelections[i], levelInactiveTexture)); - levelSelectionItem->setActivatedCallback(std::bind(&Application::loadLevel, this)); - - levelSelections[i]->setMouseOverCallback(std::bind(&Application::selectLevel, this, levelSelectionItem->getIndex())); - levelSelections[i]->setMouseMovedCallback(std::bind(&Application::selectLevel, this, levelSelectionItem->getIndex())); - levelSelections[i]->setMousePressedCallback(std::bind(&Application::activateLevel, this, levelSelectionItem->getIndex())); - } - // Setup UI batch uiBatch = new BillboardBatch(); uiBatch->resize(512); @@ -1395,17 +1353,25 @@ bool Application::loadControls() bool Application::loadGame() { - - // Load biosphere biosphere.load("data/biomes/"); // Load campaign campaign.load("data/levels/"); - currentWorld = 1; - currentLevel = 1; + currentWorldIndex = 0; + currentLevelIndex = 0; + for (int i = 0; i < 5; ++i) + { + previewLevelIndices[i] = oldPreviewLevelIndices[i] = i; + } simulationPaused = false; + // Allocate levels and initialize pointers + for (int i = 0; i < 5; ++i) + { + previewLevels[i] = new Level(); + } + // Create colony colony = new Colony(); colony->setAntModel(antModel); @@ -1502,19 +1468,15 @@ void Application::enterLevelSelection() { exitMenu(0); - currentWorld = 1; - currentLevel = 1; + // Reset world and level indices + currentWorldIndex = 0; + currentLevelIndex = 0; - // Start menu slide-in tween - levelSelectorSlideInTween->setUpdateCallback(std::bind(&UIElement::setTranslation, levelSelectorContainer, std::placeholders::_1)); - levelSelectorSlideInTween->reset(); - levelSelectorSlideInTween->start(); - - // Make menu visible and active - levelSelectorContainer->setVisible(true); - levelSelectorContainer->setActive(true); + // Change to level select state + changeState(levelSelectState); } +/* void Application::selectLevel(std::size_t index) { if (index > levelSelectorMenu->getItemCount()) @@ -1543,7 +1505,130 @@ void Application::activateLevel(std::size_t index) //levelSelectorMenu->getItem(currentLevel - 1)->deselect(); levelSelectorMenu->getItem(currentLevel - 1)->activate(); } +*/ + +// Level count: 16 +// Max loaded levels: 5 + +// 0: [ 0] 1 2 3 4 +// 1: 0 [ 1] 2 3 4 +// 2: 0 1 [ 2] 3 4 + +// 3: 5 1 2 [ 3] 4 +// 4: 5 6 2 3 [ 4] +// 5: [ 5] 6 7 3 4 +// 6: 5 [ 6] 7 8 4 +// 7: 5 6 [ 7] 8 9 +// 8: 10 6 7 [ 8] 9 +// 9: 10 11 7 8 [ 9] +//10: [10] 11 12 8 9 +//11: 10 [11] 12 13 9 +//12: 10 11 [12] 13 14 + +//13: 15 11 12 [13] 14 +//14: 15 11 12 13 [14] +//15: [15] 11 12 13 14 + +// pointer index = currentLevel % 5; + + + + +void Application::selectLevel(std::size_t index) +{ + // Set current level + currentLevelIndex = static_cast(index); + + // Calculate index of current loaded level + currentPreviewIndex = (currentLevelIndex % 5); + + // Get total number of levels in the current world + int levelCount = campaign.getLevelCount(currentWorldIndex); + + // Calculate indices of level previews + previewLevelIndices[(currentPreviewIndex + 3) % 5] = (currentLevelIndex <= 2) ? ((currentLevelIndex + 3) % 5) : currentLevelIndex - 2; + previewLevelIndices[(currentPreviewIndex + 4) % 5] = (currentLevelIndex <= 2) ? ((currentLevelIndex + 4) % 5) : currentLevelIndex - 1; + previewLevelIndices[(currentPreviewIndex + 0) % 5] = currentLevelIndex; + previewLevelIndices[(currentPreviewIndex + 1) % 5] = (currentLevelIndex >= levelCount - 1) ? (((currentLevelIndex + 1) % (levelCount - 1)) + ((levelCount - 1) - 5)) : currentLevelIndex + 1; + previewLevelIndices[(currentPreviewIndex + 2) % 5] = (currentLevelIndex >= levelCount - 2) ? (((currentLevelIndex + 2) % (levelCount - 1)) + ((levelCount - 1) - 5)) : currentLevelIndex + 2; + + // Load unloaded previews + for (int i = 0; i < 5; ++i) + { + if (oldPreviewLevelIndices[i] != previewLevelIndices[i]) + { + std::cout << "Unloaded level " << oldPreviewLevelIndices[i] << std::endl; + std::cout << "Loaded level " << previewLevelIndices[i] << std::endl; + } + } + + // Load unloaded previews + for (int i = 0; i < 5; ++i) + { + if (oldPreviewLevelIndices[i] != previewLevelIndices[i]) + { + oldPreviewLevelIndices[i] = previewLevelIndices[i]; + + // Load preview + } + + if (currentPreviewIndex == i) + { + std::cout << " [" << previewLevelIndices[i] << "] "; + } + else + { + std::cout << " " << previewLevelIndices[i] << " "; + } + } + std::cout << std::endl; + + // Perform tweening + for (int i = 0; i < 5; ++i) + { + levelPlaceholderModelInstances[i].setTranslation(Vector3(4.0f, 0.0f, 0.0f) * static_cast(previewLevelIndices[i])); + } +} + +void Application::selectNextLevel() +{ + if (currentLevelIndex < campaign.getLevelCount(currentWorldIndex) - 1) + { + selectLevel(currentLevelIndex + 1); + + // Setup camera tween + cameraTranslationTween->setTime(0.0f); + cameraTranslationTween->setDuration(0.125f); + cameraTranslationTween->setStartValue(camera.getTranslation()); + cameraTranslationTween->setDeltaValue(Vector3(4.0f, 0.0f, 0.0f)); + cameraTranslationTween->setUpdateCallback(std::bind(&SceneObject::setTranslation, &camera, std::placeholders::_1)); + cameraTranslationTween->start(); + } +} + +void Application::selectPreviousLevel() +{ + if (currentLevelIndex > 0) + { + selectLevel(currentLevelIndex - 1); + + // Setup camera tween + cameraTranslationTween->setTime(0.0f); + cameraTranslationTween->setDuration(0.125f); + cameraTranslationTween->setStartValue(camera.getTranslation()); + cameraTranslationTween->setDeltaValue(Vector3(-4.0f, 0.0f, 0.0f)); + cameraTranslationTween->setUpdateCallback(std::bind(&SceneObject::setTranslation, &camera, std::placeholders::_1)); + cameraTranslationTween->start(); + } +} + +void Application::enterSelectedLevel() +{ + +} + +/* void Application::loadLevel() { if (currentLevel < 1 || currentLevel >= campaign.levels[currentWorld].size()) @@ -1552,8 +1637,8 @@ void Application::loadLevel() return; } - const Level* level = &campaign.levels[currentWorld][currentLevel]; - const Biome* biome = &biosphere.biomes[level->biome]; + const LevelParameterSet* levelParams = campaign.getLevelParams(currentWorld, currentLevel); + const Biome* biome = &biosphere.biomes[levelParams->biome]; soilPass.setHorizonOTexture(biome->soilHorizonO); soilPass.setHorizonATexture(biome->soilHorizonA); @@ -1561,13 +1646,14 @@ void Application::loadLevel() soilPass.setHorizonCTexture(biome->soilHorizonC); std::string heightmap = std::string("data/textures/") + level->heightmap; - terrain.load(heightmap); + currentLevelTerrain->load(heightmap); // Set skybox skyboxPass.setCubemap(biome->specularCubemap); - changeState(playState); + //changeState(playState); } +*/ void Application::pauseSimulation() { diff --git a/src/application.hpp b/src/application.hpp index 4ca7ed6..b2ac9bc 100644 --- a/src/application.hpp +++ b/src/application.hpp @@ -43,6 +43,7 @@ class SplashState; class TitleState; class MainMenuState; class PlayState; +class LevelSelectState; class CameraController; class SurfaceCameraController; class TunnelCameraController; @@ -92,11 +93,15 @@ public: void activateMenuItem(std::size_t index); void selectLevel(std::size_t index); - void activateLevel(std::size_t index); + void selectNextLevel(); + void selectPreviousLevel(); + void enterSelectedLevel(); + + //void activateLevel(std::size_t index); void enterLevelSelection(); - void loadLevel(); + void pauseSimulation(); void unpauseSimulation(); @@ -135,6 +140,7 @@ public: SplashState* splashState; TitleState* titleState; MainMenuState* mainMenuState; + LevelSelectState* levelSelectState; PlayState* playState; // Scene @@ -154,6 +160,7 @@ public: ModelInstance antModelInstance; ModelInstance antHillModelInstance; ModelInstance nestModelInstance; + ModelInstance levelPlaceholderModelInstances[5]; // Graphics Renderer renderer; @@ -290,9 +297,6 @@ public: UILabel* pausedSettingsLabel; UILabel* returnToMainMenuLabel; UILabel* quitToDesktopLabel; - UIContainer* levelSelectorContainer; - UIImage* levelSelections[10]; - UIImage* levelConnectors[9]; UIImage* pauseButtonImage; UIImage* playButtonImage; UIImage* rectangularPaletteImage; @@ -320,12 +324,13 @@ public: Tween* menuFadeInTween; Tween* menuFadeOutTween; Tween* menuSlideInTween; - Tween* levelSelectorSlideInTween; Tween* antHillZoomInTween; Tween* antHillFadeOutTween; Tween* playButtonFadeTween; + Tween* cameraTranslationTween; + // Menus std::size_t menuCount; Menu** menus; @@ -337,20 +342,29 @@ public: Menu* challengeMenu; Menu* experimentMenu; Menu* settingsMenu; - Menu* levelSelectorMenu; // Models Model* antModel; Model* antHillModel; Model* nestModel; Model* forcepsModel; + Model* levelPlaceholderModel; // Game variables - Campaign campaign; - int currentWorld; - int currentLevel; Biosphere biosphere; - Terrain terrain; + Campaign campaign; + + int currentWorldIndex; + int currentLevelIndex; + + int currentPreviewIndex; + int previewLevelIndices[5]; + int oldPreviewLevelIndices[5]; + Level* previewLevels[5]; + Level* currentLevel; + + + Colony* colony; SurfaceCameraController* surfaceCam; TunnelCameraController* tunnelCam; diff --git a/src/configuration.hpp.in b/src/configuration.hpp.in index 358f276..0721ef4 100644 --- a/src/configuration.hpp.in +++ b/src/configuration.hpp.in @@ -26,11 +26,9 @@ #define ANTKEEPER_VERSION_STRING "@ANTKEEPER_VERSION@" #cmakedefine ANTKEEPER_DEBUG -#if defined(ANTKEEPER_DEBUG) - #define ANTKEEPER_FIRST_WORLD_INDEX 0 -#else - #define ANTKEEPER_FIRST_WORLD_INDEX 1 -#endif -#define ANTKEEPER_FIRST_LEVEL_INDEX 1 +// Terrain dimensions +const float ANTKEEPER_TERRAIN_WIDTH = 50.0f; +const float ANTKEEPER_TERRAIN_BASE_HEIGHT = 35.7f; +const float ANTKEEPER_TERRAIN_DEPTH = 50.0f; #endif // CONFIGURATION_HPP diff --git a/src/game/level.cpp b/src/game/level.cpp index 3979c18..51a10ac 100644 --- a/src/game/level.cpp +++ b/src/game/level.cpp @@ -1,20 +1,21 @@ #include "level.hpp" #include "../settings.hpp" +#include "../configuration.hpp" #include #include #include -Level::Level(): - worldIndex(-1), - levelIndex(-1) +LevelParameterSet::LevelParameterSet() {} -Level::~Level() +LevelParameterSet::~LevelParameterSet() {} -bool Level::load() +bool LevelParameterSet::load(const std::string& filename) { + this->filename = filename; + ParameterDict parameters; if (!parameters.load(filename)) { @@ -27,6 +28,37 @@ bool Level::load() return true; } +Level::Level() +{ + terrain.create(255, 255, Vector3(ANTKEEPER_TERRAIN_WIDTH, ANTKEEPER_TERRAIN_BASE_HEIGHT, ANTKEEPER_TERRAIN_DEPTH)); +} + +Level::~Level() +{} + +bool Level::load(const LevelParameterSet& params) +{ + // Load terrain from heightmap + std::string heightmapFilename = std::string("data/textures/") + params.heightmap; + if (!terrain.load(heightmapFilename)) + { + std::cerr << "Failed to load terrain from heightmap file \"" << heightmapFilename << "\" for level \"" << params.filename << "\"" << std::endl; + return false; + } + + //application->currentLevelTerrain->getSurfaceModel()->getGroup(0)->material = application->materialLoader->load("data/materials/debug-terrain-surface.mtl"); + + // Setup terrain surface model instance + terrainSurface.setModel(terrain.getSurfaceModel()); + terrainSurface.setTranslation(Vector3(0, 0, 0)); + + // Setup terrain subsurface model instance + terrainSubsurface.setModel(terrain.getSubsurfaceModel()); + terrainSubsurface.setTranslation(Vector3(0, 0, 0)); + + return true; +} + Campaign::Campaign() {} @@ -72,57 +104,46 @@ bool Campaign::load(const std::string& directory) std::stringstream stream; stream << worldIndexString; stream >> worldIndex; + worldIndex -= 1; stream.str(std::string()); stream.clear(); stream << levelIndexString; stream >> levelIndex; + levelIndex -= 1; if (worldIndex < 0 || levelIndex < 0) { - std::cout << "Invalid level \"" << filename << "\"" << std::endl; + std::cout << "Invalid level parameters file \"" << filename << "\"" << std::endl; continue; } // Resize vector to accommodate maximum world index - if (worldIndex >= static_cast(levels.size())) + if (worldIndex >= static_cast(levelParameterSets.size())) { - levels.resize(worldIndex + 1); + levelParameterSets.resize(worldIndex + 1); } - // Resize vector to accommodate maximum level index - if (levelIndex >= static_cast(levels[worldIndex].size())) + // Resize vector to accommodate maximum level file index + if (levelIndex >= static_cast(levelParameterSets[worldIndex].size())) { - levels[worldIndex].resize(levelIndex + 1); + levelParameterSets[worldIndex].resize(levelIndex + 1); } - // Add level - Level* level = &levels[worldIndex][levelIndex]; - level->filename = directory + filename; - level->worldIndex = worldIndex; - level->levelIndex = levelIndex; + // Load level parameters + LevelParameterSet* levelParams = &levelParameterSets[worldIndex][levelIndex]; + if (!levelParams->load(directory + filename)) + { + std::cout << "Failed to load parameters for level " << (worldIndex + 1) << "-" << (levelIndex + 1) << std::endl; + } + else + { + std::cout << "Loaded level parameters for level " << (worldIndex + 1) << "-" << (levelIndex + 1) << std::endl; + } } // Close levels directory closedir(dir); - // Load levels - for (std::size_t i = ANTKEEPER_FIRST_WORLD_INDEX; i < levels.size(); ++i) - { - for (std::size_t j = ANTKEEPER_FIRST_LEVEL_INDEX; j < levels[i].size(); ++j) - { - Level* level = &levels[i][j]; - - if (!level->load()) - { - std::cout << "Failed to load level " << i << "-" << j << std::endl; - } - else - { - std::cout << "Loaded level " << i << "-" << j << std::endl; - } - } - } - return true; -} \ No newline at end of file +} diff --git a/src/game/level.hpp b/src/game/level.hpp index 906d4cb..5b1eab8 100644 --- a/src/game/level.hpp +++ b/src/game/level.hpp @@ -1,35 +1,83 @@ -#ifndef LEVEL_SELECTOR_HPP -#define LEVEL_SELECTOR_HPP +#ifndef LEVEL_HPP +#define LEVEL_HPP #include "../configuration.hpp" +#include "terrain.hpp" #include #include -class Level +/** + * Contains the parameters required to load a level. + */ +class LevelParameterSet { public: - Level(); - ~Level(); + LevelParameterSet(); + ~LevelParameterSet(); - bool load(); + // Loads level parameters from a .lvl file + bool load(const std::string& filename); std::string filename; - int worldIndex; - int levelIndex; - std::string biome; std::string heightmap; }; +/** + * A level. + */ +class Level +{ +public: + Level(); + ~Level(); + + // Loads a level from a level file + bool load(const LevelParameterSet& params); + + Terrain terrain; + ModelInstance terrainSurface; + ModelInstance terrainSubsurface; +}; + +/** + * A collection of level parameters which constitute a campaign. + */ class Campaign { public: Campaign(); ~Campaign(); + // Loads all level parameter sets in a directory with the file name pattern `-.lvl` bool load(const std::string& directory); - std::vector> levels; + // Returns the number of worlds in the campaign + std::size_t getWorldCount() const; + + // Returns the number of levels in a world + std::size_t getLevelCount(std::size_t worldIndex) const; + + // Returns the file for the level with the specified indices + const LevelParameterSet* getLevelParams(std::size_t worldIndex, std::size_t levelIndex) const; + +private: + std::vector> levelParameterSets; }; -#endif // LEVEL_SELECTOR_HPP +inline std::size_t Campaign::getWorldCount() const +{ + return levelParameterSets.size(); +} + +inline std::size_t Campaign::getLevelCount(std::size_t worldIndex) const +{ + return levelParameterSets[worldIndex].size(); +} + +inline const LevelParameterSet* Campaign::getLevelParams(std::size_t worldIndex, std::size_t levelIndex) const +{ + return &levelParameterSets[worldIndex][levelIndex]; +} + +#endif // LEVEL_HPP diff --git a/src/states/level-select-state.cpp b/src/states/level-select-state.cpp new file mode 100644 index 0000000..895586f --- /dev/null +++ b/src/states/level-select-state.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#include "level-select-state.hpp" +#include "../application.hpp" + +LevelSelectState::LevelSelectState(Application* application): + ApplicationState(application) +{} + +LevelSelectState::~LevelSelectState() +{} + +void LevelSelectState::enter() +{ + for (int i = 0; i < 5; ++i) + { + ModelInstance* instance = &application->levelPlaceholderModelInstances[i]; + application->defaultLayer->addObject(instance); + } + application->camera.lookAt(Vector3(0, 10, 20), Vector3(0, 1, 0), Vector3(0, 1, 0)); + + application->selectLevel(0); + + levelRotation = 0.0f; +} + +void LevelSelectState::execute() +{ + // Navigate menu + if (application->menuLeft.isTriggered() && !application->menuLeft.wasTriggered()) + { + application->selectPreviousLevel(); + } + else if (application->menuRight.isTriggered() && !application->menuRight.wasTriggered()) + { + application->selectNextLevel(); + } + + if (application->menuDown.isTriggered() && !application->menuDown.wasTriggered()) + { + + } + else if (application->menuUp.isTriggered() && !application->menuUp.wasTriggered()) + { + + } + + if (application->menuSelect.isTriggered() && !application->menuSelect.wasTriggered()) + { + application->enterSelectedLevel(); + } + else if (application->menuCancel.isTriggered() && !application->menuCancel.wasTriggered()) + { + + } + + // Rotate levels + levelRotation += glm::radians(5.0f) * application->dt; + for (int i = 0; i < 5; ++i) + { + ModelInstance* instance = &application->levelPlaceholderModelInstances[i]; + instance->setRotation(glm::angleAxis(levelRotation, Vector3(0, 1, 0))); + } +} + +void LevelSelectState::exit() +{ + +} diff --git a/src/states/level-select-state.hpp b/src/states/level-select-state.hpp new file mode 100644 index 0000000..687bd1b --- /dev/null +++ b/src/states/level-select-state.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#ifndef LEVEL_SELECT_STATE_HPP +#define LEVEL_SELECT_STATE_HPP + +#include "../application-state.hpp" + +#include +using namespace Emergent; + +class LevelSelectState: public ApplicationState +{ +public: + LevelSelectState(Application* application); + virtual ~LevelSelectState(); + + virtual void enter(); + virtual void execute(); + virtual void exit(); + +private: + float levelRotation; +}; + +#endif // LEVEL_SELECT_STATE_HPP diff --git a/src/states/play-state.cpp b/src/states/play-state.cpp index ef1bce3..5930455 100644 --- a/src/states/play-state.cpp +++ b/src/states/play-state.cpp @@ -34,10 +34,6 @@ PlayState::~PlayState() void PlayState::enter() { - // Hide level selector - application->levelSelectorContainer->setVisible(false); - application->levelSelectorContainer->setActive(false); - // Setup HUD application->pauseButtonImage->setVisible(false); application->pauseButtonImage->setActive(false); @@ -55,22 +51,15 @@ void PlayState::enter() //application->backgroundLayer->addObject(&application->bgCamera); //application->backgroundLayer->addObject(&application->bgBatch); - // Create terrain model instances - application->terrain.getSurfaceModel()->getGroup(0)->material = application->materialLoader->load("data/materials/debug-terrain-surface.mtl"); - terrainSurface.setModel(application->terrain.getSurfaceModel()); - terrainSurface.setTranslation(Vector3(0, 0, 0)); - terrainSubsurface.setModel(application->terrain.getSubsurfaceModel()); - terrainSubsurface.setTranslation(Vector3(0, 0, 0)); - // Add terrain to scene - application->defaultLayer->addObject(&terrainSurface); - application->defaultLayer->addObject(&terrainSubsurface); + application->defaultLayer->addObject(&application->currentLevel->terrainSurface); + application->defaultLayer->addObject(&application->currentLevel->terrainSubsurface); // Add forceps to scene application->defaultLayer->addObject(&application->forcepsModelInstance); // Spawn ants - Navmesh* navmesh = application->terrain.getSurfaceNavmesh(); + Navmesh* navmesh = application->currentLevel->terrain.getSurfaceNavmesh(); for (int i = 0; i < 50; ++i) { Navmesh::Triangle* triangle = (*navmesh->getTriangles())[0]; @@ -178,7 +167,7 @@ void PlayState::execute() pickingRay.direction = glm::normalize(mouseFar - mouseNear); std::list triangles; - application->terrain.getSurfaceOctree()->query(pickingRay, &triangles); + application->currentLevel->terrain.getSurfaceOctree()->query(pickingRay, &triangles); auto result = intersects(pickingRay, triangles); if (std::get<0>(result)) @@ -186,7 +175,7 @@ void PlayState::execute() pick = pickingRay.extrapolate(std::get<1>(result)); std::size_t triangleIndex = std::get<3>(result); - pickTriangle = (*application->terrain.getSurfaceNavmesh()->getTriangles())[triangleIndex]; + pickTriangle = (*application->currentLevel->terrain.getSurfaceNavmesh()->getTriangles())[triangleIndex]; float forcepsDistance = (application->forcepsClosed) ? 0.0f : 0.5f;