Add audio, bug fix in map reader
This commit is contained in:
parent
6896cf037d
commit
f8060438da
Binary file not shown.
|
@ -2,9 +2,13 @@ size
|
||||||
7 7
|
7 7
|
||||||
map
|
map
|
||||||
2 2 2 2 2 2 2
|
2 2 2 2 2 2 2
|
||||||
2 0 0 0 0 0 2
|
2 0 0 0 0 6 2
|
||||||
2 0 0 1 0 0 2
|
2 0 0 1 0 0 2
|
||||||
2 0 0 1 1 0 2
|
2 0 0 1 1 0 2
|
||||||
2 1 1 2 2 2 2
|
2 1 1 2 2 2 2
|
||||||
2 0 0 0 0 0 2
|
2 0 0 0 0 5 2
|
||||||
2 2 2 2 2 2 2
|
2 2 2 2 2 2 2
|
||||||
|
teleport
|
||||||
|
5 5 1 1
|
||||||
|
trigger
|
||||||
|
1 5 4 5 0
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
Audio::Audio(const std::string &background_path, std::array<std::string, N_SOUNDS> &&sounds_paths)
|
||||||
|
{
|
||||||
|
SfMusicPtr music = std::make_unique<sf::Music>();
|
||||||
|
if (music->openFromFile(background_path))
|
||||||
|
music->setLoop(true);
|
||||||
|
else
|
||||||
|
music = nullptr;
|
||||||
|
|
||||||
|
background_music = std::move(music);
|
||||||
|
|
||||||
|
SoundEffectPtr effect;
|
||||||
|
for (int i = 0; i < N_SOUNDS; ++i)
|
||||||
|
{
|
||||||
|
effect = std::make_unique<SoundEffect>();
|
||||||
|
if (effect->buffer.loadFromFile(sounds_paths[i]))
|
||||||
|
{
|
||||||
|
effect->sound.setBuffer(effect->buffer);
|
||||||
|
array_sounds[i] = std::move(effect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
array_sounds[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Audio::setSound(const SOUND_TYPE &type, const std::string &sound_file_path)
|
||||||
|
{
|
||||||
|
SoundEffectPtr effect = std::make_unique<SoundEffect>();
|
||||||
|
|
||||||
|
if (!effect->buffer.loadFromFile(sound_file_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
effect->sound.setBuffer(effect->buffer);
|
||||||
|
|
||||||
|
array_sounds[type] = std::move(effect);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::playSound(const SOUND_TYPE &type)
|
||||||
|
{
|
||||||
|
array_sounds[type]->sound.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Audio::setBackground(const std::string &music_file_path)
|
||||||
|
{
|
||||||
|
SfMusicPtr music = std::make_unique<sf::Music>();
|
||||||
|
|
||||||
|
if (!music->openFromFile(music_file_path))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
background_music = std::move(music);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::playBackground()
|
||||||
|
{
|
||||||
|
background_music->play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::stopBackground()
|
||||||
|
{
|
||||||
|
background_music->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::pauseBackground()
|
||||||
|
{
|
||||||
|
background_music->pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::setBackgroundVolume(const float &volume)
|
||||||
|
{
|
||||||
|
background_music->setVolume(volume);
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef AUDIO_H
|
||||||
|
#define AUDIO_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <array>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <SFML/Audio.hpp>
|
||||||
|
|
||||||
|
enum SOUND_TYPE {
|
||||||
|
FOOTSTEP_SOUND = 0,
|
||||||
|
|
||||||
|
N_SOUNDS
|
||||||
|
};
|
||||||
|
|
||||||
|
class Audio
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// Struct for small sounds, like shots, foot steps, etc.
|
||||||
|
// As we always need to store SoundBuffer in the same scope as Sound, it's better to make struct.
|
||||||
|
struct SoundEffect {
|
||||||
|
sf::SoundBuffer buffer;
|
||||||
|
sf::Sound sound;
|
||||||
|
};
|
||||||
|
|
||||||
|
using SfMusicPtr = std::unique_ptr<sf::Music>;
|
||||||
|
using SoundEffectPtr = std::unique_ptr<SoundEffect>;
|
||||||
|
|
||||||
|
std::array<SoundEffectPtr, N_SOUNDS> array_sounds;
|
||||||
|
SfMusicPtr background_music;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Audio(const std::string &background_file_name, std::array<std::string, N_SOUNDS> &&sounds_paths);
|
||||||
|
|
||||||
|
bool setSound(const SOUND_TYPE &type, const std::string &sound_file_path);
|
||||||
|
void playSound(const SOUND_TYPE &type);
|
||||||
|
|
||||||
|
bool setBackground(const std::string &music_file_path);
|
||||||
|
void playBackground();
|
||||||
|
void stopBackground();
|
||||||
|
void pauseBackground();
|
||||||
|
void setBackgroundVolume(const float &volume);
|
||||||
|
};
|
||||||
|
|
||||||
|
using AudioPtr = std::unique_ptr<Audio>;
|
||||||
|
|
||||||
|
#endif // AUDIO_H
|
|
@ -195,8 +195,7 @@ TriggerCell::~TriggerCell()
|
||||||
|
|
||||||
void TriggerCell::addTarget(CellPtr &&cell)
|
void TriggerCell::addTarget(CellPtr &&cell)
|
||||||
{
|
{
|
||||||
UNUSED(cell);
|
vector_cells.emplace_back(std::move(cell));
|
||||||
//cells.emplace_back(cell);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TriggerCell::onMovingTo(HeroPtr &hero, LevelPtr &level)
|
bool TriggerCell::onMovingTo(HeroPtr &hero, LevelPtr &level)
|
||||||
|
@ -204,7 +203,7 @@ bool TriggerCell::onMovingTo(HeroPtr &hero, LevelPtr &level)
|
||||||
UNUSED(hero);
|
UNUSED(hero);
|
||||||
|
|
||||||
// We replace needed cells with the ones that the trigger provides.
|
// We replace needed cells with the ones that the trigger provides.
|
||||||
for (CellPtr &cell : cells)
|
for (CellPtr &cell : vector_cells)
|
||||||
{
|
{
|
||||||
const coordinate &row = cell->row();
|
const coordinate &row = cell->row();
|
||||||
const coordinate &col = cell->col();
|
const coordinate &col = cell->col();
|
||||||
|
@ -213,6 +212,8 @@ bool TriggerCell::onMovingTo(HeroPtr &hero, LevelPtr &level)
|
||||||
level->getCellAt(row, col) = std::move(cell);
|
level->getCellAt(row, col) = std::move(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector_cells.clear();
|
||||||
|
|
||||||
// It's an impassable object, so player can't move to here.
|
// It's an impassable object, so player can't move to here.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
14
src/cell.h
14
src/cell.h
|
@ -50,7 +50,7 @@ class Cell : public Entity
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
sf::Color cell_color;
|
sf::Color cell_color;
|
||||||
coordinate height_shift;
|
coordinate height_shift;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Cell(coordinate cell_row = 0,
|
Cell(coordinate cell_row = 0,
|
||||||
|
@ -61,10 +61,10 @@ public:
|
||||||
|
|
||||||
sf::Color color() const noexcept;
|
sf::Color color() const noexcept;
|
||||||
|
|
||||||
/// "shift_by_y" indicates the height of current cell
|
/// "shift_by_y" indicates the height of current cell
|
||||||
/// Height is a shift of y coordinate on the scene, relatively to the ground (which is 0)
|
/// Height is a shift of y coordinate on the scene, relatively to the ground (which is 0)
|
||||||
void setHeightShift(coordinate shift_by_y);
|
void setHeightShift(coordinate shift_by_y);
|
||||||
coordinate heightShift() const;
|
coordinate heightShift() const;
|
||||||
|
|
||||||
/// Determine if Hero can move onto this cell or not
|
/// Determine if Hero can move onto this cell or not
|
||||||
virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) = 0;
|
virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) = 0;
|
||||||
|
@ -179,7 +179,7 @@ public:
|
||||||
virtual ~TeleportCell() override;
|
virtual ~TeleportCell() override;
|
||||||
|
|
||||||
/// Set the coordinates of this teleport destination
|
/// Set the coordinates of this teleport destination
|
||||||
void setDestination(coordinate new_cell_row, coordinate new_cell_col);
|
void setDestination(coordinate new_cell_row, coordinate new_cell_col);
|
||||||
|
|
||||||
virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override;
|
virtual bool onMovingTo(HeroPtr &hero, LevelPtr &level) override;
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ class TriggerCell final : public Cell
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// Vector of cells to place on map
|
// Vector of cells to place on map
|
||||||
std::vector<CellPtr> cells;
|
std::vector<CellPtr> vector_cells;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Vector of cell types you can cast in to
|
/// Vector of cell types you can cast in to
|
||||||
|
|
33
src/game.cpp
33
src/game.cpp
|
@ -8,44 +8,51 @@ Game::Game()
|
||||||
// Generate level
|
// Generate level
|
||||||
level = std::make_unique<Level>();
|
level = std::make_unique<Level>();
|
||||||
|
|
||||||
|
audio = std::make_unique<Audio>("background_music.ogg", std::array<std::string, N_SOUNDS> { "footstep_sound.wav" });
|
||||||
|
|
||||||
// Prepare level renderer
|
// Prepare level renderer
|
||||||
renderer = std::make_unique<Renderer>();
|
renderer = std::make_unique<Renderer>();
|
||||||
|
|
||||||
main_window.create(sf::VideoMode(renderer->windowSize() * 5, renderer->windowSize() * 5), "SFML-Test Application", sf::Style::Default);
|
main_window.create(sf::VideoMode(renderer->windowSize() * 3, renderer->windowSize() * 3), "SFML-Test Application", sf::Style::Default);
|
||||||
main_window.setActive();
|
main_window.setActive();
|
||||||
main_window.setFramerateLimit(60);
|
main_window.setFramerateLimit(60);
|
||||||
|
|
||||||
current_level = 1;
|
current_level = 1;
|
||||||
|
|
||||||
|
audio->setBackgroundVolume(15.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Game::run()
|
int Game::run()
|
||||||
{
|
{
|
||||||
// Initial level rendering
|
audio->playBackground();
|
||||||
renderer->render(level, hero, main_window);
|
|
||||||
|
|
||||||
// On the game loop
|
// On the game loop
|
||||||
while (main_window.isOpen())
|
while (main_window.isOpen())
|
||||||
{
|
{
|
||||||
sf::Event event;
|
sf::Event event;
|
||||||
while (main_window.pollEvent(event))
|
while (main_window.pollEvent(event))
|
||||||
{
|
{
|
||||||
if (event.type == sf::Event::Closed)
|
switch (event.type)
|
||||||
main_window.close();
|
|
||||||
|
|
||||||
// Handling keyboard activity
|
|
||||||
if (event.type == sf::Event::KeyPressed)
|
|
||||||
{
|
{
|
||||||
// Move
|
case sf::Event::Closed:
|
||||||
onMoving(event.key.code);
|
main_window.close();
|
||||||
|
break;
|
||||||
|
|
||||||
// Probably something changed! Re-render
|
case sf::Event::KeyPressed:
|
||||||
renderer->render(level, hero, main_window);
|
audio->playSound(FOOTSTEP_SOUND);
|
||||||
|
onMoving(event.key.code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderer->render(level, hero, main_window);
|
||||||
main_window.display();
|
main_window.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audio->stopBackground();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "hero.h"
|
#include "hero.h"
|
||||||
#include "level.h"
|
#include "level.h"
|
||||||
|
#include "audio.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
|
|
||||||
/// The main class where all the process happens
|
/// The main class where all the process happens
|
||||||
|
@ -16,7 +17,8 @@ private:
|
||||||
// Game entities
|
// Game entities
|
||||||
HeroPtr hero;
|
HeroPtr hero;
|
||||||
LevelPtr level;
|
LevelPtr level;
|
||||||
std::unique_ptr<Renderer> renderer;
|
AudioPtr audio;
|
||||||
|
std::unique_ptr<Renderer> renderer; // wer is `using RendererPrt = ...` A?A?A?
|
||||||
|
|
||||||
int current_level;
|
int current_level;
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,12 @@ std::unique_ptr<D> static_unique_pointer_cast(std::unique_ptr<B>&& old)
|
||||||
return std::unique_ptr<D>{static_cast<D *>(old.release())};
|
return std::unique_ptr<D>{static_cast<D *>(old.release())};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Level::Map::init(const std::string &map_file_name)
|
void Level::Map::init(const std::string &path)
|
||||||
{
|
{
|
||||||
prepareDefaultCells();
|
prepareDefaultCells();
|
||||||
|
|
||||||
std::ifstream file;
|
std::ifstream file;
|
||||||
file.open(map_file_name);
|
file.open(path);
|
||||||
|
|
||||||
std::string cur_line;
|
std::string cur_line;
|
||||||
std::istringstream sstr;
|
std::istringstream sstr;
|
||||||
|
@ -109,13 +109,15 @@ void Level::Map::readTrigger(std::istringstream &sstr)
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
auto trigger_cell = static_unique_pointer_cast<TriggerCell>(std::move(data[src_row][src_col]));
|
auto trigger_cell = static_unique_pointer_cast<TriggerCell>(std::move(data[src_row][src_col]));
|
||||||
trigger_cell->addTarget(default_cells[cell_type]->clone());
|
auto dest_cell = default_cells[cell_type]->clone();
|
||||||
|
dest_cell->setPosition(dest_row, dest_col);
|
||||||
|
trigger_cell->addTarget(std::move(dest_cell));
|
||||||
data[src_row][src_col] = std::move(trigger_cell);
|
data[src_row][src_col] = std::move(trigger_cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
Level::Level(const std::string &map_file_name)
|
Level::Level(const std::string &path)
|
||||||
{
|
{
|
||||||
map.init(map_file_name);
|
map.init(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Level::rows() const
|
size_t Level::rows() const
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
#ifndef LEVEL_H
|
#ifndef LEVEL_H
|
||||||
#define LEVEL_H
|
#define LEVEL_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "cell.h"
|
#include "cell.h"
|
||||||
|
|
||||||
// Very desirable to create module for default values
|
// Very desirable to create module for default values
|
||||||
const std::string default_map_file_name = "test_map";
|
const std::string default_file_path = "test_map";
|
||||||
|
|
||||||
/// Abstraction over 2D array to quickly get access to level cells
|
/// Abstraction over 2D array to quickly get access to level cells
|
||||||
class Level
|
class Level
|
||||||
|
@ -40,7 +42,7 @@ private:
|
||||||
size_t rows, cols;
|
size_t rows, cols;
|
||||||
std::array<CellPtr, N_CELLS> default_cells;
|
std::array<CellPtr, N_CELLS> default_cells;
|
||||||
|
|
||||||
void init(const std::string &map_file_name = default_map_file_name);
|
void init(const std::string &path = default_file_path);
|
||||||
|
|
||||||
/// Prepare prototypes of default cells
|
/// Prepare prototypes of default cells
|
||||||
void prepareDefaultCells();
|
void prepareDefaultCells();
|
||||||
|
@ -56,7 +58,7 @@ private:
|
||||||
sf::Color color_ground;
|
sf::Color color_ground;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Level(const std::string &map_file_name = default_map_file_name);
|
Level(const std::string &path = default_file_path);
|
||||||
|
|
||||||
/// Number of map rows
|
/// Number of map rows
|
||||||
size_t rows() const;
|
size_t rows() const;
|
||||||
|
|
|
@ -6,6 +6,7 @@ CONFIG -= qt
|
||||||
QMAKE_CXXFLAGS = -Wall -Werror -Wextra -Wpedantic -Wconversion -std=c++17 -O0 -g
|
QMAKE_CXXFLAGS = -Wall -Werror -Wextra -Wpedantic -Wconversion -std=c++17 -O0 -g
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
audio.cpp \
|
||||||
cell.cpp \
|
cell.cpp \
|
||||||
entity.cpp \
|
entity.cpp \
|
||||||
game.cpp \
|
game.cpp \
|
||||||
|
@ -15,6 +16,7 @@ SOURCES += \
|
||||||
renderer.cpp
|
renderer.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
audio.h \
|
||||||
cell.h \
|
cell.h \
|
||||||
entity.h \
|
entity.h \
|
||||||
game.h \
|
game.h \
|
||||||
|
@ -25,4 +27,4 @@ HEADERS += \
|
||||||
# Only to highlight syntax when I am on Windows
|
# Only to highlight syntax when I am on Windows
|
||||||
win32:INCLUDEPATH += d:\SFML-2.5.1\include
|
win32:INCLUDEPATH += d:\SFML-2.5.1\include
|
||||||
|
|
||||||
LIBS += -lsfml-graphics -lsfml-window -lsfml-system
|
LIBS += -lsfml-graphics -lsfml-audio -lsfml-window -lsfml-system
|
||||||
|
|
Loading…
Reference in New Issue