From cb87b266b4a7daa19a614e7cc1e2d01c02ee8d64 Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Sun, 18 May 2025 15:07:55 +0200 Subject: [PATCH] sneek fassst as fuckkk boiii ; idk what the fuck changed lol --- main.cpp | 313 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 282 insertions(+), 31 deletions(-) diff --git a/main.cpp b/main.cpp index 9b8da78..2f566c1 100644 --- a/main.cpp +++ b/main.cpp @@ -4,6 +4,10 @@ #include #include +// Note: Make sure to link with sfml-audio in your CMakeLists.txt +// add_executable(cppsnek main.cpp) +// target_link_libraries(cppsnek sfml-graphics sfml-window sfml-system sfml-audio) + // Set namespaces for SFML and STD using namespace sf; using namespace std; @@ -59,9 +63,15 @@ private: SoundBuffer moveBuffer; SoundBuffer eatBuffer; SoundBuffer gameOverBuffer; + SoundBuffer milestoneBuffer; + SoundBuffer themeSongBuffer; + Sound moveSound; Sound eatSound; Sound gameOverSound; + Sound milestoneSound; + Sound themeSongSound; + bool soundLoaded; public: @@ -70,11 +80,18 @@ public: createMoveSound(); createEatSound(); createGameOverSound(); + createMilestoneSound(); + // createThemeSong(); // 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 + moveSound.setVolume(20.0f); // Quiet for movement + eatSound.setVolume(30.0f); // Louder for eating + gameOverSound.setVolume(35.0f); // Even louder for game over + milestoneSound.setVolume(40.0f); // More noticeable for milestones + themeSongSound.setVolume(25.0f); // Background music quieter + + // Set theme song to loop + themeSongSound.setLoop(true); } void createMoveSound() { @@ -83,13 +100,22 @@ public: std::vector samples(DURATION); - // Generate a simple beep for movement (higher pitch, shorter) + // Generate a cheerful 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 + // Major third chord (more cheerful than single tone) + double freq1 = 880; // Base note + double freq2 = 1100; // Major third + samples[i] = 5000 * sin(2 * 3.14159 * freq1 * time) + + 5000 * sin(2 * 3.14159 * freq2 * time); + } + + // Apply quick fade-in and fade-out (makes it sound less harsh) + for (unsigned i = 0; i < DURATION / 10; i++) { + double fadeIn = static_cast(i) / (DURATION / 10); + samples[i] = static_cast(samples[i] * fadeIn); } - // 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); @@ -103,25 +129,33 @@ public: void createEatSound() { const unsigned SAMPLE_RATE = 44100; - const unsigned DURATION = 8000; // Slightly longer duration for eat sound + const unsigned DURATION = 10000; // 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); + // Create a C major ascending arpeggio (C, E, G) - happy sound + double phase = (i * 15.0) / DURATION; // Controls arpeggio speed + double note = floor(phase * 3) / 3.0; // 0, 1/3, 2/3 + + // C major chord frequencies (C, E, G) + double freq; + if (note < 0.34) freq = 523.25; // C5 + else if (note < 0.67) freq = 659.25; // E5 + else freq = 783.99; // G5 + + samples[i] = 12000 * sin(2 * 3.14159 * freq * time); } // Apply fade-in and fade-out - for (unsigned i = 0; i < DURATION / 4; i++) { - double fadeIn = static_cast(i) / (DURATION / 4); + for (unsigned i = 0; i < DURATION / 5; i++) { + double fadeIn = static_cast(i) / (DURATION / 5); 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)); + for (unsigned i = 4 * DURATION / 5; i < DURATION; i++) { + double fadeOut = 1.0 - (static_cast(i - 4 * DURATION / 5) / (DURATION / 5)); samples[i] = static_cast(samples[i] * fadeOut); } @@ -133,20 +167,32 @@ public: void createGameOverSound() { const unsigned SAMPLE_RATE = 44100; - const unsigned DURATION = 44100 / 2; // Half second + const unsigned DURATION = 44100 / 1.2; // Almost a 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); + double phase = static_cast(i) / DURATION; // 0 to 1 + + // C major scale descending (C6 down to C5) + double noteFreq; + if (phase < 0.125) noteFreq = 1046.50; // C6 + else if (phase < 0.25) noteFreq = 932.33; // Bb5 + else if (phase < 0.375) noteFreq = 783.99; // G5 + else if (phase < 0.5) noteFreq = 698.46; // F5 + else if (phase < 0.625) noteFreq = 659.25; // E5 + else if (phase < 0.75) noteFreq = 587.33; // D5 + else if (phase < 0.875) noteFreq = 523.25; // C5 + else noteFreq = 493.88; // B4 + + samples[i] = 15000 * sin(2 * 3.14159 * noteFreq * time); } - // Apply "wah wah" effect with fading + // Apply envelope to make it sound more natural for (unsigned i = 0; i < DURATION; i++) { - double envelope = 1.0 - 0.8 * (static_cast(i) / DURATION); + double progress = static_cast(i) / DURATION; + double envelope = 1.0 - progress * 0.5; // Gradual fade samples[i] = static_cast(samples[i] * envelope); } @@ -156,6 +202,118 @@ public: gameOverSound.setBuffer(gameOverBuffer); } + void createMilestoneSound() { + const unsigned SAMPLE_RATE = 44100; + const unsigned DURATION = 44100 / 2; // Half second + + std::vector samples(DURATION); + + for (unsigned i = 0; i < DURATION; i++) { + double time = i / static_cast(SAMPLE_RATE); + double phase = static_cast(i) / DURATION; + + double freq1, freq2; + + if (phase < 0.3) { + // First chord - C major + freq1 = 523.25; // C5 + freq2 = 659.25; // E5 + } else if (phase < 0.6) { + // Second chord - F major + freq1 = 698.46; // F5 + freq2 = 880.00; // A5 + } else { + // Final chord - G major (dominant) + freq1 = 783.99; // G5 + freq2 = 987.77; // B5 + } + + // Mix two frequencies for a richer sound + samples[i] = 8000 * sin(2 * 3.14159 * freq1 * time) + + 8000 * sin(2 * 3.14159 * freq2 * time); + } + + // Apply envelope to make it sound more natural + for (unsigned i = 0; i < DURATION / 10; i++) { + double fadeIn = static_cast(i) / (DURATION / 10); + samples[i] = static_cast(samples[i] * fadeIn); + } + + for (unsigned i = 8 * DURATION / 10; i < DURATION; i++) { + double fadeOut = 1.0 - (static_cast(i - 8 * DURATION / 10) / (2 * DURATION / 10)); + samples[i] = static_cast(samples[i] * fadeOut); + } + + if (!milestoneBuffer.loadFromSamples(&samples[0], samples.size(), 1, SAMPLE_RATE)) { + soundLoaded = false; + } + milestoneSound.setBuffer(milestoneBuffer); + } + + void createThemeSong() { + const unsigned SAMPLE_RATE = 44100; + const unsigned DURATION = SAMPLE_RATE * 8; // 8 seconds loop + + std::vector samples(DURATION); + + const double pentatonic[] = { + 523.25, // C5 + 587.33, // D5 + 659.25, // E5 + 783.99, // G5 + 880.00 // A5 + }; + const int numNotes = 5; + + // Create a simple melody pattern + const int pattern[] = {0, 2, 4, 2, 3, 1, 0, 1, 2, 4, 3, 2, 1, 3, 2, 0}; + const int patternLength = 16; + + // Beat durations (in seconds) + const double beatDuration = 0.5; // Half second per beat + const double beatsPerBar = 4; // 4 beats in a bar + + for (unsigned i = 0; i < DURATION; i++) { + double time = i / static_cast(SAMPLE_RATE); + double beatPosition = fmod(time, beatDuration * beatsPerBar) / beatDuration; // Position within the bar + int currentBeat = static_cast(time / beatDuration) % patternLength; + + // Get current note in the pattern + int noteIndex = pattern[currentBeat]; + double freq = pentatonic[noteIndex]; + + // Add a bass note every 4 beats + double bassFreq = 0; + if (currentBeat % 4 == 0) { + bassFreq = pentatonic[0] / 2; // One octave lower than the root + } else if (currentBeat % 4 == 2) { + bassFreq = pentatonic[2] / 2; // One octave lower than the third + } + + // Simple envelope for each note + double envelope = 1.0; + double noteTime = fmod(time, beatDuration); + if (noteTime < 0.05) { + envelope = noteTime / 0.05; // Quick attack + } else if (noteTime > beatDuration * 0.8) { + envelope = (beatDuration - noteTime) / (beatDuration * 0.2); // Release + } + + // Mix the sounds + double mainNote = sin(2 * 3.14159 * freq * time); + double bassNote = (bassFreq > 0) ? sin(2 * 3.14159 * bassFreq * time) : 0; + + // Quieter theme song for background + samples[i] = static_cast(envelope * 6000 * mainNote + + envelope * 4000 * bassNote); + } + + if (!themeSongBuffer.loadFromSamples(&samples[0], samples.size(), 1, SAMPLE_RATE)) { + soundLoaded = false; + } + themeSongSound.setBuffer(themeSongBuffer); + } + void playMoveSound() { if (soundLoaded) { moveSound.play(); @@ -170,9 +328,41 @@ public: void playGameOverSound() { if (soundLoaded) { + // Stop theme song when game is over + themeSongSound.stop(); gameOverSound.play(); } } + + void playMilestoneSound() { + if (soundLoaded) { + milestoneSound.play(); + } + } + + void startThemeSong() { + if (soundLoaded) { + themeSongSound.play(); + } + } + + void stopThemeSong() { + if (soundLoaded) { + themeSongSound.stop(); + } + } + + void pauseThemeSong() { + if (soundLoaded) { + themeSongSound.pause(); + } + } + + void resumeThemeSong() { + if (soundLoaded) { + themeSongSound.play(); + } + } }; class Game { @@ -185,8 +375,12 @@ private: Clock clock; float speed; int score; + int lastMilestone; Font font; Text scoreText; + Text messageText; + Clock messageTimer; + bool showMessage; SoundManager soundManager; Vector2f lastDirection; @@ -199,10 +393,11 @@ private: VertexArray grid; // Patterns + // Make it have a lil smile for the head pattern const array, 5> HEAD_PATTERN = {{ - {1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1}, + {0, 1, 1, 1, 0}, + {1, 0, 1, 0, 1}, + {1, 1, 0, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1} }}; @@ -225,8 +420,15 @@ private: }}; public: - 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) { + Game() : window(VideoMode(WIDTH, HEIGHT), "cppsnek"), direction(1, 0), + isMoving(false), + speed(0.05f), // Fast asf speed lolz + score(0), + lastMilestone(0), + grid(Lines), + lastDirection(1, 0), + + showMessage(false) { window.setFramerateLimit(60); // Initialize snake @@ -248,11 +450,19 @@ public: if (!font.loadFromFile("/usr/share/fonts/gnu-free/FreeSans.ttf")) { font.loadFromFile("/usr/share/fonts/liberation/LiberationSans-Regular.ttf"); } + + // Setup score text scoreText.setFont(font); scoreText.setCharacterSize(24); scoreText.setFillColor(Color::White); scoreText.setPosition(10, 10); updateScoreText(); + + // Setup milestone message text + messageText.setFont(font); + messageText.setCharacterSize(32); + messageText.setFillColor(Color::Yellow); + messageText.setPosition(WIDTH / 2 - 100, HEIGHT / 2 - 50); } void createGrid() { @@ -293,22 +503,22 @@ public: void handleInput() { bool directionChanged = false; - if (Keyboard::isKeyPressed(Keyboard::Left) && direction.x == 0) { + if (Keyboard::isKeyPressed(Keyboard::A) && direction.x == 0) { direction = Vector2f(-1, 0); isMoving = true; directionChanged = true; } - else if (Keyboard::isKeyPressed(Keyboard::Right) && direction.x == 0) { + else if (Keyboard::isKeyPressed(Keyboard::D) && direction.x == 0) { direction = Vector2f(1, 0); isMoving = true; directionChanged = true; } - else if (Keyboard::isKeyPressed(Keyboard::Up) && direction.y == 0) { + else if (Keyboard::isKeyPressed(Keyboard::W) && direction.y == 0) { direction = Vector2f(0, -1); isMoving = true; directionChanged = true; } - else if (Keyboard::isKeyPressed(Keyboard::Down) && direction.y == 0) { + else if (Keyboard::isKeyPressed(Keyboard::S) && direction.y == 0) { direction = Vector2f(0, 1); isMoving = true; directionChanged = true; @@ -326,7 +536,8 @@ public: clock.restart(); - SnakeSegment newHead = {snake[0].x + direction.x, snake[0].y + direction.y}; + SnakeSegment newHead = {static_cast(snake[0].x + direction.x), + static_cast(snake[0].y + direction.y)}; if (newHead.x < 0 || newHead.x >= GRID_WIDTH || newHead.y < 0 || newHead.y >= GRID_HEIGHT) { soundManager.playGameOverSound(); @@ -349,6 +560,14 @@ public: updateScoreText(); soundManager.playEatSound(); + // Check for milestones (every 100 points) + if (score >= 100 && score / 100 > lastMilestone / 100) { + lastMilestone = score; + showMilestoneMessage(); + soundManager.playMilestoneSound(); + } + + // Speed up the game as score increases if (score % 50 == 0 && speed > 0.05f) { speed -= 0.01f; } @@ -356,6 +575,17 @@ public: snake.insert(snake.begin(), newHead); snake.pop_back(); } + + // Update message display time + if (showMessage && messageTimer.getElapsedTime().asSeconds() > 2.0f) { + showMessage = false; + } + } + + void showMilestoneMessage() { + messageText.setString("MILESTONE: " + std::to_string(score) + " POINTS!"); + showMessage = true; + messageTimer.restart(); } void reset() { @@ -366,10 +596,14 @@ public: direction = Vector2f(1, 0); lastDirection = Vector2f(1, 0); isMoving = false; - speed = 0.1f; + speed = 0.05f; // Same as in rungame score = 0; + lastMilestone = 0; updateScoreText(); spawnFruit(); + + // Restart theme song + soundManager.startThemeSong(); } void render() { @@ -396,15 +630,32 @@ public: // Draw score window.draw(scoreText); + // Draw milestone message if needed + if (showMessage) { + window.draw(messageText); + } + window.display(); } void run() { + // Don't start theme song when game starts ; cause its fucking terrible + // soundManager.startThemeSong(); + while (window.isOpen()) { Event event; while (window.pollEvent(event)) { if (event.type == Event::Closed) window.close(); + + // Pause/resume game with space + if (event.type == Event::KeyPressed && event.key.code == Keyboard::Space) { + isMoving = !isMoving; + if (isMoving) + soundManager.resumeThemeSong(); + else + soundManager.pauseThemeSong(); + } } handleInput();