audio, sfx and bgm classes; filesystem path added as type to json lib
This commit is contained in:
parent
be360b8a47
commit
013f8279d4
|
@ -13,11 +13,15 @@
|
|||
screen resolution, debug display, loading wheel animation, shadowed sprite,
|
||||
separate update and draw, sprite movement cage, multiple windows, multiple
|
||||
renderers, node children list, node animations list, copy constructor for all
|
||||
base classes, private and public class members, pixel class iterator, sprite
|
||||
movement history, input history, use seconds instead of milliseconds, store
|
||||
a node's animations in list, frame object for sprite class, inline short
|
||||
functions, add box2d to library, load in separate thread and display progress,
|
||||
add anchor to box class
|
||||
base classes (esp. sprite, audio), private and public class members, pixel
|
||||
class iterator, sprite movement history, input history, use seconds instead of
|
||||
milliseconds, store a node's animations in list, frame object for sprite
|
||||
class, inline short functions, add box2d to library, load in separate thread
|
||||
and display progress, add anchor to box class, add comments to code, generate
|
||||
documentation from comments, get resource function, automatically update
|
||||
animations, add arguments list to animation call, queue multiple calls to
|
||||
animation, print list of chunk and music decoders available, allow nodes that
|
||||
aren't connected to root
|
||||
|
||||
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
|
||||
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
#include "SDL.h"
|
||||
|
||||
#include "Box.hpp"
|
||||
#include "Configuration.hpp"
|
||||
#include "Display.hpp"
|
||||
#include "Audio.hpp"
|
||||
|
||||
BGM::BGM(Node* parent) : Node(parent) {}
|
||||
|
||||
BGM::BGM() : BGM(nullptr) {}
|
||||
|
||||
BGM::BGM(Node* parent, const fs::path& path) : BGM(parent)
|
||||
{
|
||||
load_music(path);
|
||||
}
|
||||
|
||||
BGM::BGM(const fs::path& path) : BGM(nullptr, path) {}
|
||||
|
||||
void BGM::load_music(const fs::path& path)
|
||||
{
|
||||
music = Mix_LoadMUS(path.c_str());
|
||||
}
|
||||
|
||||
void BGM::set_volume(float v)
|
||||
{
|
||||
volume = v;
|
||||
}
|
||||
|
||||
void BGM::play(int loops)
|
||||
{
|
||||
Mix_VolumeMusic(std::round(volume * 127));
|
||||
Mix_PlayMusic(music, loops);
|
||||
}
|
||||
|
||||
BGM::~BGM()
|
||||
{
|
||||
Mix_FreeMusic(music);
|
||||
}
|
||||
|
||||
SoundEffect::SoundEffect(Node* parent) : Node(parent) {}
|
||||
|
||||
SoundEffect::SoundEffect() : SoundEffect(nullptr) {}
|
||||
|
||||
SoundEffect::SoundEffect(Node* parent, const fs::path& path) : SoundEffect(parent)
|
||||
{
|
||||
load_chunk(path);
|
||||
}
|
||||
|
||||
SoundEffect::SoundEffect(const fs::path& path) : SoundEffect(nullptr, path) {}
|
||||
|
||||
void SoundEffect::load_chunk(const fs::path& path)
|
||||
{
|
||||
chunk = Mix_LoadWAV(path.c_str());
|
||||
Mix_VolumeChunk(chunk, std::round(volume * 127));
|
||||
}
|
||||
|
||||
void SoundEffect::play(float location)
|
||||
{
|
||||
play();
|
||||
Box window_box = get_window_box();
|
||||
location = std::clamp(location, window_box.get_left(), window_box.get_right());
|
||||
float location_relative = (location - window_box.get_left()) / window_box.get_w();
|
||||
int angle = 270 - location_relative * 180;
|
||||
Mix_SetPosition(channel, angle, 0);
|
||||
}
|
||||
|
||||
void SoundEffect::play()
|
||||
{
|
||||
channel = Mix_PlayChannel(-1, chunk, loops);
|
||||
}
|
||||
|
||||
void SoundEffect::play_after(float delay)
|
||||
{
|
||||
play_animation.play_once(delay);
|
||||
}
|
||||
|
||||
void SoundEffect::set_volume(float v)
|
||||
{
|
||||
volume = v;
|
||||
Mix_VolumeChunk(chunk, std::round(volume * 127));
|
||||
}
|
||||
|
||||
void SoundEffect::set_loop_count(int count)
|
||||
{
|
||||
loops = count;
|
||||
}
|
||||
|
||||
void SoundEffect::set_loop_forever()
|
||||
{
|
||||
loops = -1;
|
||||
}
|
||||
|
||||
bool SoundEffect::is_playing(bool include_delay)
|
||||
{
|
||||
if (include_delay)
|
||||
{
|
||||
if (play_animation.is_playing())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int channel_ii = 0; channel_ii < Mix_GroupAvailable(-1); channel_ii++)
|
||||
{
|
||||
if (Mix_GetChunk(channel_ii) == chunk)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoundEffect::update()
|
||||
{
|
||||
play_animation.update();
|
||||
}
|
||||
|
||||
SoundEffect::~SoundEffect()
|
||||
{
|
||||
Mix_FreeChunk(chunk);
|
||||
}
|
||||
|
||||
Audio::Audio(Node* parent) : Node(parent) {}
|
||||
|
||||
void Audio::load_sfx()
|
||||
{
|
||||
load_directory(get_configuration()["audio"]["default-sfx-root"], sfx, this);
|
||||
}
|
||||
|
||||
void Audio::load_bgm()
|
||||
{
|
||||
load_directory(get_configuration()["audio"]["default-bgm-root"], bgm, this);
|
||||
}
|
||||
|
||||
void Audio::update()
|
||||
{
|
||||
for (auto& [name, sound_effect] : sfx)
|
||||
{
|
||||
sound_effect.update();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef Audio_h_
|
||||
#define Audio_h_
|
||||
|
||||
#include <regex>
|
||||
#include <map>
|
||||
|
||||
#include "SDL_mixer.h"
|
||||
#include "filesystem.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "Animation.hpp"
|
||||
#include "extension.hpp"
|
||||
|
||||
struct BGM : Node
|
||||
{
|
||||
|
||||
Mix_Music* music;
|
||||
float volume = 1.0f;
|
||||
|
||||
BGM();
|
||||
BGM(Node*);
|
||||
BGM(Node*, const fs::path&);
|
||||
BGM(const fs::path&);
|
||||
void load_music(const fs::path&);
|
||||
void set_volume(float);
|
||||
void play(int = -1);
|
||||
~BGM();
|
||||
|
||||
};
|
||||
|
||||
struct SoundEffect : Node
|
||||
{
|
||||
|
||||
Mix_Chunk* chunk = nullptr;
|
||||
int channel, loops = 0;
|
||||
float volume = 1.0f;
|
||||
Animation play_animation = Animation(&SoundEffect::play, this);
|
||||
|
||||
SoundEffect(Node*);
|
||||
SoundEffect();
|
||||
SoundEffect(Node*, const fs::path&);
|
||||
SoundEffect(const fs::path&);
|
||||
void load_chunk(const fs::path&);
|
||||
void play(float);
|
||||
void play();
|
||||
void play_after(float);
|
||||
void set_volume(float);
|
||||
void set_loop_count(int);
|
||||
void set_loop_forever();
|
||||
bool is_playing(bool = false);
|
||||
void update();
|
||||
~SoundEffect();
|
||||
|
||||
};
|
||||
|
||||
struct Audio : Node
|
||||
{
|
||||
|
||||
std::map<std::string, SoundEffect> sfx;
|
||||
std::map<std::string, BGM> bgm;
|
||||
|
||||
Audio(Node*);
|
||||
void load_sfx();
|
||||
void load_bgm();
|
||||
void update();
|
||||
|
||||
template <typename T>
|
||||
void load_directory(const fs::path& root, std::map<std::string, T>& storage, Node* parent = nullptr)
|
||||
{
|
||||
SDL_Log("looking for audio files in %s", root.c_str());
|
||||
if (fs::exists(root))
|
||||
{
|
||||
for (const fs::path& path : sfw::glob(root / ".*"))
|
||||
{
|
||||
std::regex pattern("([^.]+).*$");
|
||||
std::smatch match;
|
||||
std::string basename = path.filename();
|
||||
if (std::regex_match(basename, match, pattern))
|
||||
{
|
||||
std::string key = match[1].str();
|
||||
SDL_Log("loading %s as %s", path.c_str(), key.c_str());
|
||||
storage.try_emplace(key, parent, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -51,6 +51,10 @@ void Configuration::set_defaults()
|
|||
{"render-test-spacing", 2},
|
||||
{"render driver", "opengl"}
|
||||
};
|
||||
sys_config["audio"] = {
|
||||
{"default-sfx-root", "resource/sfx"},
|
||||
{"default-bgm-root", "resource/bgm"}
|
||||
};
|
||||
sys_config["recording"] = {
|
||||
{"enabled", false},
|
||||
{"screenshot-prefix", "screenshot-"},
|
||||
|
|
|
@ -24,4 +24,39 @@ struct Configuration : Node
|
|||
|
||||
};
|
||||
|
||||
namespace glm
|
||||
{
|
||||
template <typename T>
|
||||
void to_json(nlohmann::json& j, const vec<2, T, defaultp>& v)
|
||||
{
|
||||
j = nlohmann::json{v.x, v.y};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void from_json(const nlohmann::json& j, vec<2, T, defaultp>& v)
|
||||
{
|
||||
j.at(0).get_to(v.x);
|
||||
j.at(1).get_to(v.y);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
namespace std::experimental::filesystem
|
||||
#else
|
||||
namespace std::filesystem
|
||||
#endif
|
||||
{
|
||||
template <typename T>
|
||||
void to_json(nlohmann::json& j, const path& p)
|
||||
{
|
||||
j = nlohmann::json{p};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void from_json(const nlohmann::json& j, path& p)
|
||||
{
|
||||
j.at(0).get_to(p);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
10
src/Game.cpp
10
src/Game.cpp
|
@ -145,6 +145,8 @@ Game::Game()
|
|||
SDL_Log("Found audio capture device %i: %s", ii,
|
||||
SDL_GetAudioDeviceName(ii, SDL_TRUE));
|
||||
}
|
||||
audio.load_sfx();
|
||||
audio.load_bgm();
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
SDL_Log("big endian");
|
||||
#else
|
||||
|
@ -511,6 +513,11 @@ Input& Game::get_input()
|
|||
return input;
|
||||
}
|
||||
|
||||
Audio& Game::get_audio()
|
||||
{
|
||||
return audio;
|
||||
}
|
||||
|
||||
glm::vec2 Game::weight(glm::vec2 motion)
|
||||
{
|
||||
return {weight(motion.x), weight(motion.y)};
|
||||
|
@ -556,7 +563,8 @@ void Game::frame(float ticks)
|
|||
recorder.update();
|
||||
}
|
||||
delegate.dispatch();
|
||||
get_root()->input.unsuppress_animation.update();
|
||||
audio.update();
|
||||
input.unsuppress_animation.update();
|
||||
update();
|
||||
framerate_indicator.update();
|
||||
if (!is_gl_context)
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "Recorder.hpp"
|
||||
#include "extension.hpp"
|
||||
#include "Sprite.hpp"
|
||||
#include "Audio.hpp"
|
||||
|
||||
struct FramerateIndicator : Sprite
|
||||
{
|
||||
|
@ -60,6 +61,7 @@ struct Game : Node
|
|||
Display display = Display(this);
|
||||
Recorder recorder = Recorder(this);
|
||||
Input input = Input(this);
|
||||
Audio audio = Audio(this);
|
||||
std::vector<float> frame_length_history;
|
||||
TTF_Font* bp_mono_font = NULL;
|
||||
FramerateIndicator framerate_indicator = FramerateIndicator(this);
|
||||
|
@ -84,6 +86,7 @@ struct Game : Node
|
|||
SDL_Renderer* get_renderer();
|
||||
const Input& get_input() const;
|
||||
Input& get_input();
|
||||
Audio& get_audio();
|
||||
glm::vec2 weight(glm::vec2);
|
||||
void run();
|
||||
void frame(float);
|
||||
|
|
12
src/Node.cpp
12
src/Node.cpp
|
@ -4,9 +4,10 @@
|
|||
#include "Input.hpp"
|
||||
#include "Box.hpp"
|
||||
#include "Game.hpp"
|
||||
#include "Audio.hpp"
|
||||
#include "Node.hpp"
|
||||
|
||||
Node::Node() : Node(NULL) {}
|
||||
Node::Node() : Node(nullptr) {}
|
||||
|
||||
Node::Node(Node* parent) : parent(parent)
|
||||
{
|
||||
|
@ -79,6 +80,11 @@ Input& Node::get_input()
|
|||
return get_root()->get_input();
|
||||
}
|
||||
|
||||
Audio& Node::get_audio()
|
||||
{
|
||||
return get_root()->get_audio();
|
||||
}
|
||||
|
||||
const Game* Node::get_root() const
|
||||
{
|
||||
const Node* r = this;
|
||||
|
@ -117,10 +123,10 @@ void Node::unsuppress_input()
|
|||
void Node::print_branch()
|
||||
{
|
||||
Node* current = this;
|
||||
while (current != NULL)
|
||||
while (current != nullptr)
|
||||
{
|
||||
std::cout << current->get_class_name() << " @ " << current;
|
||||
if (current->parent != NULL)
|
||||
if (current->parent != nullptr)
|
||||
{
|
||||
std::cout << " -> ";
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ struct Delegate;
|
|||
struct Display;
|
||||
struct Input;
|
||||
struct Box;
|
||||
struct Audio;
|
||||
|
||||
struct Node
|
||||
{
|
||||
|
@ -41,6 +42,7 @@ struct Node
|
|||
SDL_Window* get_window();
|
||||
const Input& get_input() const;
|
||||
Input& get_input();
|
||||
Audio& get_audio();
|
||||
const Game* get_root() const;
|
||||
Box get_window_box();
|
||||
void suppress_input();
|
||||
|
|
|
@ -269,11 +269,11 @@ void Sprite::toggle_hidden()
|
|||
{
|
||||
if (is_hidden())
|
||||
{
|
||||
hide();
|
||||
unhide();
|
||||
}
|
||||
else
|
||||
{
|
||||
unhide();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,22 +168,6 @@ namespace sfw
|
|||
|
||||
}
|
||||
|
||||
namespace glm
|
||||
{
|
||||
template <typename T>
|
||||
void to_json(nlohmann::json& j, const vec<2, T, defaultp>& v)
|
||||
{
|
||||
j = nlohmann::json{{"x", v.x}, {"y", v.y}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void from_json(const nlohmann::json& j, vec<2, T, defaultp>& v)
|
||||
{
|
||||
j.at(0).get_to(v.x);
|
||||
j.at(1).get_to(v.y);
|
||||
}
|
||||
}
|
||||
|
||||
int SDL_SetRenderDrawColor(SDL_Renderer*, const Color&);
|
||||
int SDL_RenderFillRect(SDL_Renderer*, const Box&);
|
||||
int lineColor(SDL_Renderer*, const Segment&, const Color&, std::uint8_t = 1);
|
||||
|
|
Loading…
Reference in New Issue