From c7999939e15121bb5c1d543232eb1b3e3f078dfd Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Sun, 18 May 2025 14:46:45 +0200 Subject: [PATCH] sound update and cmake addition for sfml sound! --- CMakeLists.txt | 1 + main.cpp | 151 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41e389c..f8271bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(cppsnek sfml-graphics sfml-window sfml-system + sfml-audio ) if(WIN32) diff --git a/main.cpp b/main.cpp index cd86a3d..9b8da78 100644 --- a/main.cpp +++ b/main.cpp @@ -1,14 +1,17 @@ #include +#include #include #include #include +// Set namespaces for SFML and STD using namespace sf; using namespace std; -constexpr int WIDTH = 800; -constexpr int HEIGHT = 600; -constexpr int GRID_SIZE = 40; +// Init window / sprite variables ( constant and will never change ) +constexpr int WIDTH = 640; +constexpr int HEIGHT = 480; +constexpr int GRID_SIZE = 20; constexpr int GRID_WIDTH = WIDTH / GRID_SIZE; constexpr int GRID_HEIGHT = HEIGHT / GRID_SIZE; constexpr int SPRITE_SIZE = GRID_SIZE; @@ -51,6 +54,127 @@ public: void setPosition(float x, float y) { sprite.setPosition(x, y); } }; +class SoundManager { +private: + SoundBuffer moveBuffer; + SoundBuffer eatBuffer; + SoundBuffer gameOverBuffer; + Sound moveSound; + Sound eatSound; + Sound gameOverSound; + bool soundLoaded; + +public: + SoundManager() : soundLoaded(true) { + // Create simple beep sounds programmatically + createMoveSound(); + createEatSound(); + createGameOverSound(); + + // Set volumes to be quieter + moveSound.setVolume(15.0f); // Very quiet for movement + eatSound.setVolume(25.0f); // Bit louder for eating + gameOverSound.setVolume(30.0f); // Louder for game over + } + + void createMoveSound() { + const unsigned SAMPLE_RATE = 44100; + const unsigned DURATION = 5000; // Very short duration (in samples) + + std::vector samples(DURATION); + + // Generate a simple beep for movement (higher pitch, shorter) + for (unsigned i = 0; i < DURATION; i++) { + double time = i / static_cast(SAMPLE_RATE); + samples[i] = 10000 * sin(2 * 3.14159 * 880 * time); // 880 Hz tone + } + + // Apply fade-out + for (unsigned i = DURATION / 2; i < DURATION; i++) { + double fadeOut = 1.0 - (static_cast(i - DURATION / 2) / (DURATION / 2)); + samples[i] = static_cast(samples[i] * fadeOut); + } + + if (!moveBuffer.loadFromSamples(&samples[0], samples.size(), 1, SAMPLE_RATE)) { + soundLoaded = false; + } + moveSound.setBuffer(moveBuffer); + } + + void createEatSound() { + const unsigned SAMPLE_RATE = 44100; + const unsigned DURATION = 8000; // Slightly longer duration for eat sound + + std::vector samples(DURATION); + + // Generate eat sound (rising pitch) + for (unsigned i = 0; i < DURATION; i++) { + double time = i / static_cast(SAMPLE_RATE); + double frequency = 440 + (i * 400 / DURATION); // Rising from 440Hz to 840Hz + samples[i] = 12000 * sin(2 * 3.14159 * frequency * time); + } + + // Apply fade-in and fade-out + for (unsigned i = 0; i < DURATION / 4; i++) { + double fadeIn = static_cast(i) / (DURATION / 4); + samples[i] = static_cast(samples[i] * fadeIn); + } + + for (unsigned i = 3 * DURATION / 4; i < DURATION; i++) { + double fadeOut = 1.0 - (static_cast(i - 3 * DURATION / 4) / (DURATION / 4)); + samples[i] = static_cast(samples[i] * fadeOut); + } + + if (!eatBuffer.loadFromSamples(&samples[0], samples.size(), 1, SAMPLE_RATE)) { + soundLoaded = false; + } + eatSound.setBuffer(eatBuffer); + } + + void createGameOverSound() { + const unsigned SAMPLE_RATE = 44100; + const unsigned DURATION = 44100 / 2; // Half second + + std::vector samples(DURATION); + + // Generate game over sound (descending pitch) + for (unsigned i = 0; i < DURATION; i++) { + double time = i / static_cast(SAMPLE_RATE); + double frequency = 440 - (i * 200 / DURATION); // Falling from 440Hz to 240Hz + samples[i] = 15000 * sin(2 * 3.14159 * frequency * time); + } + + // Apply "wah wah" effect with fading + for (unsigned i = 0; i < DURATION; i++) { + double envelope = 1.0 - 0.8 * (static_cast(i) / DURATION); + samples[i] = static_cast(samples[i] * envelope); + } + + if (!gameOverBuffer.loadFromSamples(&samples[0], samples.size(), 1, SAMPLE_RATE)) { + soundLoaded = false; + } + gameOverSound.setBuffer(gameOverBuffer); + } + + void playMoveSound() { + if (soundLoaded) { + moveSound.play(); + } + } + + void playEatSound() { + if (soundLoaded) { + eatSound.play(); + } + } + + void playGameOverSound() { + if (soundLoaded) { + gameOverSound.play(); + } + } +}; + class Game { private: RenderWindow window; @@ -63,6 +187,8 @@ private: int score; Font font; Text scoreText; + SoundManager soundManager; + Vector2f lastDirection; // Numeric sprites NumericSprite snakeHeadSprite; @@ -99,8 +225,8 @@ private: }}; public: - Game() : window(VideoMode(WIDTH, HEIGHT), "SFML CPPSNEK V1.2"), direction(1, 0), - isMoving(false), speed(0.1f), score(0), grid(Lines) { + Game() : window(VideoMode(WIDTH, HEIGHT), "SFML CPPSNEK V1.3 With Sound"), direction(1, 0), + isMoving(false), speed(0.1f), score(0), grid(Lines), lastDirection(1, 0) { window.setFramerateLimit(60); // Initialize snake @@ -165,21 +291,32 @@ public: } void handleInput() { + bool directionChanged = false; + if (Keyboard::isKeyPressed(Keyboard::Left) && direction.x == 0) { direction = Vector2f(-1, 0); isMoving = true; + directionChanged = true; } else if (Keyboard::isKeyPressed(Keyboard::Right) && direction.x == 0) { direction = Vector2f(1, 0); isMoving = true; + directionChanged = true; } else if (Keyboard::isKeyPressed(Keyboard::Up) && direction.y == 0) { direction = Vector2f(0, -1); isMoving = true; + directionChanged = true; } else if (Keyboard::isKeyPressed(Keyboard::Down) && direction.y == 0) { direction = Vector2f(0, 1); isMoving = true; + directionChanged = true; + } + + if (directionChanged && (direction.x != lastDirection.x || direction.y != lastDirection.y)) { + soundManager.playMoveSound(); + lastDirection = direction; } } @@ -192,12 +329,14 @@ public: SnakeSegment newHead = {snake[0].x + direction.x, snake[0].y + direction.y}; if (newHead.x < 0 || newHead.x >= GRID_WIDTH || newHead.y < 0 || newHead.y >= GRID_HEIGHT) { + soundManager.playGameOverSound(); reset(); return; } for (size_t i = 1; i < snake.size(); i++) { if (newHead.x == snake[i].x && newHead.y == snake[i].y) { + soundManager.playGameOverSound(); reset(); return; } @@ -208,6 +347,7 @@ public: spawnFruit(); score += 10; updateScoreText(); + soundManager.playEatSound(); if (score % 50 == 0 && speed > 0.05f) { speed -= 0.01f; @@ -224,6 +364,7 @@ public: snake.push_back({GRID_WIDTH / 2 - 1, GRID_HEIGHT / 2}); snake.push_back({GRID_WIDTH / 2 - 2, GRID_HEIGHT / 2}); direction = Vector2f(1, 0); + lastDirection = Vector2f(1, 0); isMoving = false; speed = 0.1f; score = 0;