From 1dcea72e6a84eb24d079dc04052bf00e82935b6b Mon Sep 17 00:00:00 2001 From: Allan Legemaate Date: Sat, 29 Mar 2025 15:13:38 -0400 Subject: [PATCH] feat: use latest asw --- .clang-tidy | 25 ++++++++ .github/workflows/deploy.yml | 37 ++++++----- .github/workflows/sonar.yml | 62 ------------------ .gitignore | 4 +- .gitmodules | 3 - .vscode/c_cpp_properties.json | 12 ---- .vscode/tasks.json | 2 +- CMakeLists.txt | 75 ++++++++-------------- README.md | 31 +-------- index.html | 39 +++++++++--- lib/asw | 1 - sonar-project.properties | 4 +- src/Card.cpp | 10 +-- src/Game.cpp | 24 ++++--- src/Game.h | 16 ++--- src/HighScores.cpp | 23 ++++--- src/HighScores.h | 16 ++--- src/Init.cpp | 6 +- src/Init.h | 18 +++--- src/Intro.cpp | 8 ++- src/Intro.h | 16 ++--- src/LevelSelect.cpp | 21 ++++--- src/LevelSelect.h | 16 ++--- src/Menu.cpp | 12 ++-- src/Menu.h | 16 ++--- src/State.cpp | 114 ---------------------------------- src/State.h | 92 +++------------------------ src/main.cpp | 103 +++++------------------------- src/ui/Button.cpp | 7 +-- src/ui/InputBox.cpp | 32 +++++----- 30 files changed, 255 insertions(+), 590 deletions(-) create mode 100644 .clang-tidy delete mode 100644 .github/workflows/sonar.yml delete mode 100644 .gitmodules delete mode 100644 .vscode/c_cpp_properties.json delete mode 160000 lib/asw delete mode 100644 src/State.cpp diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..760af55 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,25 @@ +Checks: | + bugprone-* + clang-analyzer-* + cppcoreguidelines-* + misc-* + modernize-* + performance-* + readability-* + portability-* + -cppcoreguidelines-avoid-magic-numbers + -readability-magic-numbers + -readability-identifier-length + -modernize-use-nodiscard + -cppcoreguidelines-init-variables + -bugprone-easily-swappable-parameters + -cppcoreguidelines-avoid-non-const-global-variables + -modernize-use-trailing-return-type + -performance-enum-size + -cppcoreguidelines-pro-bounds-constant-array-index + -cppcoreguidelines-non-private-member-variables-in-classes + -cppcoreguidelines-avoid-const-or-ref-data-members + -misc-include-cleaner + -misc-non-private-member-variables-in-classes +WarningsAsErrors: true +HeaderFilterRegex: ".*" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3f322e5..2ee57a9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,16 +6,19 @@ on: - main tags: - v* - -env: - EM_VERSION: "latest" - EM_CACHE_FOLDER: "emsdk-cache" + pull_request: + branches: + - main permissions: contents: read pages: write id-token: write +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + jobs: deploy: name: Deploy @@ -25,21 +28,22 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 - with: - submodules: recursive + uses: actions/checkout@v4 - name: Setup cache - id: cache-system-libraries - uses: actions/cache@v2 + uses: actions/cache@v4 with: - path: ${{env.EM_CACHE_FOLDER}} - key: ${{env.EM_VERSION}}-${{ runner.os }} + path: "_deps" + key: deps-${{ runner.os }} - - uses: mymindstorm/setup-emsdk@v11 + - uses: mymindstorm/setup-emsdk@v14 with: - version: ${{env.EM_VERSION}} - actions-cache-folder: ${{env.EM_CACHE_FOLDER}} + version: 4.0.6 + actions-cache-folder: "emsdk-cache" + + - name: Download ports + run: | + embuilder build harfbuzz - name: Run CMake run: emcmake cmake -G "Unix Makefiles" . @@ -47,14 +51,15 @@ jobs: - name: Make run: emmake make -j4 - - uses: actions/upload-pages-artifact@v1 + - uses: actions/upload-pages-artifact@v3 + if: github.ref == 'refs/heads/main' with: path: ./build - name: Deploy to GitHub Pages if: github.ref == 'refs/heads/main' id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 - name: Deploy to A.D.S. Games if: startsWith(github.ref, 'refs/tags/v') diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml deleted file mode 100644 index 441f5b8..0000000 --- a/.github/workflows/sonar.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Build -on: - push: - branches: - - main - pull_request: - types: [opened, synchronize, reopened] - -jobs: - build: - name: Build - runs-on: ubuntu-latest - env: - SONAR_SCANNER_VERSION: 4.7.0.2747 - SONAR_SERVER_URL: "https://sonarcloud.io" - BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - submodules: "recursive" - - - uses: awalsh128/cache-apt-pkgs-action@latest - with: - packages: libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev libsdl2-gfx-dev - version: 1.0 - - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - java-version: 11 - - - name: Download and set up sonar-scanner - env: - SONAR_SCANNER_DOWNLOAD_URL: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${{ env.SONAR_SCANNER_VERSION }}-linux.zip - run: | - mkdir -p $HOME/.sonar - curl -sSLo $HOME/.sonar/sonar-scanner.zip ${{ env.SONAR_SCANNER_DOWNLOAD_URL }} - unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/ - echo "$HOME/.sonar/sonar-scanner-${{ env.SONAR_SCANNER_VERSION }}-linux/bin" >> $GITHUB_PATH - - - name: Download and set up build-wrapper - env: - BUILD_WRAPPER_DOWNLOAD_URL: ${{ env.SONAR_SERVER_URL }}/static/cpp/build-wrapper-linux-x86.zip - run: | - curl -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip ${{ env.BUILD_WRAPPER_DOWNLOAD_URL }} - unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/ - echo "$HOME/.sonar/build-wrapper-linux-x86" >> $GITHUB_PATH - - - name: Setup project - run: cmake . - - - name: Run build-wrapper - run: | - build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make - - - name: Run sonar-scanner - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" diff --git a/.gitignore b/.gitignore index 45d2ab9..088631a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,6 @@ $RECYCLE.BIN/ # Icon must ends with two \r. Icon - # Thumbnails ._* @@ -55,4 +54,5 @@ build.ninja /build .idea Testing/ -compile_commands.json \ No newline at end of file +compile_commands.json +_deps/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ae582e6..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/asw"] - path = lib/asw - url = https://github.com/AdsGames/asw diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index f1672fb..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "configurations": [ - { - "name": "Win32", - "includePath": ["${default}", "${workspaceFolder}/lib/asw/include"], - "defines": ["_DEBUG", "UNICODE", "_UNICODE"], - "compileCommands": "${workspaceFolder}/compile_commands.json", - "configurationProvider": "ms-vscode.cmake-tools" - } - ], - "version": 4 -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1929074..dbc313e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "Build", "type": "shell", - "detail": "Run and build jim farm", + "detail": "Run and build memory", "command": "cmake --build . && cd build && ./Memory", "windows": { "command": "cmake --build . && cd build && Memory.exe" diff --git a/CMakeLists.txt b/CMakeLists.txt index c96aa79..55706a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,80 +5,55 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +include(FetchContent) + project (Memory) # Source code -file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/lib/*.cpp) -file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h ${CMAKE_CURRENT_SOURCE_DIR}/lib/*.h) +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h) add_executable (${PROJECT_NAME} ${SOURCES} ${HEADERS}) target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -pedantic) -add_subdirectory(lib/asw) +FetchContent_Declare( + asw + GIT_REPOSITORY https://github.com/adsgames/asw.git + GIT_TAG v0.5.4 + GIT_SHALLOW TRUE +) +FetchContent_MakeAvailable(asw) -# Find libs -if(NOT EMSCRIPTEN) - find_library(SDL_LIBRARY NAMES SDL2 REQUIRED) - find_library(SDL_MIXER_LIBRARY NAMES SDL2_mixer REQUIRED) - find_library(SDL_IMAGE_LIBRARY NAMES SDL2_image REQUIRED) - find_library(SDL_TTF_LIBRARY NAMES SDL2_ttf REQUIRED) - find_library(SDL_GFX_LIBRARY NAMES SDL2_gfx REQUIRED) - find_library(SDL_MAIN_LIBRARY NAMES SDL2main REQUIRED) -endif(NOT EMSCRIPTEN) +# Link Libs +if(MINGW) + target_link_libraries(${PROJECT_NAME} -lmingw32) +endif(MINGW) +target_link_libraries( + ${PROJECT_NAME} + asw +) -# Link Libs # Emscripten support if(EMSCRIPTEN) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "index") set(CMAKE_EXECUTABLE_SUFFIX ".html") - target_compile_options( - ${PROJECT_NAME} - PRIVATE - -sUSE_SDL=2 - -sUSE_SDL_IMAGE=2 - -sUSE_SDL_TTF=2 - -sUSE_SDL_MIXER=2 - -sUSE_SDL_GFX=2 - -sSDL2_IMAGE_FORMATS=["png"] - ) + target_link_libraries( ${PROJECT_NAME} -sWASM=1 - -sUSE_SDL=2 - -sUSE_SDL_IMAGE=2 - -sUSE_SDL_TTF=2 - -sUSE_SDL_MIXER=2 - -sUSE_SDL_GFX=2 - -sSDL2_IMAGE_FORMATS=["png"] - -sDEMANGLE_SUPPORT=1 - -sTOTAL_MEMORY=512MB - asw + -sALLOW_MEMORY_GROWTH=1 + -sMAXIMUM_MEMORY=1gb ) + set_target_properties( ${PROJECT_NAME} PROPERTIES LINK_FLAGS "--preload-file ${CMAKE_CURRENT_LIST_DIR}/assets@/assets --use-preload-plugins --shell-file ${CMAKE_CURRENT_LIST_DIR}/index.html" ) - -# Run of the mill executable -else(EMSCRIPTEN) - if(MINGW) - target_link_libraries(${PROJECT_NAME} -lmingw32) - endif(MINGW) - target_link_libraries( - ${PROJECT_NAME} - -lm - ${SDL_MAIN_LIBRARY} - ${SDL_LIBRARY} - ${SDL_MIXER_LIBRARY} - ${SDL_IMAGE_LIBRARY} - ${SDL_TTF_LIBRARY} - ${SDL_GFX_LIBRARY} - asw - ) endif(EMSCRIPTEN) -file(COPY ${CMAKE_CURRENT_LIST_DIR}/assets/ DESTINATION ${CMAKE_BINARY_DIR}/build/assets/) \ No newline at end of file +file(COPY ${CMAKE_CURRENT_LIST_DIR}/assets/ DESTINATION ${CMAKE_BINARY_DIR}/build/assets/) + diff --git a/README.md b/README.md index 9761946..2830f56 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ Match all the cards on the table in four different difficulties. Compete against yourself and others with the high-score tables. -[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=AdsGames_Memory&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=AdsGames_Memory) -[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=AdsGames_Memory&metric=bugs)](https://sonarcloud.io/summary/new_code?id=AdsGames_Memory) +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=AdsGames_memory&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=AdsGames_memory) +[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=AdsGames_memory&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=AdsGames_memory) +[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=AdsGames_memory&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=AdsGames_memory) ## Demo @@ -11,32 +12,6 @@ Match all the cards on the table in four different difficulties. Compete against ## Setup -### Dependencies - -To pull the submodules, run the following command: - -```bash -git submodule update --init --recursive -``` - -### Windows (MSYS2) - -```bash -pacman -S mingw-w64-i686-gcc-libs mingw-w64-i686-SDL2 mingw-w64-i686-SDL2_mixer mingw-w64-i686-SDL2_image mingw-w64-i686-SDL2_ttf -``` - -### Mac OS - -```bash -brew install sdl2 sdl2_image sdl2_ttf sdl2_mixer -``` - -### Linux - -```bash -sudo apt install libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev -``` - ### Build ```bash diff --git a/index.html b/index.html index 0ad8b76..d944101 100644 --- a/index.html +++ b/index.html @@ -14,20 +14,24 @@ width: 100%; height: 100%; background-color: #000000; + } + + #canvas_wrapper { display: flex; - align-items: center; - justify-content: center; + margin: 0 auto; } - +
+ +
+ + {{{ SCRIPT }}} diff --git a/lib/asw b/lib/asw deleted file mode 160000 index d7adc6a..0000000 --- a/lib/asw +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d7adc6a5b82929378e44c394b8be62b6d70398f7 diff --git a/sonar-project.properties b/sonar-project.properties index 1c35f11..f6c0dfb 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,3 +1,3 @@ -sonar.projectKey=AdsGames_Memory +sonar.projectKey=AdsGames_memory sonar.organization=adsgames -sonar.sources=./src \ No newline at end of file +sonar.sources=./src diff --git a/src/Card.cpp b/src/Card.cpp index 074be3c..2890cf1 100644 --- a/src/Card.cpp +++ b/src/Card.cpp @@ -85,8 +85,9 @@ void Card::update() { auto screenSize = asw::display::getLogicalSize(); if (!selected && asw::input::mouse.pressed[1] && numberSelected < 2 && - collision(asw::input::mouse.x, asw::input::mouse.x, x, x + width, - asw::input::mouse.y, asw::input::mouse.y, y, y + height)) { + collision((int)asw::input::mouse.x, (int)asw::input::mouse.x, x, + x + width, (int)asw::input::mouse.y, (int)asw::input::mouse.y, + y, y + height)) { animationTime.reset(); asw::sound::play(cardFlip); selected = true; @@ -129,6 +130,7 @@ void Card::update() { void Card::draw() const { const auto& texture = flipped ? FACE_IMAGES[type] : backImage; - asw::draw::stretchSprite(texture, x + (width - animationWidth) / 2, y, - animationWidth, height); + asw::draw::stretchSprite(texture, + asw::Quad(x + (width - animationWidth) / 2, y, + animationWidth, height)); } diff --git a/src/Game.cpp b/src/Game.cpp index 616d2ad..bca5007 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -68,14 +68,16 @@ void Game::initCards(const DifficultyConfig& config) { } } -void Game::update() { +void Game::update(float deltaTime) { + Scene::update(deltaTime); + // End game if (cards.empty()) { this->endgameUpdate(); } // Go to menu - else if (asw::input::keyboard.pressed[SDL_SCANCODE_M]) { - setNextState(ProgramState::STATE_MENU); + else if (asw::input::wasKeyPressed(asw::input::Key::ESCAPE)) { + sceneManager.setNextScene(States::Menu); } this->eraseOffScreenCards(); @@ -94,11 +96,11 @@ void Game::update() { void Game::endgameUpdate() { nameBox.update(); - if (asw::input::keyboard.pressed[SDL_SCANCODE_RETURN]) { + if (asw::input::wasKeyPressed(asw::input::Key::RETURN)) { auto& config = DIFFICULTY_CONFIG[difficulty]; scoreManager.addScore(nameBox.getValue(), moves); scoreManager.saveScores(config.highscoresFile); - setNextState(ProgramState::STATE_MENU); + sceneManager.setNextScene(States::Menu); } } @@ -155,12 +157,13 @@ void Game::matchCards() { void Game::draw() { // Background - asw::draw::sprite(background, 0, 0); + asw::draw::sprite(background, asw::Vec2(0, 0)); // Show Moves - asw::draw::rectFill(15, 15, 200, 70, asw::util::makeColor(255, 255, 255)); - asw::draw::text(font, "Moves:" + std::to_string(moves), 20, 20, - asw::util::makeColor(0, 0, 0)); + asw::draw::rectFill(asw::Quad(15, 15, 200, 70), + asw::util::makeColor(255, 255, 255)); + asw::draw::text(font, "Moves:" + std::to_string(moves), + asw::Vec2(20, 20), asw::util::makeColor(0, 0, 0)); // Draw cards for (const auto& card : cards) { @@ -169,7 +172,8 @@ void Game::draw() { if (cards.empty()) { // Create gui - asw::draw::textCenter(font, "Congratulations! Enter Your Name", 640, 310, + asw::draw::textCenter(font, "Congratulations! Enter Your Name", + asw::Vec2(640, 310), asw::util::makeColor(0, 0, 0)); nameBox.draw(); diff --git a/src/Game.h b/src/Game.h index e893f20..78ac1bd 100644 --- a/src/Game.h +++ b/src/Game.h @@ -1,5 +1,4 @@ -#ifndef GAME_H -#define GAME_H +#pragma once #include #include @@ -18,16 +17,15 @@ struct DifficultyConfig { }; // Intro screen of game -class Game : public State { +class Game : public asw::scene::Scene { public: - using State::State; + using asw::scene::Scene::Scene; void init() override; - void update() override; + + void update(float deltaTime) override; + void draw() override; - void cleanup() override{ - // Nothing to do - }; static GameDifficulty difficulty; @@ -54,5 +52,3 @@ class Game : public State { unsigned int cardSelected1{0}; unsigned int cardSelected2{0}; }; - -#endif // GAME_H diff --git a/src/HighScores.cpp b/src/HighScores.cpp index 70f4704..a070f13 100644 --- a/src/HighScores.cpp +++ b/src/HighScores.cpp @@ -48,10 +48,12 @@ void HighScores::init() { updateScores(); } -void HighScores::update() { +void HighScores::update(float deltaTime) { + Scene::update(deltaTime); + // Go to menu - if (asw::input::keyboard.down[SDL_SCANCODE_M]) { - setNextState(ProgramState::STATE_MENU); + if (asw::input::wasKeyPressed(asw::input::Key::ESCAPE)) { + sceneManager.setNextScene(States::Menu); } // Click buttons @@ -61,20 +63,20 @@ void HighScores::update() { void HighScores::draw() { // Background - asw::draw::sprite(background, 0, 0); + asw::draw::sprite(background, asw::Vec2(0, 0)); // Titles if (difficulty == GameDifficulty::EASY) { - asw::draw::textCenter(font, "Easy", 640, 100, + asw::draw::textCenter(font, "Easy", asw::Vec2(640, 100), asw::util::makeColor(0, 0, 0)); } else if (difficulty == GameDifficulty::MEDIUM) { - asw::draw::textCenter(font, "Medium", 640, 100, + asw::draw::textCenter(font, "Medium", asw::Vec2(640, 100), asw::util::makeColor(0, 0, 0)); } else if (difficulty == GameDifficulty::HARD) { - asw::draw::textCenter(font, "Hard", 640, 100, + asw::draw::textCenter(font, "Hard", asw::Vec2(640, 100), asw::util::makeColor(0, 0, 0)); } else if (difficulty == GameDifficulty::EXTREME) { - asw::draw::textCenter(font, "EXTREME", 640, 100, + asw::draw::textCenter(font, "EXTREME", asw::Vec2(640, 100), asw::util::makeColor(0, 0, 0)); } @@ -87,9 +89,10 @@ void HighScores::draw() { int drawY = 200; for (const auto& [name, score] : scores) { - asw::draw::text(font, name, 400, drawY, asw::util::makeColor(0, 0, 0)); + asw::draw::text(font, name, asw::Vec2(400, drawY), + asw::util::makeColor(0, 0, 0)); - asw::draw::text(font, std::to_string(score), 860, drawY, + asw::draw::text(font, std::to_string(score), asw::Vec2(860, drawY), asw::util::makeColor(0, 0, 0)); drawY += 50; diff --git a/src/HighScores.h b/src/HighScores.h index f6de468..926c38f 100644 --- a/src/HighScores.h +++ b/src/HighScores.h @@ -1,5 +1,4 @@ -#ifndef HIGH_SCORES_H -#define HIGH_SCORES_H +#pragma once #include #include @@ -10,16 +9,15 @@ #include "util/ScoreManager.h" // Intro screen of game -class HighScores : public State { +class HighScores : public asw::scene::Scene { public: - using State::State; + using asw::scene::Scene::Scene; void init() override; - void update() override; + + void update(float deltaTime) override; + void draw() override; - void cleanup() override{ - // Nothing to do - }; private: static std::map SCORE_FILES; @@ -39,5 +37,3 @@ class HighScores : public State { Button levelSelectLeft; Button levelSelectRight; }; - -#endif // HIGH_SCORES_H diff --git a/src/Init.cpp b/src/Init.cpp index a11b1b3..42b9f9d 100644 --- a/src/Init.cpp +++ b/src/Init.cpp @@ -8,8 +8,10 @@ void Init::init() { asw::display::setTitle("Memory"); } -void Init::update() { - setNextState(ProgramState::STATE_INTRO); +void Init::update(float deltaTime) { + Scene::update(deltaTime); + + sceneManager.setNextScene(States::Intro); } void Init::draw() { diff --git a/src/Init.h b/src/Init.h index b148d92..58e3c38 100644 --- a/src/Init.h +++ b/src/Init.h @@ -1,18 +1,16 @@ -#ifndef INIT_H -#define INIT_H +#pragma once + +#include #include "State.h" -class Init : public State { +class Init : public asw::scene::Scene { public: - using State::State; + using asw::scene::Scene::Scene; void init() override; - void update() override; + + void update(float deltaTime) override; + void draw() override; - void cleanup() override{ - // Nothing to do - }; }; - -#endif // INIT_H diff --git a/src/Intro.cpp b/src/Intro.cpp index ade4b23..22bab51 100644 --- a/src/Intro.cpp +++ b/src/Intro.cpp @@ -8,14 +8,16 @@ void Intro::init() { timer.start(); } -void Intro::update() { +void Intro::update(float deltaTime) { + Scene::update(deltaTime); + auto time = timer.getElapsedTime(); if (time >= 3000 || asw::input::keyboard.anyPressed) { - setNextState(ProgramState::STATE_MENU); + sceneManager.setNextScene(States::Menu); } } void Intro::draw() { - asw::draw::sprite(intro, 0, 0); + asw::draw::sprite(intro, asw::Vec2(0, 0)); } diff --git a/src/Intro.h b/src/Intro.h index 33cce3b..08339bf 100644 --- a/src/Intro.h +++ b/src/Intro.h @@ -1,5 +1,4 @@ -#ifndef INTRO_H -#define INTRO_H +#pragma once #include #include @@ -7,21 +6,18 @@ #include "State.h" // Intro screen of game -class Intro : public State { +class Intro : public asw::scene::Scene { public: - using State::State; + using asw::scene::Scene::Scene; void init() override; - void update() override; + + void update(float deltaTime) override; + void draw() override; - void cleanup() override{ - // Nothing to do - }; private: asw::Texture intro; Timer timer; }; - -#endif // INTRO_H diff --git a/src/LevelSelect.cpp b/src/LevelSelect.cpp index ccf73e3..0c3d1ee 100644 --- a/src/LevelSelect.cpp +++ b/src/LevelSelect.cpp @@ -47,10 +47,12 @@ void LevelSelect::init() { }); } -void LevelSelect::update() { +void LevelSelect::update(float deltaTime) { + Scene::update(deltaTime); + // Go to menu - if (asw::input::keyboard.down[SDL_SCANCODE_M]) { - setNextState(ProgramState::STATE_MENU); + if (asw::input::wasKeyPressed(asw::input::Key::ESCAPE)) { + sceneManager.setNextScene(States::Menu); } levelSelectLeft.update(); @@ -58,22 +60,23 @@ void LevelSelect::update() { // Click buttons if ((asw::input::mouse.pressed[1] && - collision(asw::input::mouse.x, asw::input::mouse.x, 250, 1050, - asw::input::mouse.y, asw::input::mouse.y, 185, 785)) || - asw::input::keyboard.down[SDL_SCANCODE_RETURN]) { + collision((int)asw::input::mouse.x, (int)asw::input::mouse.x, 250, 1050, + (int)asw::input::mouse.y, (int)asw::input::mouse.y, 185, + 785)) || + asw::input::wasKeyPressed(asw::input::Key::RETURN)) { Game::difficulty = difficulty; - setNextState(ProgramState::STATE_GAME); + sceneManager.setNextScene(States::Game); } } void LevelSelect::draw() { // Background - asw::draw::sprite(background, 0, 0); + asw::draw::sprite(background, asw::Vec2(0, 0)); // Buttons levelSelectLeft.draw(); levelSelectRight.draw(); // Draw difficulty demos - asw::draw::sprite(difficultyImages[difficulty], 250, 185); + asw::draw::sprite(difficultyImages[difficulty], asw::Vec2(250, 185)); } diff --git a/src/LevelSelect.h b/src/LevelSelect.h index f702874..6a55639 100644 --- a/src/LevelSelect.h +++ b/src/LevelSelect.h @@ -1,5 +1,4 @@ -#ifndef LEVEL_SELECT_H -#define LEVEL_SELECT_H +#pragma once #include #include @@ -9,16 +8,15 @@ #include "ui/Button.h" // Intro screen of game -class LevelSelect : public State { +class LevelSelect : public asw::scene::Scene { public: - using State::State; + using asw::scene::Scene::Scene; void init() override; - void update() override; + + void update(float deltaTime) override; + void draw() override; - void cleanup() override{ - // Nothing to do - }; private: asw::Texture background; @@ -33,5 +31,3 @@ class LevelSelect : public State { Button levelSelectLeft; Button levelSelectRight; }; - -#endif // LEVEL_SELECT_H diff --git a/src/Menu.cpp b/src/Menu.cpp index 6484d0a..bec2e8c 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -21,22 +21,24 @@ void Menu::init() { // Button actions buttonStart.setOnClick( - [this]() { setNextState(ProgramState::STATE_LEVEL_SELECT); }); + [this]() { sceneManager.setNextScene(States::LevelSelect); }); buttonHighscores.setOnClick( - [this]() { setNextState(ProgramState::STATE_HIGH_SCORES); }); + [this]() { sceneManager.setNextScene(States::HighScores); }); - buttonQuit.setOnClick([this]() { setNextState(ProgramState::STATE_EXIT); }); + buttonQuit.setOnClick([this]() { asw::core::exit = true; }); } -void Menu::update() { +void Menu::update(float deltaTime) { + Scene::update(deltaTime); + buttonStart.update(); buttonHighscores.update(); buttonQuit.update(); } void Menu::draw() { - asw::draw::sprite(background, 0, 0); + asw::draw::sprite(background, asw::Vec2(0, 0)); buttonStart.draw(); buttonHighscores.draw(); buttonQuit.draw(); diff --git a/src/Menu.h b/src/Menu.h index c5dcb53..8f95f7b 100644 --- a/src/Menu.h +++ b/src/Menu.h @@ -1,5 +1,4 @@ -#ifndef MENU_H -#define MENU_H +#pragma once #include @@ -7,16 +6,15 @@ #include "ui/Button.h" // Intro screen of game -class Menu : public State { +class Menu : public asw::scene::Scene { public: - using State::State; + using asw::scene::Scene::Scene; void init() override; - void update() override; + + void update(float deltaTime) override; + void draw() override; - void cleanup() override{ - // Nothing to do - }; private: asw::Texture background; @@ -25,5 +23,3 @@ class Menu : public State { Button buttonHighscores; Button buttonQuit; }; - -#endif // MENU_H diff --git a/src/State.cpp b/src/State.cpp deleted file mode 100644 index 65224c4..0000000 --- a/src/State.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "State.h" - -#include - -#include "Game.h" -#include "HighScores.h" -#include "Init.h" -#include "Intro.h" -#include "LevelSelect.h" -#include "Menu.h" - -/***************** - * STATE ENGINE - *****************/ - -// Draw -void StateEngine::draw() const { - if (state) { - // Clear screen - SDL_RenderClear(asw::display::renderer); - - state->draw(); - - // Update screen - SDL_RenderPresent(asw::display::renderer); - } -} - -// Update -void StateEngine::update() { - if (state) { - state->update(); - } - - changeState(); -} - -// Set next state -void StateEngine::setNextState(const ProgramState newState) { - nextState = newState; -} - -// Get state id -ProgramState StateEngine::getStateId() const { - return currentState; -} - -// Change game screen -void StateEngine::changeState() { - // If the state needs to be changed - if (nextState == ProgramState::STATE_NULL) { - return; - } - - // Delete the current state - if (state) { - state->cleanup(); - state = nullptr; - } - - // Change the state - switch (nextState) { - case ProgramState::STATE_GAME: - state = std::make_unique(*this); - std::cout << "Switched state to game." << std::endl; - break; - - case ProgramState::STATE_MENU: - state = std::make_unique(*this); - std::cout << "Switched state to main menu." << std::endl; - break; - - case ProgramState::STATE_INIT: - state = std::make_unique(*this); - std::cout << "Switched state to init." << std::endl; - break; - - case ProgramState::STATE_INTRO: - state = std::make_unique(*this); - std::cout << "Switched state to intro." << std::endl; - break; - - case ProgramState::STATE_HIGH_SCORES: - state = std::make_unique(*this); - std::cout << "Switched state to high scores." << std::endl; - break; - - case ProgramState::STATE_LEVEL_SELECT: - state = std::make_unique(*this); - std::cout << "Switched state to level select." << std::endl; - break; - - default: - std::cout << "Exiting program." << std::endl; - break; - } - - state->init(); - - // Change the current state ID - currentState = nextState; - - // NULL the next state ID - nextState = ProgramState::STATE_NULL; -} - -/********* - * STATE - *********/ - -// Change state -void State::setNextState(const ProgramState state) { - this->engine.setNextState(state); -} \ No newline at end of file diff --git a/src/State.h b/src/State.h index ad3fcc6..0777c10 100644 --- a/src/State.h +++ b/src/State.h @@ -1,91 +1,17 @@ /** - * State for machine and State Engine + * Game states * Allan Legemaate * 30/12/2016 - * Compartmentalize program into states - * which can handle only their own logic, - * drawing and transitions */ -#ifndef STATE_H -#define STATE_H - -#include -#include - -// Class -class State; +#pragma once // Game states -enum class ProgramState { - STATE_NULL, - STATE_INIT, - STATE_INTRO, - STATE_MENU, - STATE_HIGH_SCORES, - STATE_LEVEL_SELECT, - STATE_GAME, - STATE_EXIT, -}; - -/***************** - * STATE ENGINE - *****************/ -class StateEngine { - public: - // Update - void update(); - - // Draw - void draw() const; - - // Set next state - void setNextState(const ProgramState state); - - // Get state id - ProgramState getStateId() const; - - private: - // Change state - void changeState(); - - // Next state - ProgramState nextState{ProgramState::STATE_NULL}; - - // State id - ProgramState currentState{ProgramState::STATE_NULL}; - - // Stores states - std::unique_ptr state{nullptr}; +enum class States { + Init, + Intro, + Menu, + HighScores, + LevelSelect, + Game, }; - -/********* - * STATE - *********/ -class State { - public: - // Constructor - explicit State(StateEngine& engine) : engine(engine){}; - - virtual ~State() = default; - - // Init the state - virtual void init() = 0; - - // Draw to screen - virtual void draw() = 0; - - // Cleanup - virtual void cleanup() = 0; - - // Update logic - virtual void update() = 0; - - // Change state - void setNextState(const ProgramState state); - - private: - StateEngine& engine; -}; - -#endif // STATE_H diff --git a/src/main.cpp b/src/main.cpp index 8600fa7..d63549e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,98 +6,29 @@ // Includes #include -#include -#include - -#ifdef __EMSCRIPTEN__ -#include -#include -#endif - // For state engine +#include "Game.h" +#include "HighScores.h" +#include "Init.h" +#include "Intro.h" +#include "LevelSelect.h" +#include "Menu.h" #include "State.h" -using namespace std::chrono_literals; -using namespace std::chrono; -constexpr nanoseconds timestep(16ms); - -// State engine -std::unique_ptr state; - -// Functions -void setup(); -void draw(); -void update(); - -// FPS system -int fps = 0; -int frames_done = 0; - -// Setup game -void setup() { - // Load allegro library - asw::core::init(1280, 960); - - state = std::make_unique(); -} - -// Update -void update() { - // Update core - asw::core::update(); - - // Do state logic - state->update(); - - // Handle exit - if (state->getStateId() == ProgramState::STATE_EXIT) { - asw::core::exit = true; - } -} - -// Do state rendering -void draw() { - state->draw(); -} - -// Loop (emscripten compatibility) -#ifdef __EMSCRIPTEN__ -void loop() { - update(); - draw(); -} -#endif - // Main function*/ -int main(int argc, char* argv[]) { - // Setup basic functionality - setup(); - - // Set the current state ID - state->setNextState(ProgramState::STATE_INIT); - -#ifdef __EMSCRIPTEN__ - emscripten_set_main_loop(loop, 0, 1); -#else - - using clock = high_resolution_clock; - nanoseconds lag(0ns); - auto time_start = clock::now(); - - while (!asw::input::keyboard.down[SDL_SCANCODE_ESCAPE] && !asw::core::exit) { - auto delta_time = clock::now() - time_start; - time_start = clock::now(); - lag += duration_cast(delta_time); +int main() { + asw::core::init(1280, 960); - while (lag >= timestep) { - lag -= timestep; - update(); - } + auto app = asw::scene::SceneManager(); + app.registerScene(States::Init, app); + app.registerScene(States::Intro, app); + app.registerScene(States::Menu, app); + app.registerScene(States::LevelSelect, app); + app.registerScene(States::Game, app); + app.registerScene(States::HighScores, app); + app.setNextScene(States::Init); - draw(); - frames_done++; - } -#endif + app.start(); return 0; } diff --git a/src/ui/Button.cpp b/src/ui/Button.cpp index ba6cc40..de655e6 100644 --- a/src/ui/Button.cpp +++ b/src/ui/Button.cpp @@ -40,11 +40,8 @@ int Button::getY() const { void Button::draw() const { if (isHovering() && imageHover) { - asw::draw::sprite(imageHover, x, y); + asw::draw::sprite(imageHover, asw::Vec2(x, y)); } else if (!isHovering() && image) { - asw::draw::sprite(image, x, y); - } else { - asw::draw::rectFill(x, y, x + width, y + height, - asw::util::makeColor(60, 60, 60)); + asw::draw::sprite(image, asw::Vec2(x, y)); } } diff --git a/src/ui/InputBox.cpp b/src/ui/InputBox.cpp index 713d1b0..3d43bd6 100644 --- a/src/ui/InputBox.cpp +++ b/src/ui/InputBox.cpp @@ -37,9 +37,8 @@ void InputBox::update() { int closest = width; for (unsigned int i = 0; i <= text.length(); i++) { - int textSize = asw::util::getTextSize(font, text.substr(0, i)).x; - - int distance = abs(textSize + x + 6 - asw::input::mouse.x); + const int textSize = asw::util::getTextSize(font, text.substr(0, i)).x; + const int distance = abs(textSize + x + 6 - asw::input::mouse.x); if (distance < closest) { textIterator = i; @@ -70,8 +69,8 @@ void InputBox::update() { } if (type == "text" && lastKey >= 4 && lastKey <= 29) { - if (asw::input::keyboard.down[SDL_SCANCODE_LSHIFT] || - asw::input::keyboard.down[SDL_SCANCODE_RSHIFT]) { + if (asw::input::wasKeyPressed(asw::input::Key::LSHIFT) || + asw::input::wasKeyPressed(asw::input::Key::RSHIFT)) { text.insert(text.begin() + textIterator, 'A' - 4 + lastKey); } else { text.insert(text.begin() + textIterator, 'a' - 4 + lastKey); @@ -81,43 +80,48 @@ void InputBox::update() { } // some other, "special" key was pressed; handle it here - if (asw::input::keyboard.pressed[SDL_SCANCODE_BACKSPACE] && + if (asw::input::wasKeyPressed(asw::input::Key::BACKSPACE) && textIterator != 0) { textIterator--; text.erase(text.begin() + textIterator); } - if (asw::input::keyboard.pressed[SDL_SCANCODE_RIGHT] && + if (asw::input::wasKeyPressed(asw::input::Key::RIGHT) && textIterator != text.size()) { textIterator++; } - if (asw::input::keyboard.pressed[SDL_SCANCODE_LEFT] && textIterator != 0) { + if (asw::input::wasKeyPressed(asw::input::Key::LEFT) && textIterator != 0) { textIterator--; } } // Draw box void InputBox::draw() const { - asw::draw::rectFill(x, y, width, height, asw::util::makeColor(12, 12, 12)); + asw::draw::rectFill(asw::Quad(x, y, width, height), + asw::util::makeColor(12, 12, 12)); asw::Color col = (hover() || focused) ? asw::util::makeColor(230, 230, 230) : asw::util::makeColor(245, 245, 245); if (focused) { - asw::draw::rectFill(x + 2, y + 2, width - 4, height - 4, col); + asw::draw::rectFill(asw::Quad(x + 2, y + 2, width - 4, height - 4), + col); } else { - asw::draw::rectFill(x + 1, y + 1, width - 2, height - 2, col); + asw::draw::rectFill(asw::Quad(x + 1, y + 1, width - 2, height - 2), + col); } // Output the string to the screen - asw::draw::text(font, text, x + 6, y, asw::util::makeColor(22, 22, 22)); + asw::draw::text(font, text, asw::Vec2(x + 6, y), + asw::util::makeColor(22, 22, 22)); // Draw the caret if (focused) { int textSize = asw::util::getTextSize(font, text.substr(0, textIterator)).x; - asw::draw::rectFill(textSize + x + 6, y + 8, 1, height - 16, - asw::util::makeColor(0, 0, 0)); + asw::draw::rectFill( + asw::Quad(textSize + x + 6, y + 8, 1, height - 16), + asw::util::makeColor(0, 0, 0)); } }