From 2b7b60c4addb7ef6f8957b847cd2f41b05055e5d Mon Sep 17 00:00:00 2001 From: Mustafa Zaban Date: Fri, 7 Nov 2025 22:11:32 +0200 Subject: [PATCH 1/6] added clouds --- CMakeLists.txt | 2 ++ src/Cloud.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/Cloud.hpp | 17 +++++++++++++++++ src/Game.cpp | 16 ++++++++++++++++ src/Game.hpp | 4 +++- src/GameObject.hpp | 2 +- 6 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 src/Cloud.cpp create mode 100644 src/Cloud.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ca280a0..863c088 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES src/Player.cpp src/Platform.cpp src/Bird.cpp + src/Cloud.cpp ) set(HEADERS @@ -22,6 +23,7 @@ set(HEADERS src/Player.hpp src/Platform.hpp src/Bird.hpp + src/Cloud.hpp src/Common.hpp ) diff --git a/src/Cloud.cpp b/src/Cloud.cpp new file mode 100644 index 0000000..43fea65 --- /dev/null +++ b/src/Cloud.cpp @@ -0,0 +1,42 @@ +#include "Cloud.hpp" +#include +#include + +Cloud::Cloud(float x, float y, float width, float height) + : GameObject(x, y, width, height, Color{255, 255, 255, 200}) { // white with some transparency +} + +void Cloud::update(float deltaTime) { + // Move cloud slowly to the left + m_x -= m_speed * deltaTime; + // Reset cloud position if it goes off screen + if (m_x + m_width < 0) { + m_x = 1024; // screen width + } +} + +void Cloud::render(SDL_Renderer* renderer) const { + // Render a simple cloud as a filled white ellipse or circle approximation + SDL_SetRenderDrawColor(renderer, m_color.r, m_color.g, m_color.b, m_color.a); + // Simple cloud: draw 3 overlapping circles + int centerX = static_cast(m_x); + int centerY = static_cast(m_y); + int radius = static_cast(m_height / 2); + + // Draw 3 circles for cloud shape + for (int dx : std::initializer_list{-radius, 0, radius}) { + for (int dy : std::initializer_list{-radius / 2, 0, radius / 2}) { + int cx = centerX + dx; + int cy = centerY + dy; + for (int w = 0; w < radius * 2; ++w) { + for (int h = 0; h < radius * 2; ++h) { + int distX = radius - w; + int distY = radius - h; + if ((distX * distX + distY * distY) <= (radius * radius)) { + SDL_RenderDrawPoint(renderer, cx + w - radius, cy + h - radius); + } + } + } + } + } +} diff --git a/src/Cloud.hpp b/src/Cloud.hpp new file mode 100644 index 0000000..f9aa958 --- /dev/null +++ b/src/Cloud.hpp @@ -0,0 +1,17 @@ +#ifndef CLOUD_HPP +#define CLOUD_HPP + +#include "GameObject.hpp" + +class Cloud : public GameObject { +public: + Cloud(float x, float y, float width, float height); + void update(float deltaTime) override; + void render(SDL_Renderer* renderer) const override; + void setCameraOffset(float, float) override { /* Ignore camera movement */ } + +private: + float m_speed = 20.0f; // pixels per second +}; + +#endif // CLOUD_HPP diff --git a/src/Game.cpp b/src/Game.cpp index 03f1055..f117b69 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -3,6 +3,7 @@ #include "Player.hpp" #include "Platform.hpp" #include "Bird.hpp" +#include "Cloud.hpp" #include "Common.hpp" #include #include @@ -274,6 +275,11 @@ void Game::createLevel() { m_gameObjects.push_back(std::move(topPlatform)); } } + + // Create some clouds for background decoration + m_clouds.push_back(std::make_unique(100.0f, 100.0f, 120.0f, 60.0f)); + m_clouds.push_back(std::make_unique(400.0f, 80.0f, 150.0f, 70.0f)); + m_clouds.push_back(std::make_unique(700.0f, 110.0f, 130.0f, 65.0f)); } void Game::run() { @@ -389,6 +395,11 @@ void Game::update(float deltaTime) { // Update birds updateBirds(deltaTime); + // Update clouds + for (auto& cloud : m_clouds) { + cloud->update(deltaTime); + } + // Update player first m_player->update(deltaTime); @@ -611,6 +622,11 @@ void Game::render() { SDL_SetRenderDrawColor(m_renderer, 135, 206, 250, 255); // Light sky blue SDL_RenderClear(m_renderer); + // Render clouds in background + for (const auto& cloud : m_clouds) { + cloud->render(m_renderer); + } + // Render all game objects for (const auto& obj : m_gameObjects) { obj->render(m_renderer); diff --git a/src/Game.hpp b/src/Game.hpp index 448fa85..5961af8 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -8,6 +8,7 @@ #include "GameObject.hpp" #include "Player.hpp" #include "Bird.hpp" +#include "Cloud.hpp" class Game { public: @@ -45,7 +46,8 @@ class Game { std::vector> m_gameObjects; std::unique_ptr m_player; std::vector> m_birds; - + std::vector> m_clouds; + // World and camera properties float m_worldWidth = 2000.0f; float m_cameraX = 0.0f; diff --git a/src/GameObject.hpp b/src/GameObject.hpp index b7b7160..3a8d76c 100644 --- a/src/GameObject.hpp +++ b/src/GameObject.hpp @@ -18,7 +18,7 @@ class GameObject { float getWidth() const { return m_width; } float getHeight() const { return m_height; } - void setCameraOffset(float x, float y) { m_cameraOffsetX = x; m_cameraOffsetY = y; } + virtual void setCameraOffset(float x, float y) { m_cameraOffsetX = x; m_cameraOffsetY = y; } protected: float m_x, m_y; From b4b2ee5657b744745d643f4394f1a6bc21158d90 Mon Sep 17 00:00:00 2001 From: Mustafa Zaban Date: Fri, 7 Nov 2025 22:22:16 +0200 Subject: [PATCH 2/6] updated distance tracking --- src/Game.cpp | 6 +----- src/Player.cpp | 9 ++++----- src/Player.hpp | 7 +++---- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Game.cpp b/src/Game.cpp index f117b69..06fa950 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -406,11 +406,7 @@ void Game::update(float deltaTime) { // Reset grounded state - will be set to true if standing on something m_player->setGrounded(false); - // Update distance traveled (only when moving right and game is not over) - if (!m_gameOver && m_player->getVelX() > 0) { - float distanceDelta = m_player->getVelX() * deltaTime; - m_player->updateDistance(distanceDelta); - } + // Distance is now tracked in Player::update() to only count progress to the right // Check for platform and ground collisions bool onGround = false; diff --git a/src/Player.cpp b/src/Player.cpp index de9e4ae..5edf83a 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -37,14 +37,13 @@ void Player::update(float deltaTime) { } } - // Update position and track distance - float oldX = m_x; + // Update position m_x += m_velX * deltaTime; m_y += m_velY * deltaTime; - // Track distance traveled (only when moving right) - if (m_x > oldX) { - m_distanceTraveled += (m_x - oldX); + // Update maximum distance traveled to the right + if (m_x > m_maxRightDistance) { + m_maxRightDistance = m_x; } // Only prevent going off the left edge of the world diff --git a/src/Player.hpp b/src/Player.hpp index d5920e4..1f0bbe2 100644 --- a/src/Player.hpp +++ b/src/Player.hpp @@ -47,9 +47,8 @@ class Player { bool isAlive() const { return m_lives > 0; } // Distance tracking - float getDistanceTraveled() const { return m_distanceTraveled; } - void updateDistance(float deltaX) { if (deltaX > 0) m_distanceTraveled += deltaX; } - void resetDistance() { m_distanceTraveled = 0.0f; } + float getDistanceTraveled() const { return m_maxRightDistance; } + void resetDistance() { m_maxRightDistance = 0.0f; } // Knockback for collision void applyKnockback(float forceX, float forceY) { @@ -92,7 +91,7 @@ class Player { int m_lives = 3; // Distance tracking - float m_distanceTraveled = 0.0f; + float m_maxRightDistance = 0.0f; // Tracks the rightmost position reached }; #endif // PLAYER_HPP From 49f4e9a8acac87cc57513ac52095569c56dc1395 Mon Sep 17 00:00:00 2001 From: Mustafa Zaban Date: Fri, 7 Nov 2025 23:07:12 +0200 Subject: [PATCH 3/6] improved game over screen --- CMakeLists.txt | 2 + src/Game.cpp | 245 +++++++++++++++++++++++++++++++++++++------------ src/Game.hpp | 2 + src/Sign.cpp | 225 +++++++++++++++++++++++++++++++++++++++++++++ src/Sign.hpp | 45 +++++++++ 5 files changed, 459 insertions(+), 60 deletions(-) create mode 100644 src/Sign.cpp create mode 100644 src/Sign.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 863c088..bf2780b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ set(SOURCES src/Platform.cpp src/Bird.cpp src/Cloud.cpp + src/Sign.cpp ) set(HEADERS @@ -24,6 +25,7 @@ set(HEADERS src/Platform.hpp src/Bird.hpp src/Cloud.hpp + src/Sign.hpp src/Common.hpp ) diff --git a/src/Game.cpp b/src/Game.cpp index 06fa950..d6ca8db 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -280,6 +280,8 @@ void Game::createLevel() { m_clouds.push_back(std::make_unique(100.0f, 100.0f, 120.0f, 60.0f)); m_clouds.push_back(std::make_unique(400.0f, 80.0f, 150.0f, 70.0f)); m_clouds.push_back(std::make_unique(700.0f, 110.0f, 130.0f, 65.0f)); + + // Sign will be created when game is over } void Game::run() { @@ -622,6 +624,11 @@ void Game::render() { for (const auto& cloud : m_clouds) { cloud->render(m_renderer); } + + // Render the MACHI sign + if (m_sign) { + m_sign->render(m_renderer); + } // Render all game objects for (const auto& obj : m_gameObjects) { @@ -754,6 +761,9 @@ void Game::restartGame() { m_player->setVelY(0.0f); m_invulnerabilityTimer = 0.0f; + // Clear the sign when starting a new game + m_sign.reset(); + // Clear birds m_birds.clear(); m_birdSpawnTimer = 0.0f; @@ -856,103 +866,218 @@ void Game::renderUI() { SDL_Rect overlay = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT}; SDL_RenderFillRect(m_renderer, &overlay); - // Draw MACHI box with red border + // Position GAME OVER box higher on the screen + const int gameOverBoxY = SCREEN_HEIGHT/2 - 250; // Moved up from center + + // Draw GAME OVER box with red border and black background SDL_SetRenderDrawColor(m_renderer, 255, 0, 0, 255); // Red border - SDL_Rect gameOverBg = {SCREEN_WIDTH/2 - 220, SCREEN_HEIGHT/2 - 150, 440, 80}; - SDL_RenderFillRect(m_renderer, &gameOverBg); + SDL_Rect gameOverOuter = {SCREEN_WIDTH/2 - 350, gameOverBoxY, 700, 180}; + SDL_RenderFillRect(m_renderer, &gameOverOuter); - // White inner box - SDL_SetRenderDrawColor(m_renderer, 255, 255, 255, 255); - SDL_Rect gameOverInner = {SCREEN_WIDTH/2 - 215, SCREEN_HEIGHT/2 - 145, 430, 70}; + // Black inner box + SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255); + SDL_Rect gameOverInner = {SCREEN_WIDTH/2 - 345, gameOverBoxY + 5, 690, 170}; SDL_RenderFillRect(m_renderer, &gameOverInner); - // Draw MACHI text - if (m_font) { - SDL_Color redColor = {255, 0, 0, 255}; - SDL_Surface* machiSurface = TTF_RenderText_Blended(m_font, "MACHI", redColor); - if (machiSurface) { - SDL_Texture* machiTexture = SDL_CreateTextureFromSurface(m_renderer, machiSurface); - if (machiTexture) { - int textW = machiSurface->w; - int textH = machiSurface->h; + // Draw "GAME OVER" text in bright red with a much larger font + TTF_Font* largeFont = TTF_OpenFont("assets/fonts/impact.ttf", 96); + if (!largeFont) { + largeFont = TTF_OpenFont("/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf", 96); + if (!largeFont) { + largeFont = TTF_OpenFont("assets/fonts/arialbd.ttf", 96); + if (!largeFont) { + largeFont = TTF_OpenFont("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 96); + if (!largeFont) { + // Last resort fallback to any available font + largeFont = TTF_OpenFont("assets/fonts/arial.ttf", 96); + if (!largeFont) { + largeFont = TTF_OpenFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 96); + } + } + } + } + } + + if (largeFont) { + // Make the font bright red with a slight glow effect + SDL_Color brightRed = {255, 30, 30, 255}; + + // Render the text with a slight offset to create a glow effect + SDL_Surface* shadowSurface = TTF_RenderText_Blended(largeFont, "GAME OVER", {255, 0, 0, 200}); + SDL_Surface* gameOverSurface = TTF_RenderText_Blended(largeFont, "GAME OVER", brightRed); + + // Apply the glow effect if both surfaces were created + if (shadowSurface && gameOverSurface) { + // The shadow is handled by the order of rendering below + } else if (!gameOverSurface && shadowSurface) { + // If only shadow was created, use that + gameOverSurface = shadowSurface; + shadowSurface = nullptr; + } + if (gameOverSurface) { + SDL_Texture* gameOverTexture = SDL_CreateTextureFromSurface(m_renderer, gameOverSurface); + if (gameOverTexture) { + int textW = gameOverSurface->w; + int textH = gameOverSurface->h; + // Center the text in the box with a slight shadow for depth + if (shadowSurface) { + SDL_Texture* shadowTexture = SDL_CreateTextureFromSurface(m_renderer, shadowSurface); + if (shadowTexture) { + SDL_Rect shadowRect = { + SCREEN_WIDTH/2 - textW/2 + 4, // Slight offset for shadow + gameOverBoxY + 90 - textH/2 + 4, // Center in the game over box + textW, + textH + }; + SDL_RenderCopy(m_renderer, shadowTexture, NULL, &shadowRect); + SDL_DestroyTexture(shadowTexture); + } + SDL_FreeSurface(shadowSurface); + } + + // Position text in the center of the game over box SDL_Rect dstRect = { SCREEN_WIDTH/2 - textW/2, - SCREEN_HEIGHT/2 - 130, + gameOverBoxY + 90 - textH/2, // Center in the game over box textW, textH }; - SDL_RenderCopy(m_renderer, machiTexture, NULL, &dstRect); - SDL_DestroyTexture(machiTexture); + SDL_RenderCopy(m_renderer, gameOverTexture, NULL, &dstRect); + SDL_DestroyTexture(gameOverTexture); } - SDL_FreeSurface(machiSurface); + SDL_FreeSurface(gameOverSurface); } + TTF_CloseFont(largeFont); } - // Draw final distance box - SDL_SetRenderDrawColor(m_renderer, 100, 100, 255, 255); - SDL_Rect distanceBg2 = {SCREEN_WIDTH/2 - 200, SCREEN_HEIGHT/2 - 40, 400, 50}; + // Create and render the MACHI sign (larger and with effects) + if (!m_sign) { + float signX = static_cast(SCREEN_WIDTH) * 0.5f - 100.0f; // Shift sign to the right + float signY = 100.0f; // Position from top + m_sign = std::make_unique( + signX, // x position (centered) + signY, // y position from top + "MACHI", // text + Color{255, 50, 50, 255} // bright red color + ); + m_sign->setEffectSpeed(2.5f); // Slightly faster pulsing + m_sign->setScale(8.0f); // Make it even bigger + } else { + // Update position in case window was resized + float signX = static_cast(SCREEN_WIDTH) * 0.5f - 150.0f; + m_sign->setPosition(signX, 100.0f); + } + m_sign->render(m_renderer); + + // Draw final distance box (moved down to make room for game over text) + const int distanceBoxY = SCREEN_HEIGHT/2 - 40; // Moved down from center + + // Draw outer blue box + SDL_SetRenderDrawColor(m_renderer, 0, 0, 200, 255); // Darker blue + SDL_Rect distanceBg2 = {SCREEN_WIDTH/2 - 220, distanceBoxY, 440, 70}; // Taller box SDL_RenderFillRect(m_renderer, &distanceBg2); - SDL_SetRenderDrawColor(m_renderer, 255, 255, 255, 255); - SDL_Rect distanceInner = {SCREEN_WIDTH/2 - 195, SCREEN_HEIGHT/2 - 35, 390, 40}; + // Draw inner white box + SDL_SetRenderDrawColor(m_renderer, 240, 240, 255, 255); // Light blue-white + SDL_Rect distanceInner = {SCREEN_WIDTH/2 - 215, distanceBoxY + 5, 430, 60}; SDL_RenderFillRect(m_renderer, &distanceInner); // Draw final distance text with font - SDL_Color blueColor = {0, 0, 255, 255}; + SDL_Color blueColor = {0, 0, 150, 255}; // Darker blue for better contrast char finalDistStr[30]; snprintf(finalDistStr, sizeof(finalDistStr), "FINAL DISTANCE: %d", distanceMeters); - SDL_Surface* finalDistSurface = TTF_RenderText_Solid(m_font, finalDistStr, blueColor); + // Use a slightly larger font for the distance + TTF_Font* distanceFont = TTF_OpenFont("assets/fonts/arialbd.ttf", 28); + if (!distanceFont) { + distanceFont = TTF_OpenFont("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 28); + if (!distanceFont) distanceFont = m_font; // Fall back to default font + } + + SDL_Surface* finalDistSurface = TTF_RenderText_Blended(distanceFont ? distanceFont : m_font, finalDistStr, blueColor); if (finalDistSurface) { SDL_Texture* finalDistTexture = SDL_CreateTextureFromSurface(m_renderer, finalDistSurface); if (finalDistTexture) { int textW = finalDistSurface->w; int textH = finalDistSurface->h; - SDL_Rect dstRect = {SCREEN_WIDTH/2 - textW/2, SCREEN_HEIGHT/2 - 25, textW, textH}; + // Center the text in the distance box + SDL_Rect dstRect = { + SCREEN_WIDTH/2 - textW/2, + distanceBoxY + 35 - textH/2, // Vertically center in the box + textW, + textH + }; SDL_RenderCopy(m_renderer, finalDistTexture, NULL, &dstRect); SDL_DestroyTexture(finalDistTexture); } SDL_FreeSurface(finalDistSurface); } - // Draw "INSERT A COIN FOR NEW GAME" message - SDL_Color goldColor = {255, 200, 0, 255}; - const char* coinMsg = "INSERT A COIN FOR NEW GAME"; + if (distanceFont && distanceFont != m_font) { + TTF_CloseFont(distanceFont); + } - // Create a larger font for the coin message - TTF_Font* largeFont = TTF_OpenFont("assets/fonts/arial.ttf", 28); - if (!largeFont) { - largeFont = TTF_OpenFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 28); + // Draw "INSERT COIN" message with flashing effect + static Uint32 lastFlashTime = SDL_GetTicks(); + static bool flashVisible = true; + Uint32 currentTime = SDL_GetTicks(); + + // Toggle visibility every 500ms for flashing effect + if (currentTime - lastFlashTime > 500) { + flashVisible = !flashVisible; + lastFlashTime = currentTime; } - if (largeFont) { - SDL_Surface* coinSurface = TTF_RenderText_Solid(largeFont, coinMsg, goldColor); - if (coinSurface) { - SDL_Texture* coinTexture = SDL_CreateTextureFromSurface(m_renderer, coinSurface); - if (coinTexture) { - // Draw background - SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255); - SDL_Rect bgRect = { - SCREEN_WIDTH/2 - coinSurface->w/2 - 10, - SCREEN_HEIGHT/2 + 50, - coinSurface->w + 20, - coinSurface->h + 10 - }; - SDL_RenderFillRect(m_renderer, &bgRect); - - // Draw text - SDL_Rect textRect = { - SCREEN_WIDTH/2 - coinSurface->w/2, - SCREEN_HEIGHT/2 + 55, - coinSurface->w, - coinSurface->h - }; - SDL_RenderCopy(m_renderer, coinTexture, NULL, &textRect); - SDL_DestroyTexture(coinTexture); + if (flashVisible) { + const char* coinMsg = "INSERT COIN"; + + // Create a larger font for the coin message + TTF_Font* largeFont = TTF_OpenFont("assets/fonts/arial.ttf", 32); + if (!largeFont) { + largeFont = TTF_OpenFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 32); + } + + if (largeFont) { + SDL_Color redColor = {255, 0, 0, 255}; + SDL_Surface* coinSurface = TTF_RenderText_Blended(largeFont, coinMsg, redColor); + if (coinSurface) { + SDL_Texture* coinTexture = SDL_CreateTextureFromSurface(m_renderer, coinSurface); + if (coinTexture) { + // Draw black background with red border + SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255); + SDL_Rect bgRect = { + SCREEN_WIDTH/2 - coinSurface->w/2 - 15, + SCREEN_HEIGHT/2 + 50, + coinSurface->w + 30, + coinSurface->h + 20 + }; + // Draw red border + SDL_SetRenderDrawColor(m_renderer, 255, 0, 0, 255); + SDL_RenderDrawRect(m_renderer, &bgRect); + // Draw inner black area + SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255); + SDL_Rect innerRect = { + bgRect.x + 2, + bgRect.y + 2, + bgRect.w - 4, + bgRect.h - 4 + }; + SDL_RenderFillRect(m_renderer, &innerRect); + + // Draw text + SDL_Rect textRect = { + SCREEN_WIDTH/2 - coinSurface->w/2, + SCREEN_HEIGHT/2 + 60, + coinSurface->w, + coinSurface->h + }; + SDL_RenderCopy(m_renderer, coinTexture, NULL, &textRect); + SDL_DestroyTexture(coinTexture); + } + SDL_FreeSurface(coinSurface); } - SDL_FreeSurface(coinSurface); + TTF_CloseFont(largeFont); } - TTF_CloseFont(largeFont); } } } diff --git a/src/Game.hpp b/src/Game.hpp index 5961af8..7238c18 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -8,6 +8,7 @@ #include "GameObject.hpp" #include "Player.hpp" #include "Bird.hpp" +#include "Sign.hpp" #include "Cloud.hpp" class Game { @@ -46,6 +47,7 @@ class Game { std::vector> m_gameObjects; std::unique_ptr m_player; std::vector> m_birds; + std::unique_ptr m_sign; std::vector> m_clouds; // World and camera properties diff --git a/src/Sign.cpp b/src/Sign.cpp new file mode 100644 index 0000000..198808e --- /dev/null +++ b/src/Sign.cpp @@ -0,0 +1,225 @@ +#include "Sign.hpp" +#include +#include +#include + +/// 5x7 font data (1 = pixel on, 0 = pixel off) +// Each character is represented by 7 bytes (rows), each byte is a row of pixels (5 bits) +const uint8_t Sign::FONT[][7] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // (space) + { 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04 }, // ! + { 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00 }, // " + { 0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A }, // # + { 0x0E, 0x15, 0x14, 0x0E, 0x05, 0x15, 0x0E }, // $ + { 0x11, 0x11, 0x02, 0x04, 0x08, 0x11, 0x11 }, // % + { 0x0C, 0x12, 0x14, 0x08, 0x15, 0x12, 0x0D }, // & + { 0x04, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00 }, // ' + { 0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02 }, // ( + { 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08 }, // ) + { 0x00, 0x0A, 0x04, 0x1F, 0x04, 0x0A, 0x00 }, // * + { 0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00 }, // + + { 0x00, 0x00, 0x00, 0x00, 0x0C, 0x04, 0x08 }, // , + { 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00 }, // - + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C }, // . + { 0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x10 }, // / + { 0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E }, // 0 + { 0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E }, // 1 + { 0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F }, // 2 + { 0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E }, // 3 + { 0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02 }, // 4 + { 0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E }, // 5 + { 0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E }, // 6 + { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08 }, // 7 + { 0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E }, // 8 + { 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C }, // 9 + { 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00 }, // : + { 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x04, 0x08 }, // ; + { 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02 }, // < + { 0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00 }, // = + { 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08 }, // > + { 0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04 }, // ? + { 0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0F }, // @ + { 0x04, 0x0A, 0x11, 0x11, 0x1F, 0x11, 0x11 }, // A + { 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E }, // B + { 0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E }, // C + { 0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C }, // D + { 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x1F }, // E + { 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x10, 0x10 }, // F + { 0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F }, // G + { 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11 }, // H + { 0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E }, // I + { 0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C }, // J + { 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11 }, // K + { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F }, // L + { 0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11 }, // M + { 0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x11 }, // N + { 0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E }, // O + { 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10 }, // P + { 0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D }, // Q + { 0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11 }, // R + { 0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E }, // S + { 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }, // T + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E }, // U + { 0x11, 0x11, 0x11, 0x0A, 0x0A, 0x0A, 0x04 }, // V + { 0x11, 0x11, 0x11, 0x15, 0x15, 0x1B, 0x11 }, // W + { 0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11 }, // X + { 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04 }, // Y + { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F }, // Z + { 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E }, // [ + { 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01 }, // backslash + { 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E }, // ] + { 0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00 }, // ^ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F }, // _ + { 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ` + { 0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F }, // a + { 0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x1E }, // b + { 0x00, 0x00, 0x0E, 0x11, 0x10, 0x11, 0x0E }, // c + { 0x01, 0x01, 0x0F, 0x11, 0x11, 0x11, 0x0F }, // d + { 0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E }, // e + { 0x06, 0x09, 0x08, 0x1C, 0x08, 0x08, 0x08 }, // f + { 0x00, 0x0F, 0x11, 0x11, 0x0F, 0x01, 0x0E }, // g + { 0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, 0x11 }, // h + { 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x0E }, // i + { 0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0C }, // j + { 0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12 }, // k + { 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E }, // l + { 0x00, 0x00, 0x1A, 0x15, 0x15, 0x11, 0x11 }, // m + { 0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11 }, // n + { 0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E }, // o + { 0x00, 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10 }, // p + { 0x00, 0x0F, 0x11, 0x11, 0x0F, 0x01, 0x01 }, // q + { 0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10 }, // r + { 0x00, 0x00, 0x0F, 0x10, 0x0E, 0x01, 0x1E }, // s + { 0x08, 0x08, 0x1C, 0x08, 0x08, 0x09, 0x06 }, // t + { 0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0D }, // u + { 0x00, 0x00, 0x11, 0x11, 0x0A, 0x0A, 0x04 }, // v + { 0x00, 0x00, 0x11, 0x15, 0x15, 0x15, 0x0A }, // w + { 0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11 }, // x + { 0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E }, // y + { 0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F }, // z + { 0x02, 0x04, 0x04, 0x08, 0x04, 0x04, 0x02 }, // { + { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }, // | + { 0x08, 0x04, 0x04, 0x02, 0x04, 0x04, 0x08 } // } +}; + +Sign::Sign(float x, float y, const std::string& text, const Color& color) + : GameObject(x, y, (CHAR_WIDTH + CHAR_SPACING) * text.length() * 3, CHAR_HEIGHT * 3, color) + , m_text(text) { + // Convert text to uppercase for the sign + std::transform(m_text.begin(), m_text.end(), m_text.begin(), ::toupper); +} + +void Sign::update(float deltaTime) { + if (m_effectEnabled) { + m_effectTime += deltaTime * m_effectSpeed; + } +} + +void Sign::render(SDL_Renderer* renderer) const { + if (m_text.empty()) return; + + float x = m_x - m_cameraOffsetX; + float y = m_y - m_cameraOffsetY; + + // Calculate total width and height of the sign + float totalWidth = m_text.length() * (CHAR_WIDTH + CHAR_SPACING) * m_scale; + float totalHeight = (CHAR_HEIGHT + 2) * m_scale; + + // Draw outer border (dark) + SDL_SetRenderDrawColor(renderer, 40, 40, 80, 200); + SDL_FRect outerBorder = {x - 15, y - 15, totalWidth + 30, totalHeight + 30}; + SDL_RenderFillRectF(renderer, &outerBorder); + + // Draw inner border (lighter) + SDL_SetRenderDrawColor(renderer, 80, 80, 150, 220); + SDL_FRect innerBorder = {x - 10, y - 10, totalWidth + 20, totalHeight + 20}; + SDL_RenderFillRectF(renderer, &innerBorder); + + // Draw gradient background + for (int i = 0; i < totalHeight + 10; i++) { + float ratio = static_cast(i) / (totalHeight + 10); + SDL_SetRenderDrawColor(renderer, + static_cast(20 + ratio * 40), + static_cast(20 + ratio * 30), + static_cast(60 + ratio * 40), + 230); + SDL_RenderDrawLineF(renderer, x - 5, y - 5 + i, x + totalWidth + 5, y - 5 + i); + } + + // Draw pixel decorations + SDL_SetRenderDrawColor(renderer, 255, 255, 100, 100); + for (int i = 0; i < 4; i++) { + // Top-left corner decoration + SDL_RenderDrawPointF(renderer, x - 12 + i, y - 12); + SDL_RenderDrawPointF(renderer, x - 12, y - 12 + i); + // Top-right corner decoration + SDL_RenderDrawPointF(renderer, x + totalWidth + 12 - i, y - 12); + SDL_RenderDrawPointF(renderer, x + totalWidth + 12, y - 12 + i); + // Bottom-left corner decoration + SDL_RenderDrawPointF(renderer, x - 12 + i, y + totalHeight + 12); + SDL_RenderDrawPointF(renderer, x - 12, y + totalHeight + 12 - i); + // Bottom-right corner decoration + SDL_RenderDrawPointF(renderer, x + totalWidth + 12 - i, y + totalHeight + 12); + SDL_RenderDrawPointF(renderer, x + totalWidth + 12, y + totalHeight + 12 - i); + } + + // Draw each character with a slight offset for 3D effect + for (size_t i = 0; i < m_text.length(); ++i) { + // Shadow + drawChar(renderer, m_text[i], + x + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale + 2, + y + 2, + m_scale, + {0, 0, 0, 128}); + + // Main text with pulsing effect + float pulse = m_effectEnabled ? (std::sin(m_effectTime * 2.0f) * 0.1f + 0.9f) : 1.0f; + Uint8 red = static_cast(m_color.r * pulse); + Uint8 green = static_cast(m_color.g * pulse * 0.8f); + Uint8 blue = static_cast(m_color.b * pulse * 0.6f); + + drawChar(renderer, m_text[i], + x + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale, + y, + m_scale, + {red, green, blue, m_color.a}); + } +} + +void Sign::drawChar(SDL_Renderer* renderer, char c, float x, float y, float scale, const Color& color) const { + // Convert character to uppercase and get font index + c = toupper(c); + int charIndex = (c >= ' ' && c <= '}') ? (c - ' ') : 0; + + // Make sure the character index is within bounds + const int numChars = sizeof(FONT) / (sizeof(uint8_t) * 7); + if (charIndex < 0 || charIndex >= numChars) { + charIndex = 0; // Default to space if character not found + } + + // Draw each pixel of the character + for (int row = 0; row < CHAR_HEIGHT; ++row) { + uint8_t rowData = FONT[charIndex][row]; + + for (int col = 0; col < CHAR_WIDTH; ++col) { + if (rowData & (1 << (4 - col))) { // Check each bit from left to right + // Add a simple pulsing effect + float pulse = m_effectEnabled ? (sinf(m_effectTime * 3.0f + row * 0.5f) * 0.3f + 0.7f) : 1.0f; + + SDL_SetRenderDrawColor(renderer, + static_cast(color.r * pulse), + static_cast(color.g * pulse), + static_cast(color.b * pulse), + color.a); + + SDL_Rect pixel = { + static_cast(x + col * scale), + static_cast(y + row * scale), + static_cast(scale), + static_cast(scale) + }; + SDL_RenderFillRect(renderer, &pixel); + } + } + } +} diff --git a/src/Sign.hpp b/src/Sign.hpp new file mode 100644 index 0000000..491f8eb --- /dev/null +++ b/src/Sign.hpp @@ -0,0 +1,45 @@ +#ifndef SIGN_HPP +#define SIGN_HPP + +#include "GameObject.hpp" +#include +#include +#include + +class Sign : public GameObject { +public: + Sign(float x, float y, const std::string& text, const Color& color = {255, 255, 255, 255}); + + void update(float deltaTime) override; + void render(SDL_Renderer* renderer) const override; + + void setEffectEnabled(bool enabled) { m_effectEnabled = enabled; } + void setEffectSpeed(float speed) { m_effectSpeed = speed; } + void setScale(float scale) { m_scale = scale; } + +private: + std::string m_text; + bool m_effectEnabled = true; + float m_effectTime = 0.0f; + float m_effectSpeed = 2.0f; + float m_scale = 3.0f; // Scaling factor for the sign + + // 8x8 font data for each character (simplified) + static constexpr int CHAR_WIDTH = 5; + static constexpr int CHAR_HEIGHT = 7; + static constexpr int CHAR_SPACING = 1; + + // Simple 5x7 font data (1 = pixel on, 0 = pixel off) + static const uint8_t FONT[][7]; + + void drawChar(SDL_Renderer* renderer, char c, float x, float y, float scale, const Color& color) const; + + // Helper method to draw a pixel with scaling + void drawPixel(SDL_Renderer* renderer, float x, float y, float scale, const Color& color) const { + SDL_FRect pixel = {x, y, scale, scale}; + SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); + SDL_RenderFillRectF(renderer, &pixel); + } +}; + +#endif // SIGN_HPP From 88a4ef920b58ad29c76996ff73eb56427385533f Mon Sep 17 00:00:00 2001 From: Mustafa Zaban Date: Fri, 7 Nov 2025 23:45:10 +0200 Subject: [PATCH 4/6] aligned text game over --- src/Game.cpp | 65 +++++++++++++++++----------------------------------- src/Sign.cpp | 17 ++++++++++---- src/Sign.hpp | 2 ++ 3 files changed, 36 insertions(+), 48 deletions(-) diff --git a/src/Game.cpp b/src/Game.cpp index d6ca8db..2d27d38 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -866,17 +866,17 @@ void Game::renderUI() { SDL_Rect overlay = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT}; SDL_RenderFillRect(m_renderer, &overlay); - // Position GAME OVER box higher on the screen - const int gameOverBoxY = SCREEN_HEIGHT/2 - 250; // Moved up from center + // Position GAME OVER box (slightly lower than before) + const int gameOverBoxY = SCREEN_HEIGHT/2 - 200; // Moved down a bit // Draw GAME OVER box with red border and black background SDL_SetRenderDrawColor(m_renderer, 255, 0, 0, 255); // Red border - SDL_Rect gameOverOuter = {SCREEN_WIDTH/2 - 350, gameOverBoxY, 700, 180}; + SDL_Rect gameOverOuter = {SCREEN_WIDTH/2 - 350, gameOverBoxY+95, 700, 110}; SDL_RenderFillRect(m_renderer, &gameOverOuter); // Black inner box SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255); - SDL_Rect gameOverInner = {SCREEN_WIDTH/2 - 345, gameOverBoxY + 5, 690, 170}; + SDL_Rect gameOverInner = {SCREEN_WIDTH/2 - 345, gameOverBoxY + 100, 690, 100}; SDL_RenderFillRect(m_renderer, &gameOverInner); // Draw "GAME OVER" text in bright red with a much larger font @@ -899,46 +899,21 @@ void Game::renderUI() { } if (largeFont) { - // Make the font bright red with a slight glow effect + // Make the font bright red SDL_Color brightRed = {255, 30, 30, 255}; - - // Render the text with a slight offset to create a glow effect - SDL_Surface* shadowSurface = TTF_RenderText_Blended(largeFont, "GAME OVER", {255, 0, 0, 200}); SDL_Surface* gameOverSurface = TTF_RenderText_Blended(largeFont, "GAME OVER", brightRed); - // Apply the glow effect if both surfaces were created - if (shadowSurface && gameOverSurface) { - // The shadow is handled by the order of rendering below - } else if (!gameOverSurface && shadowSurface) { - // If only shadow was created, use that - gameOverSurface = shadowSurface; - shadowSurface = nullptr; - } if (gameOverSurface) { SDL_Texture* gameOverTexture = SDL_CreateTextureFromSurface(m_renderer, gameOverSurface); if (gameOverTexture) { int textW = gameOverSurface->w; int textH = gameOverSurface->h; - // Center the text in the box with a slight shadow for depth - if (shadowSurface) { - SDL_Texture* shadowTexture = SDL_CreateTextureFromSurface(m_renderer, shadowSurface); - if (shadowTexture) { - SDL_Rect shadowRect = { - SCREEN_WIDTH/2 - textW/2 + 4, // Slight offset for shadow - gameOverBoxY + 90 - textH/2 + 4, // Center in the game over box - textW, - textH - }; - SDL_RenderCopy(m_renderer, shadowTexture, NULL, &shadowRect); - SDL_DestroyTexture(shadowTexture); - } - SDL_FreeSurface(shadowSurface); - } + // No shadow effect, just center the text // Position text in the center of the game over box SDL_Rect dstRect = { SCREEN_WIDTH/2 - textW/2, - gameOverBoxY + 90 - textH/2, // Center in the game over box + gameOverBoxY + 131 - textH/2 + 20, // Center in the game over box, slightly lower textW, textH }; @@ -950,27 +925,29 @@ void Game::renderUI() { TTF_CloseFont(largeFont); } - // Create and render the MACHI sign (larger and with effects) + // Create and render the MACHI sign (centered above GAME OVER) if (!m_sign) { - float signX = static_cast(SCREEN_WIDTH) * 0.5f - 100.0f; // Shift sign to the right - float signY = 100.0f; // Position from top + // Center the sign horizontally + float signX = static_cast(SCREEN_WIDTH) * 0.5f - 100; // Centered + float signY = 80.0f; // Slightly lower than before m_sign = std::make_unique( - signX, // x position (centered) - signY, // y position from top + signX, // x position (aligned with GAME OVER) + signY, // y position (higher up) "MACHI", // text Color{255, 50, 50, 255} // bright red color ); m_sign->setEffectSpeed(2.5f); // Slightly faster pulsing - m_sign->setScale(8.0f); // Make it even bigger + m_sign->setScale(6.0f); // Slightly smaller to fit better + m_sign->setTextAlignment(1.0f); // Center text within the sign } else { // Update position in case window was resized - float signX = static_cast(SCREEN_WIDTH) * 0.5f - 150.0f; - m_sign->setPosition(signX, 100.0f); + float signX = static_cast(SCREEN_WIDTH) * 0.5f - 100; + m_sign->setPosition(signX, 80.0f); } m_sign->render(m_renderer); - // Draw final distance box (moved down to make room for game over text) - const int distanceBoxY = SCREEN_HEIGHT/2 - 40; // Moved down from center + // Draw final distance box (positioned below GAME OVER) + const int distanceBoxY = SCREEN_HEIGHT/2 + 95; // Slightly lower than before // Draw outer blue box SDL_SetRenderDrawColor(m_renderer, 0, 0, 200, 255); // Darker blue @@ -1047,7 +1024,7 @@ void Game::renderUI() { SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 255); SDL_Rect bgRect = { SCREEN_WIDTH/2 - coinSurface->w/2 - 15, - SCREEN_HEIGHT/2 + 50, + SCREEN_HEIGHT/2 + 180, coinSurface->w + 30, coinSurface->h + 20 }; @@ -1067,7 +1044,7 @@ void Game::renderUI() { // Draw text SDL_Rect textRect = { SCREEN_WIDTH/2 - coinSurface->w/2, - SCREEN_HEIGHT/2 + 60, + SCREEN_HEIGHT/2 + 190, coinSurface->w, coinSurface->h }; diff --git a/src/Sign.cpp b/src/Sign.cpp index 198808e..6943e8c 100644 --- a/src/Sign.cpp +++ b/src/Sign.cpp @@ -103,7 +103,7 @@ const uint8_t Sign::FONT[][7] = { }; Sign::Sign(float x, float y, const std::string& text, const Color& color) - : GameObject(x, y, (CHAR_WIDTH + CHAR_SPACING) * text.length() * 3, CHAR_HEIGHT * 3, color) + : GameObject(x, y, (CHAR_WIDTH + CHAR_SPACING) * text.length() * 6, CHAR_HEIGHT * 6, color) , m_text(text) { // Convert text to uppercase for the sign std::transform(m_text.begin(), m_text.end(), m_text.begin(), ::toupper); @@ -163,11 +163,20 @@ void Sign::render(SDL_Renderer* renderer) const { SDL_RenderDrawPointF(renderer, x + totalWidth + 12, y + totalHeight + 12 - i); } - // Draw each character with a slight offset for 3D effect + // Calculate total width of the text for alignment + float totalTextWidth = m_text.length() * (CHAR_WIDTH + CHAR_SPACING) * m_scale; + + // Calculate starting x position based on alignment + float startX = x; + if (m_textAlignment > 0.0f) { + startX = x + (m_width - totalTextWidth) * m_textAlignment; + } + + // Draw each character with alignment for (size_t i = 0; i < m_text.length(); ++i) { // Shadow drawChar(renderer, m_text[i], - x + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale + 2, + startX + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale + 2, y + 2, m_scale, {0, 0, 0, 128}); @@ -179,7 +188,7 @@ void Sign::render(SDL_Renderer* renderer) const { Uint8 blue = static_cast(m_color.b * pulse * 0.6f); drawChar(renderer, m_text[i], - x + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale, + startX + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale, y, m_scale, {red, green, blue, m_color.a}); diff --git a/src/Sign.hpp b/src/Sign.hpp index 491f8eb..cc9b9f1 100644 --- a/src/Sign.hpp +++ b/src/Sign.hpp @@ -16,6 +16,7 @@ class Sign : public GameObject { void setEffectEnabled(bool enabled) { m_effectEnabled = enabled; } void setEffectSpeed(float speed) { m_effectSpeed = speed; } void setScale(float scale) { m_scale = scale; } + void setTextAlignment(float alignment) { m_textAlignment = alignment; } // 0.0 = left, 0.5 = center, 1.0 = right private: std::string m_text; @@ -23,6 +24,7 @@ class Sign : public GameObject { float m_effectTime = 0.0f; float m_effectSpeed = 2.0f; float m_scale = 3.0f; // Scaling factor for the sign + float m_textAlignment = 0.0f; // Text alignment (0.0 = left, 0.5 = center, 1.0 = right) // 8x8 font data for each character (simplified) static constexpr int CHAR_WIDTH = 5; From 3cd8b1dd87d2d5b67c6b3f0d629c97c94215e413 Mon Sep 17 00:00:00 2001 From: Mustafa Zaban Date: Fri, 7 Nov 2025 23:59:01 +0200 Subject: [PATCH 5/6] machi sign finalised --- src/Game.cpp | 23 +++++++++++++++-------- src/Sign.cpp | 12 +++++++----- src/Sign.hpp | 1 + 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/Game.cpp b/src/Game.cpp index 2d27d38..5a169e0 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -927,22 +927,29 @@ void Game::renderUI() { // Create and render the MACHI sign (centered above GAME OVER) if (!m_sign) { - // Center the sign horizontally - float signX = static_cast(SCREEN_WIDTH) * 0.5f - 100; // Centered - float signY = 80.0f; // Slightly lower than before + // Calculate sign dimensions (twice as big as before) + const float signWidth = 400.0f; // Increased width for better centering + const float signHeight = 200.0f; // Increased height for better proportions + + // Center the sign horizontally with the new size + float signX = static_cast(SCREEN_WIDTH) * 0.5f - signWidth * 0.5f + 50; + float signY = 190.0f; // Moved up to make room for larger size + m_sign = std::make_unique( - signX, // x position (aligned with GAME OVER) + signX, // x position (centered) signY, // y position (higher up) "MACHI", // text Color{255, 50, 50, 255} // bright red color ); m_sign->setEffectSpeed(2.5f); // Slightly faster pulsing - m_sign->setScale(6.0f); // Slightly smaller to fit better - m_sign->setTextAlignment(1.0f); // Center text within the sign + m_sign->setScale(12.0f); // Twice as big as before (was 6.0f) + m_sign->setTextAlignment(0.5f); // Center text within the sign + m_sign->setSize(signWidth, signHeight); // Set explicit size for better centering } else { // Update position in case window was resized - float signX = static_cast(SCREEN_WIDTH) * 0.5f - 100; - m_sign->setPosition(signX, 80.0f); + float signX = static_cast(SCREEN_WIDTH) * 0.5f - 200.0f; // Adjusted for new size + m_sign->setPosition(signX, 40.0f); + m_sign->setSize(400.0f, 200.0f); // Ensure size is maintained } m_sign->render(m_renderer); diff --git a/src/Sign.cpp b/src/Sign.cpp index 6943e8c..6fc1bf7 100644 --- a/src/Sign.cpp +++ b/src/Sign.cpp @@ -166,18 +166,20 @@ void Sign::render(SDL_Renderer* renderer) const { // Calculate total width of the text for alignment float totalTextWidth = m_text.length() * (CHAR_WIDTH + CHAR_SPACING) * m_scale; - // Calculate starting x position based on alignment - float startX = x; + // Calculate starting x position based on alignment with 2px left adjustment + float startX = x - 2.0f; // Move 2 pixels to the left if (m_textAlignment > 0.0f) { - startX = x + (m_width - totalTextWidth) * m_textAlignment; + startX = x + (m_width - totalTextWidth) * m_textAlignment - 2.0f; // Adjust for alignment and move left } + // Add a small vertical offset to center the text better + const float verticalOffset = 8.0f * (m_scale / 6.0f); // Draw each character with alignment for (size_t i = 0; i < m_text.length(); ++i) { // Shadow drawChar(renderer, m_text[i], startX + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale + 2, - y + 2, + y + 2 + verticalOffset, // Apply vertical offset to shadow m_scale, {0, 0, 0, 128}); @@ -189,7 +191,7 @@ void Sign::render(SDL_Renderer* renderer) const { drawChar(renderer, m_text[i], startX + i * (CHAR_WIDTH + CHAR_SPACING) * m_scale, - y, + y + verticalOffset, // Apply vertical offset to main text m_scale, {red, green, blue, m_color.a}); } diff --git a/src/Sign.hpp b/src/Sign.hpp index cc9b9f1..77beee2 100644 --- a/src/Sign.hpp +++ b/src/Sign.hpp @@ -17,6 +17,7 @@ class Sign : public GameObject { void setEffectSpeed(float speed) { m_effectSpeed = speed; } void setScale(float scale) { m_scale = scale; } void setTextAlignment(float alignment) { m_textAlignment = alignment; } // 0.0 = left, 0.5 = center, 1.0 = right + void setSize(float width, float height) { m_width = width; m_height = height; } // Set explicit size for the sign private: std::string m_text; From 809c417bf8ce6b96771c773420d61ca3ad1c7cb4 Mon Sep 17 00:00:00 2001 From: Mustafa Zaban Date: Sat, 8 Nov 2025 00:10:14 +0200 Subject: [PATCH 6/6] distance box updated --- src/Game.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Game.cpp b/src/Game.cpp index 5a169e0..6685f72 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -833,24 +833,31 @@ void Game::renderUI() { float distance = m_player->getDistanceTraveled(); int distanceMeters = static_cast(distance / 10.0f); // Convert pixels to "meters" - // Draw distance background - SDL_SetRenderDrawColor(m_renderer, 0, 0, 0, 180); - SDL_Rect distanceBg = {SCREEN_WIDTH - 200, 15, 180, 40}; + // Draw distance background with blue border and white fill + SDL_SetRenderDrawColor(m_renderer, 0, 0, 200, 255); // Blue border + SDL_Rect distanceBorder = {SCREEN_WIDTH - 240, 15, 230, 40}; // Wider (230px) and less tall (40px) + SDL_RenderDrawRect(m_renderer, &distanceBorder); + + // Fill with white + SDL_SetRenderDrawColor(m_renderer, 255, 255, 255, 255); // White fill + SDL_Rect distanceBg = {SCREEN_WIDTH - 239, 16, 228, 38}; // Slightly smaller than border SDL_RenderFillRect(m_renderer, &distanceBg); - // Draw distance label and number as text - SDL_Color textColor = {0, 255, 0, 255}; // Green for distance - char distStr[20]; - snprintf(distStr, sizeof(distStr), "DIST: %d", distanceMeters); + // Draw distance label and number as blue text + SDL_Color textColor = {0, 0, 200, 255}; // Blue text + char distStr[32]; + snprintf(distStr, sizeof(distStr), "DISTANCE: %d", distanceMeters); // Create a surface with the text - SDL_Surface* textSurface = TTF_RenderText_Solid(m_font, distStr, textColor); + SDL_Surface* textSurface = TTF_RenderText_Blended(m_font, distStr, textColor); if (textSurface) { // Create a texture from the surface SDL_Texture* textTexture = SDL_CreateTextureFromSurface(m_renderer, textSurface); if (textTexture) { - // Set the rendering space and render to screen - SDL_Rect renderQuad = {SCREEN_WIDTH - 190, 25, textSurface->w, textSurface->h}; + // Center the text in the box + int textX = SCREEN_WIDTH - 230 + (230 - textSurface->w) / 2; // Adjusted for new width + int textY = 15 + (40 - textSurface->h) / 2; + SDL_Rect renderQuad = {textX, textY, textSurface->w, textSurface->h}; SDL_RenderCopy(m_renderer, textTexture, NULL, &renderQuad); // Free the texture SDL_DestroyTexture(textTexture);