implemented sound system and score

This commit is contained in:
Joseph Aquino 2026-01-08 00:43:51 -05:00
parent 78779cccb9
commit 27d074401a
14 changed files with 151 additions and 57 deletions

2
.clangd Normal file
View File

@ -0,0 +1,2 @@
CompileFlags:
CompilationDatabase: build/

BIN
assets/sounds/bgMusic.wav Normal file

Binary file not shown.

BIN
assets/sounds/eat.wav Normal file

Binary file not shown.

BIN
assets/sounds/lose.ogg Normal file

Binary file not shown.

BIN
assets/sounds/move.wav Normal file

Binary file not shown.

BIN
assets/sounds/win.ogg Normal file

Binary file not shown.

View File

@ -11,6 +11,6 @@ struct Fruit
sf::Vector2u gridPos{}; sf::Vector2u gridPos{};
Color color{}; Color color{};
sf::Vector2f windowPos(float gridSize_in); sf::Vector2f windowPos(float gridSize_in) const;
void respawn(const std::vector<SnakeNode>& body_in, sf::Vector2u gridCount_in); void respawn(const std::vector<SnakeNode>& body_in, sf::Vector2u gridCount_in);
}; };

View File

@ -1,14 +1,21 @@
#pragma once #pragma once
#include <Util.h> #include "Util.h"
#include <Player.h> #include "Player.h"
#include <Fruit.h> #include "Fruit.h"
#include <GameConfig.h> #include "GameConfig.h"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp> #include <SFML/Audio.hpp>
#include <imgui-SFML.h> #include <imgui-SFML.h>
#include <imgui.h> #include <imgui.h>
enum class GameState
{
playing,
lose,
win
};
class Game class Game
{ {
@ -51,6 +58,16 @@ private:
sf::Text score; sf::Text score;
sf::SoundBuffer failSoundBuffer; sf::SoundBuffer failSoundBuffer;
sf::SoundBuffer winSoundBuffer;
sf::SoundBuffer bgMusicBuffer;
sf::SoundBuffer eatSoundBuffer;
sf::SoundBuffer moveSoundBuffer;
sf::Sound failSound;
sf::Sound winSound;
sf::Sound bgMusic;
sf::Sound eatSound;
sf::Sound moveSound;
sf::RectangleShape tempRect; sf::RectangleShape tempRect;
@ -62,6 +79,8 @@ private:
sf::Vector2u gridCount; sf::Vector2u gridCount;
size_t frameCount{}; size_t frameCount{};
size_t fruitEaten{};
GameState state{GameState::playing};
bool useImgui; bool useImgui;
bool fail{}; bool fail{};
bool win{}; bool win{};

View File

@ -11,5 +11,5 @@ struct GameConfig
Color playerHeadColor; Color playerHeadColor;
Color playerBodyColor; Color playerBodyColor;
sf::Vector2u headGridStartPos; sf::Vector2u headGridStartPos;
unsigned int gridSize; float gridSize;
}; };

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <Random.h> #include "Random.h"
#include <Color.h> #include "Color.h"
#include <Math-util.h> #include "Math-util.h"

View File

@ -5,7 +5,7 @@ cd "$SCRIPT_DIR"
if [ -z "$1" ] || [ $# -eq 0 ] if [ -z "$1" ] || [ $# -eq 0 ]
then then
./third-party/premake5/premake5 --config=Debug ecc ../third-party/premake5/premake5 --config=Debug ecc
else else
./third-party/premake5/premake5 --config=$1 ecc ../third-party/premake5/premake5 --config=$1 ecc
fi fi

View File

@ -7,7 +7,7 @@ Fruit::Fruit(sf::Vector2i gridPos_in, const sf::Color& color_in)
, color(color_in) , color(color_in)
{ } { }
sf::Vector2f Fruit::windowPos(float gridSize_in) sf::Vector2f Fruit::windowPos(float gridSize_in) const
{ {
return {gridPos.x * gridSize_in, gridPos.y * gridSize_in}; return {gridPos.x * gridSize_in, gridPos.y * gridSize_in};
} }
@ -16,16 +16,17 @@ void Fruit::respawn(const std::vector<SnakeNode>& body_in, sf::Vector2u gridCoun
{ {
unsigned int tempX; unsigned int tempX;
unsigned int tempY; unsigned int tempY;
bool valid = false; bool valid;
do do
{ {
valid = true;
tempX = Random::get(0, gridCount_in.x - 1); tempX = Random::get(0, gridCount_in.x - 1);
tempY = Random::get(0, gridCount_in.y - 1); tempY = Random::get(0, gridCount_in.y - 1);
for (const auto& node : body_in) for (const auto& node : body_in)
{ {
if (node.gridPos.x != tempX and node.gridPos.y != tempY) if (node.gridPos.x == tempX and node.gridPos.y == tempY)
{ {
valid = true; valid = false;
} }
} }
} while (!valid); } while (!valid);

View File

@ -10,12 +10,15 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
Game::Game(bool useImgui_in) Game::Game(bool useImgui_in)
: config() : config()
, window({sf::VideoMode({1920u, 1080u}), "project-snake"}) , window({sf::VideoMode({1920u, 1080u}), "project-snake"})
, font("assets/fonts/ChakraPetch-Regular.ttf")
, score(font) , score(font)
, failSound(failSoundBuffer)
, winSound(winSoundBuffer)
, bgMusic(bgMusicBuffer)
, eatSound(eatSoundBuffer)
, moveSound(moveSoundBuffer)
, useImgui(useImgui_in) , useImgui(useImgui_in)
{ {
if (!ImGui::SFML::Init(window)) if (!ImGui::SFML::Init(window))
@ -31,8 +34,8 @@ Game::Game(bool useImgui_in)
return; return;
} }
gridCount.x = window.getSize().x / config.gridSize; gridCount.x = window.getSize().x / static_cast<unsigned int>(config.gridSize);
gridCount.y = window.getSize().y / config.gridSize; gridCount.y = window.getSize().y / static_cast<unsigned int>(config.gridSize);
player.body.reserve(100); player.body.reserve(100);
player.body.emplace_back(config.headGridStartPos); player.body.emplace_back(config.headGridStartPos);
@ -40,6 +43,51 @@ Game::Game(bool useImgui_in)
fruit.gridPos = {5, 5}; fruit.gridPos = {5, 5};
fruit.color = sf::Color::Red; fruit.color = sf::Color::Red;
if (!font.openFromFile("assets/fonts/ChakraPetch-Regular.ttf"))
{
std::cerr << "ERROR: Failed to load font!\n";
return;
}
if (!failSoundBuffer.loadFromFile("assets/sounds/lose.ogg"))
{
std::cerr << "ERROR: Failed to load lose.ogg! Check file path.\n";
return;
}
if (!winSoundBuffer.loadFromFile("assets/sounds/win.ogg"))
{
std::cerr << "ERROR: Failed to load lose.ogg! Check file path.\n";
return;
}
if (!bgMusicBuffer.loadFromFile("assets/sounds/bgMusic.wav"))
{
std::cerr << "ERROR: Failed to load lose.ogg! Check file path.\n";
return;
}
if (!eatSoundBuffer.loadFromFile("assets/sounds/eat.wav"))
{
std::cerr << "ERROR: Failed to load lose.ogg! Check file path.\n";
return;
}
if (!moveSoundBuffer.loadFromFile("assets/sounds/move.wav"))
{
std::cerr << "ERROR: Failed to load lose.ogg! Check file path.\n";
return;
}
failSound.setVolume(10.f);
winSound.setVolume(10.f);
bgMusic.setVolume(10.f);
eatSound.setVolume(10.f);
moveSound.setVolume(10.f);
bgMusic.setLooping(true);
bgMusic.play();
//uncomment to quickly test player movement //uncomment to quickly test player movement
/* /*
player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 1, config.headGridStartPos.y}); player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 1, config.headGridStartPos.y});
@ -48,14 +96,13 @@ Game::Game(bool useImgui_in)
player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 4, config.headGridStartPos.y}); player.body.emplace_back(sf::Vector2i{config.headGridStartPos.x - 4, config.headGridStartPos.y});
*/ */
tempRect.setSize(sf::Vector2f{(float)config.gridSize, (float)config.gridSize}); tempRect.setSize(sf::Vector2f{(config.gridSize), config.gridSize});
tempRect.setOutlineThickness(-5); tempRect.setOutlineThickness(-5);
tempRect.setOutlineColor(sf::Color::Black); tempRect.setOutlineColor(sf::Color::Black);
score.setPosition({10, static_cast<float>(window.getSize().y - 40)}); score.setPosition({10, static_cast<float>(window.getSize().y - 40)});
window.setFramerateLimit(config.framerate); window.setFramerateLimit(config.framerate);
} }
bool Game::parseConfigFile() bool Game::parseConfigFile()
@ -74,31 +121,37 @@ bool Game::parseConfigFile()
if (inputBuff == "framerate") if (inputBuff == "framerate")
{ {
configFile >> config.framerate; configFile >> config.framerate;
continue;
} }
if (inputBuff == "tickRate") if (inputBuff == "tickRate")
{ {
configFile >> config.tickRate; configFile >> config.tickRate;
continue;
} }
if (inputBuff == "playerHeadColor") if (inputBuff == "playerHeadColor")
{ {
configFile >> config.playerHeadColor.r >> config.playerHeadColor.g >> config.playerHeadColor.b; configFile >> config.playerHeadColor.r >> config.playerHeadColor.g >> config.playerHeadColor.b;
continue;
} }
if (inputBuff == "playerBodyColor") if (inputBuff == "playerBodyColor")
{ {
configFile >> config.playerBodyColor.r >> config.playerBodyColor.g >> config.playerBodyColor.b; configFile >> config.playerBodyColor.r >> config.playerBodyColor.g >> config.playerBodyColor.b;
continue;
} }
if (inputBuff == "headGridStartPos") if (inputBuff == "headGridStartPos")
{ {
configFile >> config.headGridStartPos.x >> config.headGridStartPos.y; configFile >> config.headGridStartPos.x >> config.headGridStartPos.y;
continue;
} }
if (inputBuff == "gridSize") if (inputBuff == "gridSize")
{ {
configFile >> config.gridSize; configFile >> config.gridSize;
continue;
} }
} }
@ -191,7 +244,8 @@ void Game::collision()
{ {
if (player.head().gridPos == player.body.at(i).gridPos) if (player.head().gridPos == player.body.at(i).gridPos)
{ {
fail = true; state = GameState::lose;
failSound.play();
return; return;
} }
} }
@ -201,13 +255,14 @@ void Game::collision()
player.body.emplace_back(player.body.back().previousGridPos); player.body.emplace_back(player.body.back().previousGridPos);
if (player.body.size() != (gridCount.x * gridCount.y)) if (player.body.size() != (gridCount.x * gridCount.y))
{ {
//play sound eatSound.play();
player.score += 100;
fruit.respawn(player.body, gridCount); fruit.respawn(player.body, gridCount);
} }
else else
{ {
//play win sound state = GameState::win;
winSound.play();
} }
} }
@ -237,13 +292,16 @@ void Game::movement()
if (frameCount % config.tickRate != 0) return; if (frameCount % config.tickRate != 0) return;
moveSound.play();
SnakeNode& head = player.head(); SnakeNode& head = player.head();
switch (player.inputBuffer) switch (player.inputBuffer)
{ {
case Direction::up: case Direction::up:
if (head.gridPos.y == 0) if (head.gridPos.y == 0)
{ {
fail = true; state = GameState::lose;
failSound.play();
return; return;
} }
@ -256,7 +314,8 @@ void Game::movement()
case Direction::down: case Direction::down:
if (head.gridPos.y == gridCount.y - 1) if (head.gridPos.y == gridCount.y - 1)
{ {
fail = true; state = GameState::lose;
failSound.play();
return; return;
} }
@ -269,7 +328,8 @@ void Game::movement()
case Direction::left: case Direction::left:
if (head.gridPos.x == 0) if (head.gridPos.x == 0)
{ {
fail = true; state = GameState::lose;
failSound.play();
return; return;
} }
@ -282,7 +342,8 @@ void Game::movement()
case Direction::right: case Direction::right:
if (head.gridPos.x == gridCount.x -1) if (head.gridPos.x == gridCount.x -1)
{ {
fail = true; state = GameState::lose;
failSound.play();
return; return;
} }
@ -334,12 +395,12 @@ void Game::render()
for (auto& node : player.body) for (auto& node : player.body)
{ {
tempRect.setFillColor(node.color.sfml()); tempRect.setFillColor(node.color.sfml());
tempRect.setPosition(node.windowPos((float)config.gridSize)); tempRect.setPosition(node.windowPos(config.gridSize));
window.draw(tempRect); window.draw(tempRect);
} }
tempRect.setFillColor(fruit.color.sfml()); tempRect.setFillColor(fruit.color.sfml());
tempRect.setPosition(fruit.windowPos((float)config.gridSize)); tempRect.setPosition(fruit.windowPos(config.gridSize));
window.draw(tempRect); window.draw(tempRect);
score.setString("Score: " + std::to_string(player.score)); score.setString("Score: " + std::to_string(player.score));
@ -353,11 +414,12 @@ void Game::render()
void Game::soundSystem() void Game::soundSystem()
{ {
if (state != GameState::playing)
}
void Game::scoreSystem()
{ {
bgMusic.stop();
eatSound.stop();
moveSound.stop();
}
} }
@ -365,22 +427,30 @@ void Game::resetGame()
{ {
player.body.clear(); player.body.clear();
player.body.emplace_back(config.headGridStartPos); player.body.emplace_back(config.headGridStartPos);
fail = false;
player.facing = Direction::up; player.facing = Direction::up;
fruit.respawn(player.body, gridCount);
state = GameState::playing;
bgMusic.play();
} }
void Game::failState() void Game::failState()
{ {
// if (failSound.getStatus() == sf::Sound::Status::Stopped) if (failSound.getStatus() == sf::Sound::Status::Stopped)
// { {
// resetGame(); resetGame();
// return; return;
// } }
} }
void Game::winState() void Game::winState()
{ {
if (winSound.getStatus() == sf::Sound::Status::Stopped)
{
resetGame();
return;
}
} }
void Game::run() void Game::run()
@ -393,21 +463,19 @@ void Game::run()
input(); input();
if (!fail and !win) if (state == GameState::playing)
{ {
movement(); movement();
collision(); collision();
soundSystem(); soundSystem();
scoreSystem();
} }
else if (fail) else if (state == GameState::lose)
{ {
failState(); failState();
} }
else if (win) else if (state == GameState::win)
{ {
winState(); winState();
} }
@ -420,3 +488,7 @@ void Game::run()
ImGui::SFML::Shutdown(); ImGui::SFML::Shutdown();
} }
/*
*
*/

View File

@ -5,7 +5,7 @@ int main(int argc, char* argv[])
{ {
// parse command-line arguments // parse command-line arguments
bool useImgui{true}; bool useImgui{true};
for (int i = 0; i < argc; i++) for (int i = 1; i < argc; i++)
{ {
if (!strcmp(argv[i], "--noImgui")) if (!strcmp(argv[i], "--noImgui"))
{ {