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{};
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);
};

View File

@ -1,14 +1,21 @@
#pragma once
#include <Util.h>
#include <Player.h>
#include <Fruit.h>
#include <GameConfig.h>
#include "Util.h"
#include "Player.h"
#include "Fruit.h"
#include "GameConfig.h"
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <imgui-SFML.h>
#include <imgui.h>
enum class GameState
{
playing,
lose,
win
};
class Game
{
@ -51,6 +58,16 @@ private:
sf::Text score;
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;
@ -62,6 +79,8 @@ private:
sf::Vector2u gridCount;
size_t frameCount{};
size_t fruitEaten{};
GameState state{GameState::playing};
bool useImgui;
bool fail{};
bool win{};

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ Fruit::Fruit(sf::Vector2i gridPos_in, const sf::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};
}
@ -16,16 +16,17 @@ void Fruit::respawn(const std::vector<SnakeNode>& body_in, sf::Vector2u gridCoun
{
unsigned int tempX;
unsigned int tempY;
bool valid = false;
bool valid;
do
{
valid = true;
tempX = Random::get(0, gridCount_in.x - 1);
tempY = Random::get(0, gridCount_in.y - 1);
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);

View File

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

View File

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