sneek fassst as fuckkk boiii ; idk what the fuck changed lol
This commit is contained in:
313
main.cpp
313
main.cpp
@@ -4,6 +4,10 @@
|
||||
#include <random>
|
||||
#include <array>
|
||||
|
||||
// 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<Int16> 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<double>(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<double>(i) / (DURATION / 10);
|
||||
samples[i] = static_cast<Int16>(samples[i] * fadeIn);
|
||||
}
|
||||
|
||||
// Apply fade-out
|
||||
for (unsigned i = DURATION / 2; i < DURATION; i++) {
|
||||
double fadeOut = 1.0 - (static_cast<double>(i - DURATION / 2) / (DURATION / 2));
|
||||
samples[i] = static_cast<Int16>(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<Int16> samples(DURATION);
|
||||
|
||||
// Generate eat sound (rising pitch)
|
||||
for (unsigned i = 0; i < DURATION; i++) {
|
||||
double time = i / static_cast<double>(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<double>(i) / (DURATION / 4);
|
||||
for (unsigned i = 0; i < DURATION / 5; i++) {
|
||||
double fadeIn = static_cast<double>(i) / (DURATION / 5);
|
||||
samples[i] = static_cast<Int16>(samples[i] * fadeIn);
|
||||
}
|
||||
|
||||
for (unsigned i = 3 * DURATION / 4; i < DURATION; i++) {
|
||||
double fadeOut = 1.0 - (static_cast<double>(i - 3 * DURATION / 4) / (DURATION / 4));
|
||||
for (unsigned i = 4 * DURATION / 5; i < DURATION; i++) {
|
||||
double fadeOut = 1.0 - (static_cast<double>(i - 4 * DURATION / 5) / (DURATION / 5));
|
||||
samples[i] = static_cast<Int16>(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<Int16> samples(DURATION);
|
||||
|
||||
// Generate game over sound (descending pitch)
|
||||
for (unsigned i = 0; i < DURATION; i++) {
|
||||
double time = i / static_cast<double>(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<double>(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<double>(i) / DURATION);
|
||||
double progress = static_cast<double>(i) / DURATION;
|
||||
double envelope = 1.0 - progress * 0.5; // Gradual fade
|
||||
samples[i] = static_cast<Int16>(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<Int16> samples(DURATION);
|
||||
|
||||
for (unsigned i = 0; i < DURATION; i++) {
|
||||
double time = i / static_cast<double>(SAMPLE_RATE);
|
||||
double phase = static_cast<double>(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<double>(i) / (DURATION / 10);
|
||||
samples[i] = static_cast<Int16>(samples[i] * fadeIn);
|
||||
}
|
||||
|
||||
for (unsigned i = 8 * DURATION / 10; i < DURATION; i++) {
|
||||
double fadeOut = 1.0 - (static_cast<double>(i - 8 * DURATION / 10) / (2 * DURATION / 10));
|
||||
samples[i] = static_cast<Int16>(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<Int16> 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<double>(SAMPLE_RATE);
|
||||
double beatPosition = fmod(time, beatDuration * beatsPerBar) / beatDuration; // Position within the bar
|
||||
int currentBeat = static_cast<int>(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<Int16>(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<array<int, 5>, 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<int>(snake[0].x + direction.x),
|
||||
static_cast<int>(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();
|
||||
|
||||
Reference in New Issue
Block a user