Skip to content

Commit

Permalink
Final Version
Browse files Browse the repository at this point in the history
- Implement settings persistence between runs of the application
- Add ability to change game speed and fpslock at runtime
- Give game mode a proper texture, score counter, and box for containing the snake
- Give snake a texture that rotates to follow the direction of the snake
- Give the fruit/pellets a texture
- Sound on death and pellet consumption
- Custom BGM during the game
anastasia-v-r authored Oct 14, 2019
2 parents f38e0d1 + 4c0a37e commit 58cb7c5
Showing 25 changed files with 292 additions and 68 deletions.
79 changes: 69 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -11,13 +11,23 @@ matrix:
- CONAN_SETTINGS_FLAG="-g cmake -s compiler=\"Visual Studio\" -s compiler.version=15 -s arch=x86_64 -s build_type=Release -b missing"
- CMAKE_GENERATOR_FLAG="-G \"Visual Studio 15 2017\" -DCMAKE_GENERATOR_PLATFORM=x64"
- BUILD_CONFIG=Release
- DEPLOY_EXE=winBin.zip
cache:
directories:
- $HOME/.conan/data

# Windows msvc Debug
- name: "Windows Debug"
os: windows
env:
- CONAN_SETTINGS_FLAG="-g cmake -s compiler=\"Visual Studio\" -s compiler.version=15 -s arch=x86_64 -s build_type=Debug -b missing"
- CMAKE_GENERATOR_FLAG="-G \"Visual Studio 15 2017\" -DCMAKE_GENERATOR_PLATFORM=x64"
- BUILD_CONFIG=Debug
- DEPLOY_EXE=winBin.zip
cache:
directories:
- $HOME/.conan/data

# MacOS clang Release
- name: "MacOS Release"
os: osx
@@ -26,9 +36,14 @@ matrix:
- compiler=clang
- COMPILER_CC=clang
- COMPILER_CXX=clang++
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Release"
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Release -b missing"
- CMAKE_GENERATOR_FLAG=""
- BUILD_CONFIG=Release
- DEPLOY_EXE=macBin.zip
cache:
directories:
- $HOME/.conan/data

# MacOS clang Debug
- name: "MacOS Debug"
os: osx
@@ -37,9 +52,14 @@ matrix:
- compiler=clang
- COMPILER_CC=clang
- COMPILER_CXX=clang++
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Debug"
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Debug -b missing"
- CMAKE_GENERATOR_FLAG=""
- BUILD_CONFIG=Debug
- DEPLOY_EXE=macBin.zip
cache:
directories:
- $HOME/.conan/data

# Linux gcc Release
- name: "Linux Release"
os: linux
@@ -48,13 +68,18 @@ matrix:
- COMPILER=g++-8
- COMPILER_CC=gcc-8
- COMPILER_CXX=g++-8
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Release -s compiler.libcxx=libstdc++11"
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Release -s compiler.libcxx=libstdc++11 -b missing"
- CMAKE_GENERATOR_FLAG="-G \"Unix Makefiles\""
- BUILD_CONFIG=Release
- DEPLOY_EXE=linuxBin.zip
cache:
directories:
- $HOME/.conan/data
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['gcc-8', 'g++-8' ]

# Linux gcc Debug
- name: "Linux Debug"
os: linux
@@ -63,26 +88,38 @@ matrix:
- COMPILER=g++-8
- COMPILER_CC=gcc-8
- COMPILER_CXX=g++-8
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Debug -s compiler.libcxx=libstdc++11"
- CONAN_SETTINGS_FLAG="-g cmake -s build_type=Debug -s compiler.libcxx=libstdc++11 -b missing"
- CMAKE_GENERATOR_FLAG="-G \"Unix Makefiles\""
- BUILD_CONFIG=Debug
- DEPLOY_EXE=linuxBin.zip
cache:
directories:
- $HOME/.conan/data
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['gcc-8', 'g++-8' ]
allow_failures:
- os: osx
- os: linux
fast_finish: true

# The pre-install script. On windows it will install conan via chocolatey
install:
before_install:
- |
if [[ "${TRAVIS_OS_NAME}" == "windows" ]]; then
choco install conan
else
pip install --user --upgrade pip
pip install --user conan --upgrade
choco install python3
export PATH="/c/Python37:/c/Python37/Scripts:$PATH"
python -m pip install --upgrade pip
fi
install:
- |
if [[ "${TRAVIS_OS_NAME}" == "windows" ]]; then
pip install conan
else
pip install --user --upgrade pip
pip install --user conan --upgrade
fi
# Setup Build
before_script:
# The path to conan does not get set properly because travis does not restart the shell
@@ -109,4 +146,26 @@ script:
# Cmake Build
- mkdir build && cd build
- eval cmake .. ${CMAKE_GENERATOR_FLAG}
- eval cmake --build . --config "${BUILD_CONFIG}"
- eval cmake --build . --config ${BUILD_CONFIG}

# Check dir
before_deploy:
- |
if [[ "${TRAVIS_OS_NAME}" == "windows" ]]; then
echo %cd%
ls
powershell.exe Compress-Archive -Path .\bin\ -DestinationPath ${DEPLOY_EXE}
else
pwd
ls
zip -r ${DEPLOY_EXE} bin/
fi
# Deploy to github
deploy:
provider: releases
api_key: ${GITHUB_TOKEN}
file: ${DEPLOY_EXE}
skip_cleanup: true
on:
branch: master
condition: "$BUILD_CONFIG = Release"
4 changes: 2 additions & 2 deletions .vs/tasks.vs.json
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
"workingDirectory": "conan/",
"command": "${env.COMSPEC}",
"args": [
"conan install .. -g cmake_multi -s build_type=Release"
"conan install .. -g cmake_multi -s compiler=\"Visual Studio\" -s compiler.version=15 -s arch=x86_64 -s build_type=Release -b missing"
]
},
{
@@ -18,7 +18,7 @@
"workingDirectory": "conan/",
"command": "${env.COMSPEC}",
"args": [
"conan install .. -g cmake_multi -s build_type=Debug"
"conan install .. -g cmake_multi -s compiler=\"Visual Studio\" -s compiler.version=15 -s arch=x86_64 -s build_type=Debug -b missing"
]
},
{
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -7,6 +7,11 @@ else()
cmake_policy(VERSION 3.14)
endif()

# OS
if(UNIX AND NOT APPLE)
set(LINUX TRUE)
endif()

# Project Creation
project (Cnake)
set (CMAKE_CXX_STANDARD 17)
@@ -36,6 +41,7 @@ else()
endif()
endif()

# Find some packaages
find_package(nlohmann_json 3.2.0 REQUIRED)

# Program Asset Management
19 changes: 3 additions & 16 deletions CMakeSettings.json
Original file line number Diff line number Diff line change
@@ -10,31 +10,19 @@
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [
{
"name": "CMAKE_MAKE_PROGRAM",
"value": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe",
"type": "FILEPATH"
}
]
"variables": []
},
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "Release",
"configurationType": "RelWithDebInfo",
"buildRoot": "${projectDir}\\build\\${name}",
"installRoot": "${projectDir}\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [
{
"name": "CMAKE_MAKE_PROGRAM",
"value": "C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe",
"type": "FILEPATH"
}
]
"variables": []
},
{
"name": "WSL-Debug",
@@ -48,7 +36,6 @@
"ctestCommandArgs": "",
"inheritEnvironments": [ "linux_x64" ],
"wslPath": "${defaultWSLPath}",
"addressSanitizerEnabled": true,
"addressSanitizerRuntimeFlags": "detect_leaks=0",
"variables": []
}
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -58,7 +58,10 @@ This is a clone of the famous "Snake" game coded in [C++](http://cplusplus.com)
## Dependencies && Resource
SFML v2.5.1
- All the static libraries
- All includes
- All includes

Conan v1.11.1
Cmake v3.1+

## Contributions
If you wish to contribute to my little project here for some odd reason,
@@ -70,3 +73,7 @@ you are welcome to do so but just follow a few things.

## License
This project is under the [MIT License](https://choosealicense.com/licenses/mit/)

## Credits
[Pickup_03](https://freesound.org/people/LittleRobotSoundFactory/sounds/270342/)"eat.wav" by [Little Robot Sound Factory](https://freesound.org/people/LittleRobotSoundFactory/) under the [Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/legalcode)
[Hit_03](https://freesound.org/people/LittleRobotSoundFactory/sounds/270332/)"die.wav" by [Little Robot Sound Factory](https://freesound.org/people/LittleRobotSoundFactory/) under the [Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/legalcode)
Binary file added assets/audio/bgm.wav
Binary file not shown.
Binary file added assets/audio/die.wav
Binary file not shown.
Binary file added assets/audio/eat.wav
Binary file not shown.
4 changes: 4 additions & 0 deletions assets/modes/GameMode.json
Original file line number Diff line number Diff line change
@@ -12,6 +12,10 @@
{
"textureName": "snakebody",
"textureLoc": "SnakeBody.png"
},
{
"textureName": "fruit",
"textureLoc": "Fruit.png"
}
],
"objectCount": 1,
46 changes: 41 additions & 5 deletions assets/modes/SettingsMode.json
Original file line number Diff line number Diff line change
@@ -3,21 +3,57 @@
"textures": [
{
"textureName": "background",
"textureLoc": "MenuBg.png"
"textureLoc": "SettingsSplash.png"
}
],
"objectCount": 2,
"objectCount": 8,
"objects": [
{
"name": "background",
"size": [ 1920, 1080 ],
"textureName": "background"
},
{
"name": "placeHolder",
"name": "fps60",
"size": [ 230, 130 ],
"position": [ 1010, 180 ],
"textureName": "empty"
},
{
"name": "fpsUnlimited",
"size": [ 400, 130 ],
"position": [ 1250, 180 ],
"textureName": "empty"
},
{
"name": "speedSlow",
"size": [ 230, 130 ],
"position": [ 870, 475 ],
"textureName": "empty"
},
{
"name": "speedMed",
"size": [ 330, 130 ],
"position": [ 1105, 475 ],
"textureName": "empty"
},
{
"name": "speedFast",
"size": [ 200, 130 ],
"position": [ 1440, 475 ],
"textureName": "empty"
},
{
"name": "SaveButton",
"size": [ 400, 200 ],
"position": [ 400, 770 ],
"textureName": "empty"
},
{
"name": "ExitButton",
"size": [ 400, 200 ],
"position": [ 760, 430 ],
"textureName": "green"
"position": [ 1110, 770 ],
"textureName": "empty"
}
]
}
Binary file added assets/textures/Fruit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/textures/SettingsSplash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/textures/SnakeHead.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/textures/playfield.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/textures/snakebody.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion conanfile.txt
Original file line number Diff line number Diff line change
@@ -4,4 +4,5 @@ jsonformoderncpp/3.7.0@vthiery/stable

[options]
sfml:window=True
sfml:graphics=True
sfml:graphics=True
sfml:audio=True
7 changes: 7 additions & 0 deletions include/GameMode.hpp
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
#include "Mode.hpp"
#include "Player.hpp"
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>

class GameMode : public Mode
{
@@ -12,5 +13,11 @@ class GameMode : public Mode
void processKeys(sf::Keyboard::Key, bool);
private:
Player mPlayer;
sf::Text score;
sf::Font font;
sf::Sound eat;
sf::SoundBuffer eatSound;
sf::Sound die;
sf::SoundBuffer dieSound;
float gameSpeed;
};
5 changes: 4 additions & 1 deletion include/Player.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <vector>
#include <mutex>

@@ -20,15 +21,17 @@ class Player : public sf::Drawable
// Setters
void processKeys(sf::Keyboard::Key);
// Getters
sf::Vector2f getHeadPos();
// Processors
void movePlayer();
void addPart();
bool safeCheck(sf::RectangleShape&);
bool safeCheck(sf::RectangleShape&, sf::Text&, sf::Sound&, sf::Sound&);
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
private:
std::vector<sf::RectangleShape> snakeBody;
Direction m_dir;
Direction m_lastDir;
std::mutex* mu;
int playerScore;
};
6 changes: 4 additions & 2 deletions include/Settings.hpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#pragma once
#include <SFML/Graphics.hpp>

class Settings
{
public:
Settings();
Settings(sf::RenderWindow*);
~Settings() = default;
bool getFpsLock() { return fpsLock; };
float getGameSpeed() { return gameSpeed; };
void setFpsLock(bool temp) { fpsLock = temp; };
void setFpsLock(bool);
void setGameSpeed(float temp) { gameSpeed = temp; };
void saveToFile();
private:
bool fpsLock;
float gameSpeed;
sf::RenderWindow* window;
};
7 changes: 5 additions & 2 deletions include/SettingsMode.hpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#pragma once
#include "Mode.hpp"
#include "Settings.hpp"
#include <SFML/Graphics.hpp>

class SettingsMode : public Mode
{
public:
SettingsMode(std::mutex* mutex);
SettingsMode(std::mutex*, Settings*);
virtual std::pair<ModeAction, ModeOption> Run(sf::Time, sf::RenderWindow&) override;
private:

private:

Settings* settings;
bool fps;
float speed;
};
22 changes: 18 additions & 4 deletions src/GameMode.cpp
Original file line number Diff line number Diff line change
@@ -8,10 +8,22 @@ GameMode::GameMode(std::mutex* mutex, float speed)
: Mode("GameMode.json", mutex, ModeOption::Game)
, mPlayer(objectTextures, mutex)
, gameSpeed{ speed } {
eatSound.loadFromFile("assets/audio/eat.wav");
eat.setBuffer(eatSound);
eat.setVolume(40);
dieSound.loadFromFile("assets/audio/die.wav");
die.setBuffer(dieSound);
eat.setVolume(60);
font.loadFromFile("assets/fonts/bauh.ttf");
score.setFont(font);
score.setCharacterSize(30);
score.setString("Score : 0");
score.setPosition(1920 - (score.getLocalBounds().width + (score.getCharacterSize() * 2)), 0);
screenObjects.emplace_back(&score);
screenObjects.emplace_back(&mPlayer);
sf::RectangleShape food(sf::Vector2f(50, 50));
food.setPosition(500, 500);
Mode::pushObject("food", food, "Blue");
food.setPosition(510, 490);
Mode::pushObject("food", food, "fruit");
}

std::pair<ModeAction, ModeOption> GameMode::Run(sf::Time time, sf::RenderWindow& window) {
@@ -39,13 +51,15 @@ std::pair<ModeAction, ModeOption> GameMode::Run(sf::Time time, sf::RenderWindow&
// Update Game Logic
if (timeBank.asSeconds() > gameSpeed) {
mPlayer.movePlayer();
if (mPlayer.safeCheck(screenObjectsMap["food"])) {
if (mPlayer.safeCheck(screenObjectsMap["food"], score, eat, die)) {
return std::make_pair(ModeAction::Add, ModeOption::Lose);
}
auto [x, y] = mPlayer.getHeadPos();
std::cout << "[" << x << "," << y << "]" << std::endl;
timeBank -= (sf::seconds)(gameSpeed);
} else {
timeBank += time;
}
// Im case of no state changes
// In case of no state changes
return std::make_pair(ModeAction::None, ModeOption::None);
}
50 changes: 37 additions & 13 deletions src/Player.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
#include "Player.hpp"
#include <iostream>
#include <time.h>
#include <string>

Player::Player(const std::map<std::string, sf::Texture>& textures, std::mutex* mut)
: snakeBody(5, sf::RectangleShape(sf::Vector2f(50.0f, 50.0f)))
: snakeBody(4, sf::RectangleShape(sf::Vector2f(50.0f, 50.0f)))
, m_dir{ Direction::Left }
, m_lastDir{ Direction::Left }
, mu{ mut }
, playerScore{ 0 }
{
for (int i = 0; i < snakeBody.size(); i++) {
snakeBody[i].setPosition((float)(800 + (i * 100)), 500.0f);
snakeBody[i].setPosition((float)(985 + (i * 50)), 565.0f);
snakeBody[i].setTexture(&(textures.at("snakebody")));
snakeBody[i].setOrigin(snakeBody[i].getSize().x / 2, snakeBody[i].getSize().y / 2);
}
snakeBody[0].setTexture(&(textures.at("snakehead")));
}
@@ -52,20 +55,25 @@ void Player::processKeys(sf::Keyboard::Key key) {
void Player::movePlayer() {
sf::Vector2f vel;
auto scale = snakeBody[0].getSize().x;
auto* head = &snakeBody[0];
std::cout << scale;
switch (m_dir)
{
case Up:
vel = sf::Vector2f(0, -scale);
head->setRotation(90);
break;
case Right:
vel = sf::Vector2f(scale, 0);
head->setRotation(180);
break;
case Down:
vel = sf::Vector2f(0, scale);
head->setRotation(270);
break;
case Left:
vel = sf::Vector2f(-scale, 0);
head->setRotation(0);
break;
default:
break;
@@ -87,28 +95,38 @@ void Player::addPart() {
mu->unlock();
}

bool Player::safeCheck(sf::RectangleShape& fruit) {
bool Player::safeCheck(sf::RectangleShape& fruit, sf::Text& text, sf::Sound& eat, sf::Sound& die) {
auto head = snakeBody[0];
sf::Vector2f headPos(head.getPosition().x + (head.getSize().x / 2), head.getPosition().y + (head.getSize().y / 2));
sf::Vector2f headPos(head.getPosition().x, head.getPosition().y);
sf::Vector2f fruitPos(fruit.getPosition().x + (fruit.getSize().x / 2), fruit.getPosition().y + (fruit.getSize().y / 2));
for (int i = 1; i < snakeBody.size(); i++) {
if (snakeBody[i].getGlobalBounds().contains(headPos)) {
for (int i = 1; i < snakeBody.size(); i++) { // Check if snake has eaten itself
if (snakeBody[i].getGlobalBounds().intersects(snakeBody[0].getGlobalBounds())) {
die.play();
return true;
}
}
if (head.getGlobalBounds().contains(fruitPos)) {
std::srand((unsigned int)std::time(NULL));
if (head.getGlobalBounds().contains(fruitPos)) { // Check if snake ate fruit and is so replace it
Player::addPart();
float x = (float)((rand() % (1920 / 50)) * 50);
float y = (float)((rand() % (1080 / 50)) * 50);
eat.play();
text.setString("Score : " + std::to_string(++playerScore));
float x = (float)((rand() % (1920 / 50)) * 50) + 10.0f;
float y = (float)((rand() % (1080 / 50)) * 50) - 10.0f;
while (x < 310 || x >= 1610 || y < 40 || y >= 1040) {
x = (float)((rand() % (1920 / 50)) * 50) + 10.0f;
y = (float)((rand() % (1080 / 50)) * 50) - 10.0f;
}
bool done = true;
fruit.setPosition(x, y);
fruitPos = sf::Vector2f(fruit.getPosition().x + (fruit.getSize().x / 2), fruit.getPosition().y + (fruit.getSize().y / 2));
do {
for (int i = 1; i < snakeBody.size(); i++) {
if (snakeBody[i].getGlobalBounds().contains(fruitPos)) {
x = (float)((rand() % (1920 / 50)) * 50);
y = (float)((rand() % (1080 / 50)) * 50);
x = (float)((rand() % (1920 / 50)) * 50) + 10.0f;
y = (float)((rand() % (1080 / 50)) * 50) - 10.0f;
while (x < 310 || x >= 1610 || y < 40 || y >= 1040) {
x = (float)((rand() % (1920 / 50)) * 50) + 10.0f;
y = (float)((rand() % (1080 / 50)) * 50) - 10.0f;
}
fruit.setPosition(x, y);
fruitPos = sf::Vector2f(fruit.getPosition().x + (fruit.getSize().x / 2), fruit.getPosition().y + (fruit.getSize().y / 2));
done = false;
@@ -117,12 +135,18 @@ bool Player::safeCheck(sf::RectangleShape& fruit) {
done = true;
}
} while (!done);
} else if (headPos.x < 0 || headPos.x > 1920 || headPos.y < 0 || headPos.y > 1080) {
} else if (headPos.x < 310 || headPos.x > 1610 || headPos.y < 40 || headPos.y > 1040) {
die.play();
return true;
}
return false;
}


sf::Vector2f Player::getHeadPos() {
return snakeBody[0].getPosition();
}

void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const {
for (auto& snakePart : snakeBody) {
target.draw(snakePart, states);
16 changes: 13 additions & 3 deletions src/Settings.cpp
Original file line number Diff line number Diff line change
@@ -3,26 +3,28 @@
#include <iostream>
#include <string>

Settings::Settings() {
Settings::Settings(sf::RenderWindow* win) : window{ win } {
std::fstream file;
file.open("assets/settings.txt", std::ios::in);
std::string line;
if (!file.fail()) {
if (!file.fail()) { // Load from existing file
std::getline(file, line, '\n');
std::cout << line << std::endl;
std::getline(file, line, '\n');
std::cout << line << std::endl;
if (line == "true") {
fpsLock = true;
win->setFramerateLimit(60);
} else {
fpsLock = false;
win->setFramerateLimit(0);
}
std::getline(file, line, '\n');
std::cout << line << std::endl;
std::getline(file, line, '\n');
std::cout << line << std::endl;
gameSpeed = std::stof(line);
} else {
} else { // Create file if one does not exist
file.open("assets/settings.txt", std::ios::out);
file << "# fpslock\n" << "false\n" << "# gamespeed\n" << ".10f\n";
fpsLock = false;
@@ -31,6 +33,14 @@ Settings::Settings() {
file.close();
}

void Settings::setFpsLock(bool temp) {
fpsLock = temp;
if (fpsLock)
window->setFramerateLimit(60);
else
window->setFramerateLimit(0);
}

void Settings::saveToFile() {
std::fstream file;
file.open("assets/settings.txt", std::ios::out);
31 changes: 29 additions & 2 deletions src/SettingsMode.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include "SettingsMode.hpp"
#include "Settings.hpp"
#include <iostream>

SettingsMode::SettingsMode(std::mutex* mutex) : Mode("SettingsMode.json", mutex, ModeOption::Intro) {
SettingsMode::SettingsMode(std::mutex* mutex, Settings* settings) : settings{ settings }, Mode("SettingsMode.json", mutex, ModeOption::Intro) {
fps = settings->getFpsLock();
speed = settings->getGameSpeed();
auto mode = sf::VideoMode::getDesktopMode();
}

@@ -16,11 +20,34 @@ std::pair<ModeAction, ModeOption> SettingsMode::Run(sf::Time time, sf::RenderWin
case sf::Event::KeyPressed:
switch (evnt.key.code)
{
case sf::Keyboard::Escape:
case sf::Keyboard::BackSpace:
return std::make_pair(ModeAction::DropTo, ModeOption::Menu);
break;
}
break;
case sf::Event::MouseButtonPressed: {
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
sf::Vector2f mousePosF(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
if (screenObjectsMap["fps60"].getGlobalBounds().contains(mousePosF))
fps = true;
else if (screenObjectsMap["fpsUnlimited"].getGlobalBounds().contains(mousePosF))
fps = false;
else if (screenObjectsMap["speedSlow"].getGlobalBounds().contains(mousePosF))
speed = .20f;
else if (screenObjectsMap["speedMed"].getGlobalBounds().contains(mousePosF))
speed = .10f;
else if (screenObjectsMap["speedFast"].getGlobalBounds().contains(mousePosF))
speed = .05f;
else if (screenObjectsMap["SaveButton"].getGlobalBounds().contains(mousePosF)) {
settings->setFpsLock(fps);
settings->setGameSpeed(speed);
return std::make_pair(ModeAction::DropTo, ModeOption::One);
}
else if (screenObjectsMap["ExitButton"].getGlobalBounds().contains(mousePosF))
return std::make_pair(ModeAction::DropTo, ModeOption::One);
}
break;
default:
break;
}
@@ -31,6 +58,6 @@ std::pair<ModeAction, ModeOption> SettingsMode::Run(sf::Time time, sf::RenderWin
} else {
timeBank += time;
}
// Im case of no state changes
// In case of no state changes
return std::make_pair(ModeAction::None, ModeOption::None);
}
46 changes: 40 additions & 6 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
// Preprocessor
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <thread>
#include <mutex>
#include <atomic>
#include <time.h>
#include <Player.hpp>
#include <ModeList.hpp>
#include <RuntimeStats.hpp>
#include <Settings.hpp>
// Entry Point
int main() {
// Seed rand
std::srand((unsigned int)std::time(NULL));
// Create mutex for synccing threads
static std::mutex mu;
// Setup Window
auto desktop = sf::VideoMode::getDesktopMode();
desktop.width += 1;
sf::RenderWindow window(desktop, "Cnake", sf::Style::None);
window.setActive(false);
// Load Settings
Settings gameSettings;
if (gameSettings.getFpsLock()) {
window.setFramerateLimit(60);
}
Settings gameSettings(&window);
// Prepare Stack
std::stack<std::unique_ptr<Mode>> ModeStack;
ModeStack.push(std::make_unique<IntroMode>(&mu));
@@ -68,6 +70,26 @@ int main() {
}
std::cout << "Rendering thread closed!" << std::endl;
});
// Variables for manipulation music thread
std::atomic<bool> killSong = false;
std::atomic<bool> playSong = false;
// Create Music Thread
std::thread MusicThread([&isRunning, &killSong, &playSong] {
sf::Music music;
music.openFromFile("assets/audio/bgm.wav");
music.setVolume(70);
music.setLoop(true);
while (isRunning) {
if (killSong) {
music.pause();
killSong = false;
} else if (playSong) {
music.play();
playSong = false;
}
}
music.stop();
});
// Begin Game
sf::Clock GameClock;
while (!ModeStack.empty()) {
@@ -88,13 +110,15 @@ int main() {
ModeStack.push(std::make_unique<MenuMode>(&mu));
break;
case ModeOption::Settings:
ModeStack.push(std::make_unique<SettingsMode>(&mu));
ModeStack.push(std::make_unique<SettingsMode>(&mu, &gameSettings));
break;
case ModeOption::Game:
playSong = true;
ModeStack.push(std::make_unique<GameMode>(&mu, gameSettings.getGameSpeed()));
break;
case ModeOption::Paused:
case ModeOption::Lose:
killSong = true;
isPaused = true;
while (!isWaiting) {
}
@@ -114,16 +138,26 @@ int main() {
// Safely Kill Render Thread
if ((result.second == ModeOption::None) || (result.second == ModeOption::One && ModeStack.size() == 1)) {
isRunning = false;
MusicThread.join();
RenderThread.join();
}
} else if (ModeStack.top()->type() == ModeOption::Game) {
killSong = true;
}
mu.lock();
if (ModeStack.top()->type() == ModeOption::Paused) {
playSong = true;
showStats = true;
}
if (result.second == ModeOption::One) {
if (ModeStack.top()->type() == ModeOption::Game) {
killSong = true;
}
ModeStack.pop();
} else {
while (!(ModeStack.empty()) && (ModeStack.top()->type() != result.second)) {
if (ModeStack.top()->type() == ModeOption::Game) {
killSong = true;
}
ModeStack.pop();
}
}

0 comments on commit 58cb7c5

Please sign in to comment.