mapcreator git · master
SDL3 2.5D game and engine using assets, with map editor
C++ 99.3%git clone https://git.christianimmanuel.de/sdl-graphics/mapcreator.gitwget https://git.christianimmanuel.de/sdl-graphics/mapcreator/archive/mapcreator.tar.gzPropper Cursor
src/building/building.cpp | 11 +- src/building/building.hpp | 4 +- src/character/character.cpp | 36 ++++-- src/character/character.hpp | 2 +- src/cursor/animated_cursor.cpp | 283 +++++++++++++++++++++++++++++++++++++++++ src/cursor/animated_cursor.hpp | 75 +++++++++++ src/defaults/defaults.hpp | 1 - src/defaults/input.hpp | 2 + src/game/game.cpp | 19 ++- src/game/game.hpp | 3 + src/game/game_state.hpp | 2 + src/game/state_menu_main.cpp | 2 + src/game/state_modify.cpp | 2 + src/game/state_playing.cpp | 13 +- 14 files changed, 429 insertions(+), 26 deletions(-) diff --git a/src/building/building.cpp b/src/building/building.cpp index 50a8ba9..0788e63 100644 --- a/src/building/building.cpp +++ b/src/building/building.cpp @@ -362,10 +362,10 @@ Building::has_Menu() { return false; } -void +CharacterMenuType Building::open_Menu(Character* player) { if (building_status != BuildingStatus::CONSTRUCTED) - return; + return CharacterMenuType::NONE; if (BuildingData::is_ResearchTable(building_type)) { Research::research_buildings.clear(); @@ -383,16 +383,15 @@ Building::open_Menu(Character* player) { std::cout << "Open Research menu\n"; std::cout << "Build Items: " << Research::research_buildings.size() << std::endl; std::cout << "Item Items: " << Research::research_items.size() << std::endl; - player->active_menu = CharacterMenuType::RESEARCH; selected_building_type = building_type; - return; + return CharacterMenuType::RESEARCH; } if (BuildingData::is_CraftingTable(building_type)) { std::cout << "Open Crafting menu\n"; - player->active_menu = CharacterMenuType::WORKBENCH; selected_building_type = building_type; - return; + return CharacterMenuType::WORKBENCH; } + return CharacterMenuType::NONE; } void diff --git a/src/building/building.hpp b/src/building/building.hpp index 330d3c1..08d4f95 100644 --- a/src/building/building.hpp +++ b/src/building/building.hpp @@ -20,7 +20,7 @@ enum class BuildingStatus : uint32_t { }; - +enum class CharacterMenuType; class Building : public Object { public: @@ -70,7 +70,7 @@ public: bool has_Menu(); - void + CharacterMenuType open_Menu(Character* player); void close_Menu(); diff --git a/src/character/character.cpp b/src/character/character.cpp index 92991d2..9a134f4 100644 --- a/src/character/character.cpp +++ b/src/character/character.cpp @@ -11,6 +11,7 @@ #include "building/craft.hpp" #include "farm/farm.hpp" #include "character/message.hpp" +#include "cursor/animated_cursor.hpp" @@ -634,15 +635,30 @@ Character::build_Start() { } +inline void setActiveMenu(CharacterMenuType& active_menu, const CharacterMenuType& new_menu, AnimatedCursor* cursor) { + switch (active_menu) { + case CharacterMenuType::NONE: + active_menu = new_menu; + cursor->set_State(CursorState::ANIMATED); + break; + default: + active_menu = CharacterMenuType::NONE; + cursor->set_State(CursorState::HIDDEN); + break; + } +} + void -Character::interact_WithBuilding(Building* building) { +Character::interact_WithBuilding(Building* building, Input& input) { if (active_menu == CharacterMenuType::WORKBENCH) { building->close_Menu(); - active_menu = CharacterMenuType::NONE; + setActiveMenu(active_menu, CharacterMenuType::NONE, input.cursor); } else if (building->has_Menu()) { std::cout << "INTERACT OPEN" << std::endl; - building->open_Menu(this); + CharacterMenuType type = building->open_Menu(this); + if (type != CharacterMenuType::NONE) + setActiveMenu(active_menu, type, input.cursor); } } @@ -1412,7 +1428,8 @@ Character::handle_Input(Input& input, SDL_Rect win_size) { // WORKBENCH if (active_menu == CharacterMenuType::WORKBENCH) { if (input.pressed_c_released ) - active_menu = CharacterMenuType::NONE; + setActiveMenu(active_menu, CharacterMenuType::NONE, input.cursor); + Building::draw_menu_curser_grid = Research::cursor_ResearchGridTileIndex(input.mouse_state_raw, win_size); // CRAFT if (input.click_left_released) { @@ -1441,7 +1458,8 @@ Character::handle_Input(Input& input, SDL_Rect win_size) { // RESEARCH if (active_menu == CharacterMenuType::RESEARCH) { if (input.pressed_c_released ) - active_menu = CharacterMenuType::NONE; + setActiveMenu(active_menu, CharacterMenuType::NONE, input.cursor); + Building::draw_menu_curser_grid = Research::cursor_ResearchGridTileIndex(input.mouse_state_raw, win_size); if (input.click_left_released) { Research::research_Stop(); @@ -1461,7 +1479,9 @@ Character::handle_Input(Input& input, SDL_Rect win_size) { set_BuildingDiscovery(); } } else { - active_menu = CharacterMenuType::NONE; + if (active_menu != CharacterMenuType::NONE) + setActiveMenu(active_menu, CharacterMenuType::NONE, input.cursor); + Inventory::selected_build_item = ItemType::NONE; Item::crafting_item.is_crafting = false; } @@ -1475,7 +1495,7 @@ Character::handle_Input(Input& input, SDL_Rect win_size) { selected_item = inventory->get_SelectedHotbarItem(); building_Stop(); if (active_menu == CharacterMenuType::BUILDING) - active_menu = CharacterMenuType::NONE; + setActiveMenu(active_menu, CharacterMenuType::NONE, input.cursor); std::cout << "SWITCH " << selected_item->id << std::endl; return; } @@ -1529,7 +1549,7 @@ Character::handle_Input(Input& input, SDL_Rect win_size) { std::cout << "STAT: " << (int)status << std::endl; return; case ObjectCategory::BUILDING: - interact_WithBuilding(static_cast<Building*>(object)); + interact_WithBuilding(static_cast<Building*>(object), input); return; default: break; } diff --git a/src/character/character.hpp b/src/character/character.hpp index 21e1f1f..c845648 100644 --- a/src/character/character.hpp +++ b/src/character/character.hpp @@ -265,7 +265,7 @@ class Character { void thirst_Drain(); - void interact_WithBuilding(Building* building); + void interact_WithBuilding(Building* building, Input& input); void getting_Hit(float demage); diff --git a/src/cursor/animated_cursor.cpp b/src/cursor/animated_cursor.cpp new file mode 100644 index 0000000..29b3467 --- /dev/null +++ b/src/cursor/animated_cursor.cpp @@ -0,0 +1,283 @@ +// g++ -std=c++23 -O2 -Wall -Wextra animated_cursor.hpp.cpp $(pkg-config --cflags --libs sdl3 sdl3-image) -o cursor_particles && ./cursor_particles + +#include <SDL3/SDL.h> +#include <SDL3_image/SDL_image.h> +#include <vector> +#include <algorithm> +#include <random> +#include <cmath> +#include <print> + +#include "cursor/animated_cursor.hpp" + + +AnimatedCursor::AnimatedCursor() : spriteTexture(nullptr), + spriteSurface(nullptr), isReversing(false), reverseProgress(0.0f), + time(0.0f), clickX(400.0f), clickY(300.0f), + currentFrame(0), isPlayingAnimation(false), mouseX(400.0f), mouseY(300.0f) {} + + AnimatedCursor::~AnimatedCursor() { + Cleanup(); + } + +bool AnimatedCursor::Init(SDL_Renderer* renderer, const char* filename) { + spriteSurface = IMG_Load(filename); + if (!spriteSurface) { + SDL_Log("IMG_Load failed: %s", SDL_GetError()); + return false; + } + + spriteTexture = SDL_CreateTextureFromSurface(renderer, spriteSurface); + if (!spriteTexture) { + SDL_Log("SDL_CreateTextureFromSurface failed: %s", SDL_GetError()); + return false; + } + + frame_ExtractFirst(); + return true; +} + +void AnimatedCursor::set_State(const CursorState& state_new) { + std::print("MOUSE STATE {0}\n", (int)state_new); + + bool is_visible = SDL_CursorVisible(); + if (state == CursorState::ANIMATED || state == CursorState::HIDDEN) { + if (is_visible && !isReversing) + SDL_HideCursor(); + } else if (state == CursorState::NORMAL){ + if (!is_visible) + SDL_ShowCursor(); + } + state = state_new; +} + +void AnimatedCursor::frame_ExtractFirst() { + pixels.clear(); + allFrames.clear(); + allFrames.resize(TOTAL_FRAMES); + + // Lock surface for pixel access + SDL_LockSurface(spriteSurface); + Uint32* surfacePixels = (Uint32*)spriteSurface->pixels; + int pitch = spriteSurface->pitch / 4; + + const SDL_PixelFormatDetails* details = + SDL_GetPixelFormatDetails(spriteSurface->format); + if (!details) { + SDL_UnlockSurface(spriteSurface); + return; + } + + // Extract non-transparent pixels from all 8 frames + for (size_t frame = 0; frame < TOTAL_FRAMES; frame++) { + int frameOffsetX = static_cast<int>(frame) * FRAME_WIDTH; + + for (int y = 0; y < FRAME_HEIGHT; y++) { + for (int x = 0; x < FRAME_WIDTH; x++) { + Uint32 pixel = surfacePixels[y * pitch + (frameOffsetX + x)]; + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, details, NULL, &r, &g, &b, &a); + + if (a > 0) { // Non-transparent pixel + Pixel p; + p.srcX = x; + p.srcY = y; + p.originalColor = {r, g, b, a}; + allFrames[frame].push_back(p); + } + } + } + } + + SDL_UnlockSurface(spriteSurface); + + // Start with first frame + pixels = allFrames[0]; + currentFrame = 0; + + // Generate shuffled positions and colors + state_GenerateShuffle(); +} + +void AnimatedCursor::state_GenerateShuffle() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<float> angleDist(0.0f, 2.0f * M_PI); + std::uniform_real_distribution<float> radiusDist(0.0f, SPHERE_RADIUS); + std::uniform_real_distribution<float> speedDist(0.3f, 4.5f); + std::uniform_int_distribution<> colorDist(0, 255); + + // Initialize each pixel with random position and movement + for (auto& p : pixels) { + // Initial position in sphere + p.currentAngle = angleDist(gen); + p.currentRadius = radiusDist(gen); + + // Target for smooth movement + p.targetAngle = angleDist(gen); + p.targetRadius = radiusDist(gen); + + // Random movement speeds + p.angleSpeed = speedDist(gen); + p.radiusSpeed = speedDist(gen) * 0.5f; + + // Generate random shuffled color + p.shuffledColor = { + (Uint8)colorDist(gen), + (Uint8)colorDist(gen), + (Uint8)colorDist(gen), + p.originalColor.a + }; + } +} + +SDL_Color lerpColor(const SDL_Color& a, const SDL_Color& b, float t) { + return { + (Uint8)(a.r + (b.r - a.r) * t), + (Uint8)(a.g + (b.g - a.g) * t), + (Uint8)(a.b + (b.b - a.b) * t), + (Uint8)(a.a + (b.a - a.a) * t) + }; +} + +void AnimatedCursor::Render(SDL_Renderer* renderer) { + if (state != CursorState::ANIMATED && !isReversing) return; + SDL_SetRenderDrawColor(renderer, 20, 20, 30, 255); + + // Calculate current state based on reverse progress + float progress = isReversing ? reverseProgress : 0.0f; + + // Ease function for smooth animation + float eased = progress * progress * (3.0f - 2.0f * progress); // Smoothstep + + // Position where animation happens (click position or following mouse) + // float centerX = isReversing ? clickX : mouseX; + // float centerY = isReversing ? clickY : mouseY; + float centerX = mouseX; + float centerY = mouseY; + + for (const auto& p : pixels) { + // Calculate position in sphere + float sphereX = centerX + cos(p.currentAngle) * p.currentRadius; + float sphereY = centerY + sin(p.currentAngle) * p.currentRadius; + + // Interpolate position + int x, y; + if (isReversing) { + // During animation: sphere -> sprite at click position + x = (int)(sphereX + (centerX - FRAME_WIDTH/2 + p.srcX - sphereX) * eased); + y = (int)(sphereY + (centerY - FRAME_HEIGHT/2 + p.srcY - sphereY) * eased); + } else { + // Shuffled state (sphere following mouse) + x = (int)sphereX; + y = (int)sphereY; + } + + // Interpolate color + SDL_Color color; + if (isReversing) { + color = lerpColor(p.shuffledColor, p.originalColor, eased); + } else { + color = p.shuffledColor; + } + + SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); + SDL_RenderPoint(renderer, x, y); + } + +} + +void AnimatedCursor::Update(float deltaTime, float mx, float my) { + if (state != CursorState::ANIMATED && !isReversing) return; + mouseX = mx; mouseY = my; + time += deltaTime; + + // Update pixel positions (movement within sphere) + if (!isReversing) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<float> angleDist(0.0f, 2.0f * M_PI); + std::uniform_real_distribution<float> radiusDist(0.0f, SPHERE_RADIUS); + + for (auto& p : pixels) { + // Smoothly move toward target + float angleDiff = p.targetAngle - p.currentAngle; + // Normalize angle difference to [-PI, PI] + while (angleDiff > M_PI) angleDiff -= 2.0f * M_PI; + while (angleDiff < -M_PI) angleDiff += 2.0f * M_PI; + + p.currentAngle += angleDiff * p.angleSpeed * deltaTime; + p.currentRadius += (p.targetRadius - p.currentRadius) * p.radiusSpeed * deltaTime; + + // Check if close to target, if so pick new target + if (fabs(angleDiff) < 0.1f && fabs(p.targetRadius - p.currentRadius) < 1.0f) { + p.targetAngle = angleDist(gen); + p.targetRadius = radiusDist(gen); + } + } + } + + // Handle reverse animation and frame playback + if (isReversing) { + reverseProgress += deltaTime / ANIMATION_DURATION; + + if (reverseProgress >= 0.2f) { + // Unshuffle complete, now play through frames + if (!isPlayingAnimation) { + isPlayingAnimation = true; + currentFrame = 0; + reverseProgress = 0.0f; + } + } + + // Play through animation frames + if (isPlayingAnimation) { + // Play all 8 frames over remaining time + float frameTime = ANIMATION_DURATION / TOTAL_FRAMES; + currentFrame = (int)(reverseProgress / frameTime); + + if (currentFrame >= (int)TOTAL_FRAMES) { + // Animation complete, go back to frame 0 and reshuffle + currentFrame = 0; + pixels = allFrames[0]; + state_GenerateShuffle(); + isReversing = false; + isPlayingAnimation = false; + reverseProgress = 0.0f; + } else { + // Switch to current frame + if (currentFrame < (int)TOTAL_FRAMES && currentFrame >= 0) { + pixels = allFrames[(size_t)currentFrame]; + // Keep the shuffle state for smooth transition + for (size_t i = 0; i < pixels.size() && i < allFrames[0].size(); i++) { + pixels[i].currentAngle = allFrames[0][i].currentAngle; + pixels[i].currentRadius = allFrames[0][i].currentRadius; + pixels[i].targetAngle = allFrames[0][i].targetAngle; + pixels[i].targetRadius = allFrames[0][i].targetRadius; + pixels[i].angleSpeed = allFrames[0][i].angleSpeed; + pixels[i].radiusSpeed = allFrames[0][i].radiusSpeed; + pixels[i].shuffledColor = allFrames[0][i].shuffledColor; + } + } + } + + reverseProgress += deltaTime / ANIMATION_DURATION; + } + } +} + +void AnimatedCursor::mouse_OnClick() { + if (state != CursorState::ANIMATED) return; + if (isReversing) return; + + isReversing = true; + reverseProgress = 0.0f; + clickX = mouseX; + clickY = mouseY; +} + + +void AnimatedCursor::Cleanup() { + if (spriteTexture) SDL_DestroyTexture(spriteTexture); + if (spriteSurface) SDL_DestroySurface(spriteSurface); +} diff --git a/src/cursor/animated_cursor.hpp b/src/cursor/animated_cursor.hpp new file mode 100644 index 0000000..7d960d5 --- /dev/null +++ b/src/cursor/animated_cursor.hpp @@ -0,0 +1,75 @@ +// g++ -std=c++23 -O2 -Wall -Wextra animated_cursor.hpp.cpp $(pkg-config --cflags --libs sdl3 sdl3-image) -o cursor_particles && ./cursor_particles + +#pragma once + +#include <SDL3/SDL.h> +#include <SDL3_image/SDL_image.h> +#include <vector> +#include <algorithm> +#include <random> +#include <cmath> + + + +enum class CursorState : uint32_t { + NORMAL, + ANIMATED, + HIDDEN +}; + +struct Pixel { + int srcX, srcY; + float currentAngle; // Current angle in sphere + float currentRadius; // Current radius in sphere + float targetAngle; // Target angle for movement + float targetRadius; // Target radius for movement + float angleSpeed; // Speed of angle change + float radiusSpeed; // Speed of radius change + SDL_Color originalColor; + SDL_Color shuffledColor; +}; + +class AnimatedCursor { +private: + SDL_Texture* spriteTexture; + SDL_Surface* spriteSurface; + + std::vector<Pixel> pixels; + std::vector<std::vector<Pixel>> allFrames; // Store all 8 frames + bool isReversing; + float reverseProgress; + float time; // For continuous animation + float clickX, clickY; // Position where click happened + int currentFrame; // 0-7 for the 8 frames + bool isPlayingAnimation; // True when playing through frames + + const int FRAME_WIDTH = 64; // 512 / 8 frames + const int FRAME_HEIGHT = 64; + const int SPHERE_RADIUS = 16; // 32px diameter sphere + const size_t TOTAL_FRAMES = 8; + const float ANIMATION_DURATION = 1.2f; // Total time for unshuffle + frame play + +public: + CursorState state = CursorState::NORMAL; + float mouseX, mouseY; // Sphere follows cursor + AnimatedCursor(); + + ~AnimatedCursor(); + + bool Init(SDL_Renderer* renderer, const char* filename); + + void set_State(const CursorState& state_new); + + void frame_ExtractFirst(); + + void state_GenerateShuffle(); + + void Render(SDL_Renderer* renderer); + + void Update(float deltaTime, float mx, float my); + + void mouse_OnClick(); + + + void Cleanup(); +}; diff --git a/src/defaults/defaults.hpp b/src/defaults/defaults.hpp index 2d2d477..fd9b6b0 100644 --- a/src/defaults/defaults.hpp +++ b/src/defaults/defaults.hpp @@ -4,7 +4,6 @@ #include <vector> #include <stddef.h> - enum class WalkDirection { UP, LEFT, diff --git a/src/defaults/input.hpp b/src/defaults/input.hpp index 41cda38..f1a5636 100644 --- a/src/defaults/input.hpp +++ b/src/defaults/input.hpp @@ -3,6 +3,7 @@ #include <SDL3/SDL.h> #include <iostream> #include "defaults/defaults.hpp" +#include "cursor/animated_cursor.hpp" class Character; @@ -25,6 +26,7 @@ class Input { bool pressed_return_released = false; bool pressed_arrowdown_released = false; bool pressed_arrowup_released = false; + AnimatedCursor* cursor; SDL_FPoint mouse_state; SDL_FPoint mouse_state_raw; SDL_Point mouse_game_offset; diff --git a/src/game/game.cpp b/src/game/game.cpp index 71668e0..e9443ea 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -24,6 +24,7 @@ #include "building/research.hpp" #include "defaults/input.hpp" #include "start_screen/start_screen.hpp" +#include "cursor/animated_cursor.hpp" // Game class encapsulating SDL initialization and loop @@ -63,6 +64,12 @@ Game::Game() : running(true) { lastTicks = SDL_GetTicks(); + // INIT Cursor + SDL_HideCursor(); + cursor = input.cursor = new AnimatedCursor(); + cursor->Init(renderer, "Pixel_Crawler/Entities/Characters/Body_A/Animations/Slice_Base/Slice_Up.png"); + + // Music audio = new Audio(); Animation::audio = audio; @@ -114,13 +121,13 @@ void Game::set_State(GameState_e new_state, NewGameState_e game_state_e) { bool ret = false; switch (new_state) { case GameState_e::STATE_MODIFY: - ret = SDL_ShowCursor(); + cursor->set_State(CursorState::NORMAL); break; case GameState_e::STATE_MENU_MAIN: - ret = SDL_ShowCursor(); + cursor->set_State(CursorState::ANIMATED); break; case GameState_e::STATE_PLAYING: - ret = SDL_HideCursor(); + cursor->set_State(CursorState::HIDDEN); break; } if (!ret) { @@ -272,6 +279,9 @@ void Game::handle_Events() { win_size.h = h; break; } + case SDL_EVENT_MOUSE_BUTTON_DOWN: + cursor->mouse_OnClick(); + break; case SDL_EVENT_MOUSE_BUTTON_UP: input.click_left_released = true; input.click_left = false; @@ -370,6 +380,7 @@ void Game::handle_Events() { void Game::Update() { state_current->Update(this); + cursor->Update(Default::delta_time, input.mouse_state_raw.x, input.mouse_state_raw.y); } void Game::Render() { @@ -385,6 +396,8 @@ void Game::Render() { if (Ui::draw_key_info) Ui::draw_KeyInfo(this); + cursor->Render(renderer); + SDL_RenderPresent(renderer); } diff --git a/src/game/game.hpp b/src/game/game.hpp index d65fb94..09dfe3f 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -15,6 +15,7 @@ #include "audio/audio.hpp" class Input; +class AnimatedCursor; enum class NewGameState_e { @@ -36,6 +37,8 @@ public: Audio* audio = nullptr; + AnimatedCursor* cursor = nullptr; + bool is_cheating = false; std::unique_ptr<StatePlaying> state_playing; diff --git a/src/game/game_state.hpp b/src/game/game_state.hpp index bdb127a..144424f 100644 --- a/src/game/game_state.hpp +++ b/src/game/game_state.hpp @@ -4,6 +4,7 @@ #include <SDL3/SDL_mouse.h> #include "audio/audio.hpp" +#include "cursor/animated_cursor.hpp" class Game; class Input; @@ -24,5 +25,6 @@ public: bool is_Finished() const { return finished; } protected: Audio* audio = nullptr; + AnimatedCursor* cursor = nullptr; bool finished = false; }; diff --git a/src/game/state_menu_main.cpp b/src/game/state_menu_main.cpp index f3f8855..b074fed 100644 --- a/src/game/state_menu_main.cpp +++ b/src/game/state_menu_main.cpp @@ -22,6 +22,8 @@ bool StateMenuMain::Init(Game* game) { buttons.push_back({ MenuState::NEW, "New Game", {300, 200, 200, 50}, false}); buttons.push_back({ MenuState::QUIT, "Quit", {300, 320, 200, 50}, false}); buttons.push_back({ MenuState::NEW_CHEAT, "New Cheat", {300, 200, 200, 50}, false}); + cursor = game->cursor; + cursor->set_State(CursorState::ANIMATED); return true; } diff --git a/src/game/state_modify.cpp b/src/game/state_modify.cpp index 80ae20b..f30a757 100644 --- a/src/game/state_modify.cpp +++ b/src/game/state_modify.cpp @@ -14,6 +14,8 @@ bool StateModify::Init(Game* game) { //Tile::tileset_offset.x = Map::offset.x; //Tile::tileset_offset.y = Map::offset.y; + cursor = game->cursor; + cursor->state = CursorState::NORMAL; return true; } diff --git a/src/game/state_playing.cpp b/src/game/state_playing.cpp index df71b6a..c991c1b 100644 --- a/src/game/state_playing.cpp +++ b/src/game/state_playing.cpp @@ -24,6 +24,9 @@ bool StatePlaying::Init(Game* game) { Default::last = 0; Default::delta_time = 0.0; + cursor = game->cursor; + cursor->set_State(CursorState::HIDDEN); + player = std::make_unique<Character>(); player->Init(game->renderer); player->researched_items[static_cast<size_t>(ItemType::BUILDING_TOOL)] = true; @@ -92,15 +95,15 @@ bool StatePlaying::Init(Game* game) { return true; } -inline void setActiveMenu(CharacterMenuType& active_menu, const CharacterMenuType& new_menu) { +inline void setActiveMenu(CharacterMenuType& active_menu, const CharacterMenuType& new_menu, AnimatedCursor* cursor) { switch (active_menu) { case CharacterMenuType::NONE: active_menu = new_menu; - SDL_ShowCursor(); + cursor->set_State(CursorState::ANIMATED); break; default: active_menu = CharacterMenuType::NONE; - SDL_HideCursor(); + cursor->set_State(CursorState::HIDDEN); break; } } @@ -131,7 +134,7 @@ void StatePlaying::handle_Events(SDL_Event& event, Game* game) { if (player->selected_item->object_type == InventoryObjectType::ITEM) { sel_item = static_cast<InventoryItem*>(player->selected_item); if (sel_item->type == ItemType::BUILDING_TOOL) - setActiveMenu(player->active_menu, CharacterMenuType::BUILDING); + setActiveMenu(player->active_menu, CharacterMenuType::BUILDING, cursor); else player->messages->Add(MessageKey::BUILDING_TOOL_REQUIRED); } else @@ -142,7 +145,7 @@ void StatePlaying::handle_Events(SDL_Event& event, Game* game) { Inventory::selected_hotbar = !Inventory::selected_hotbar ? Inventory::selected_hotbar_last : 0; break; case SDL_SCANCODE_E: - setActiveMenu(player->active_menu, CharacterMenuType::INVENTORY); + setActiveMenu(player->active_menu, CharacterMenuType::INVENTORY, cursor); Inventory::draw_menu = !Inventory::draw_menu; break; case SDL_SCANCODE_K: {