From b3b12e52ea379bbef78d759959c114c6bca53147 Mon Sep 17 00:00:00 2001 From: Mustafa Zaban Date: Fri, 14 Nov 2025 00:57:34 +0200 Subject: [PATCH] watter added --- CMakeLists.txt | 2 + src/Game.cpp | 14 +++++ src/Game.hpp | 2 + src/Water.cpp | 148 +++++++++++++++++++++++++++++++++++++++++++++++++ src/Water.hpp | 32 +++++++++++ 5 files changed, 198 insertions(+) create mode 100644 src/Water.cpp create mode 100644 src/Water.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bf2780b..2cafdd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES src/Bird.cpp src/Cloud.cpp src/Sign.cpp + src/Water.cpp ) set(HEADERS @@ -26,6 +27,7 @@ set(HEADERS src/Bird.hpp src/Cloud.hpp src/Sign.hpp + src/Water.hpp src/Common.hpp ) diff --git a/src/Game.cpp b/src/Game.cpp index 6685f72..eefd324 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -281,6 +281,9 @@ void Game::createLevel() { 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)); + // Create water at the bottom of the screen - lowered even more + m_water = std::make_unique(0, SCREEN_HEIGHT - 40, m_worldWidth, 160); + // Sign will be created when game is over } @@ -401,6 +404,12 @@ void Game::update(float deltaTime) { for (auto& cloud : m_clouds) { cloud->update(deltaTime); } + + // Update water animation + if (m_water) { + m_water->update(deltaTime); + m_water->setCameraOffset(m_cameraX, 0); + } // Update player first m_player->update(deltaTime); @@ -625,6 +634,11 @@ void Game::render() { cloud->render(m_renderer); } + // Render water (above clouds but below platforms and player) + if (m_water) { + m_water->render(m_renderer); + } + // Render the MACHI sign if (m_sign) { m_sign->render(m_renderer); diff --git a/src/Game.hpp b/src/Game.hpp index 7238c18..db4577b 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -10,6 +10,7 @@ #include "Bird.hpp" #include "Sign.hpp" #include "Cloud.hpp" +#include "Water.hpp" class Game { public: @@ -49,6 +50,7 @@ class Game { std::vector> m_birds; std::unique_ptr m_sign; std::vector> m_clouds; + std::unique_ptr m_water; // World and camera properties float m_worldWidth = 2000.0f; diff --git a/src/Water.cpp b/src/Water.cpp new file mode 100644 index 0000000..7cf0d5d --- /dev/null +++ b/src/Water.cpp @@ -0,0 +1,148 @@ +#include "Water.hpp" +#include "Common.hpp" +#include +#include +#include +#include + +Water::Water(float x, float y, float width, float height) + : GameObject(x, y, width, height, {25, 100, 160, 180}) { // Deeper blue with more transparency + // Initialize wave layers with different properties + WaveLayer layer1, layer2, layer3; + + // Main slow waves - increased size and adjusted for better visibility + layer1.time = 0.0f; + layer1.speed = 0.15f; // Even slower speed + layer1.height = 20.0f; // Much more pronounced waves + layer1.frequency = 0.25f; // Wider waves + layer1.colors[0] = {20, 100, 200, 180}; + layer1.colors[1] = {40, 140, 230, 200}; + + // Secondary waves - medium speed + layer2.time = 50.0f; + layer2.speed = 0.3f; + layer2.height = 10.0f; // Increased height + layer2.frequency = 0.5f; // Slightly wider + layer2.colors[0] = {30, 120, 210, 160}; + layer2.colors[1] = {50, 150, 240, 180}; + + // High frequency waves - fine detail + layer3.time = 100.0f; + layer3.speed = 0.45f; + layer3.height = 6.0f; // Increased height for better visibility + layer3.frequency = 1.0f; // Slightly less frequent + layer3.colors[0] = {40, 140, 220, 140}; + layer3.colors[1] = {60, 170, 250, 160}; + + m_waveLayers.push_back(layer1); + m_waveLayers.push_back(layer2); + m_waveLayers.push_back(layer3); + + // Generate random foam pattern + generateFoamPattern(); +} + +void Water::generateFoamPattern() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution dist(0.0f, 1.0f); + + m_foamPattern.resize(FOAM_PATTERN_SIZE); + for (int i = 0; i < FOAM_PATTERN_SIZE; ++i) { + float t = static_cast(i) / FOAM_PATTERN_SIZE; + float noise = 0.5f + 0.5f * std::sin(t * 15.0f) * std::cos(t * 10.0f); + m_foamPattern[i] = 0.3f + 0.7f * noise * dist(gen); + } +} + +void Water::update(float deltaTime) { + m_time += deltaTime; + + // Update each wave layer + for (auto& layer : m_waveLayers) { + layer.time += deltaTime * layer.speed; + } +} + +void Water::render(SDL_Renderer* renderer) const { + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + + // Draw base water color - extended to the left to prevent edge artifacts + SDL_SetRenderDrawColor(renderer, 30, 100, 200, 200); + SDL_Rect waterRect = { + -100, // Extend 100 pixels to the left + static_cast(m_y - m_cameraOffsetY), + static_cast(m_width + 100), // Extend width to cover the offset + static_cast(m_height) + }; + SDL_RenderFillRect(renderer, &waterRect); + + // Draw wave layers from bottom to top + for (const auto& layer : m_waveLayers) { + std::vector vertices; + std::vector indices; + + // Add bottom-left and bottom-right vertices for the water body - extended to the left + SDL_Vertex bottomLeft = { + {-100.0f, static_cast(m_y + m_height - m_cameraOffsetY)}, + {layer.colors[0].r, layer.colors[0].g, layer.colors[0].b, 180}, + {0, 0} + }; + + SDL_Vertex bottomRight = { + {static_cast(m_width + 100), static_cast(m_y + m_height - m_cameraOffsetY)}, + {layer.colors[0].r, layer.colors[0].g, layer.colors[0].b, 180}, + {0, 0} + }; + + // Add wave points along the top edge + for (int i = 0; i < WAVE_POINTS; ++i) { + float t = static_cast(i) / (WAVE_POINTS - 1); + // Extend the wave points beyond the left edge to prevent diagonal artifacts + float x = t * (m_width + 200) - 100; // Start 100px left of the screen + + // Calculate wave height using multiple frequencies for natural look + float wave = 0.0f; + wave += std::sin(t * 10.0f + layer.time * layer.frequency) * layer.height; + wave += std::sin(t * 5.0f + layer.time * layer.frequency * 0.7f) * layer.height * 0.5f; + + // Add some noise for more natural look + float noise = m_foamPattern[(i + static_cast(layer.time * 20.0f)) % FOAM_PATTERN_SIZE]; + wave += (noise - 0.5f) * 2.0f; + + SDL_Vertex vertex = { + {x, m_y - m_cameraOffsetY + wave}, + {layer.colors[1].r, layer.colors[1].g, layer.colors[1].b, + static_cast(200 * (0.7f + 0.3f * (wave + layer.height) / (layer.height * 2.0f)))}, + {0, 0} + }; + + vertices.push_back(vertex); + + // Create triangles for the water surface - with extended coverage + if (i > 0) { + int idx = vertices.size() - 1; + // Only create triangles if both points are within the visible area or just outside + if (x > -200 && x < m_width + 200) { + // Triangle 1: bottom-left, previous top, current top + vertices.push_back(bottomLeft); + indices.push_back(vertices.size() - 1); + indices.push_back(idx - 1); + indices.push_back(idx); + + // Triangle 2: bottom-right, bottom-left, current top + vertices.push_back(bottomRight); + indices.push_back(vertices.size() - 1); + indices.push_back(vertices.size() - 3); + indices.push_back(idx); + } + } + } + + // Draw the water surface with the calculated vertices and indices + if (!vertices.empty() && !indices.empty()) { + SDL_RenderGeometry(renderer, nullptr, vertices.data(), vertices.size(), + indices.data(), indices.size()); + } + } +} diff --git a/src/Water.hpp b/src/Water.hpp new file mode 100644 index 0000000..069b9fe --- /dev/null +++ b/src/Water.hpp @@ -0,0 +1,32 @@ +#ifndef WATER_HPP +#define WATER_HPP + +#include "GameObject.hpp" +#include +#include + +class Water : public GameObject { +public: + struct WaveLayer { + float time = 0.0f; + float speed = 1.0f; + float height = 1.0f; + float frequency = 1.0f; + SDL_Color colors[2]; + }; + + Water(float x, float y, float width, float height); + void update(float deltaTime) override; + void render(SDL_Renderer* renderer) const override; + +private: + void generateFoamPattern(); + + float m_time = 0.0f; + std::vector m_foamPattern; + std::vector m_waveLayers; + static const int WAVE_POINTS = 64; + static const int FOAM_PATTERN_SIZE = 128; +}; + +#endif // WATER_HPP