ADD: PlaySound when rolling dice
This commit is contained in:
parent
89435a66a4
commit
a5643d794c
@ -243,6 +243,9 @@ add_library(Engine STATIC
|
||||
engine/src/core/inputsOutputs/context/InputContext.h
|
||||
engine/src/layer/SceneManager.cpp
|
||||
engine/src/layer/SceneManager.h
|
||||
engine/src/core/events/EventBus.cpp
|
||||
engine/src/core/events/EventBus.h
|
||||
engine/src/core/audio/ecs/PlaySoundComponent.h
|
||||
)
|
||||
target_include_directories(Engine PUBLIC engine/src ${dr_libs_SOURCE_DIR})
|
||||
target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui spdlog::spdlog tinyobjloader stb_image OpenAL::OpenAL)
|
||||
@ -280,6 +283,9 @@ target_link_libraries(GameLib PUBLIC Engine)
|
||||
add_executable(ColorRace
|
||||
game/src/main.cpp
|
||||
engine/src/core/animation/components/BlockingAnimationComponent.h
|
||||
engine/src/core/audio/ecs/AudioSystem.cpp
|
||||
engine/src/core/audio/ecs/AudioSystem.h
|
||||
engine/src/core/audio/ecs/BlockingSoundComponent.h
|
||||
)
|
||||
|
||||
target_link_libraries(ColorRace PRIVATE
|
||||
|
||||
Binary file not shown.
35
engine/src/core/audio/ecs/AudioSystem.cpp
Normal file
35
engine/src/core/audio/ecs/AudioSystem.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// Created by sebastian on 05.08.26.
|
||||
//
|
||||
|
||||
#include "AudioSystem.h"
|
||||
|
||||
#include "BlockingSoundComponent.h"
|
||||
#include "PlaySoundComponent.h"
|
||||
#include "core/audio/SoundSource.h"
|
||||
|
||||
void engine::audio::AudioSystem::update(float deltaTime) const {
|
||||
std::vector<Entity> toRemove;
|
||||
|
||||
for (auto& [entity, playSound] : m_registry.getPool<PlaySoundComponent>()) {
|
||||
auto& source = m_registry.getComponent<SoundSource>(entity);
|
||||
if (!playSound.started) {
|
||||
source.setBuffer(*playSound.soundBuffer);
|
||||
source.setGain(playSound.gain);
|
||||
source.play();
|
||||
playSound.started = true;
|
||||
} else if (!source.isPlaying()) {
|
||||
if (playSound.onFinished) {
|
||||
playSound.onFinished();
|
||||
}
|
||||
toRemove.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto entity : toRemove) {
|
||||
m_registry.removeComponent<PlaySoundComponent>(entity);
|
||||
if (m_registry.hasComponent<BlockingSoundComponent>(entity)) {
|
||||
m_registry.removeComponent<BlockingSoundComponent>(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
engine/src/core/audio/ecs/AudioSystem.h
Normal file
20
engine/src/core/audio/ecs/AudioSystem.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by sebastian on 05.08.26.
|
||||
//
|
||||
|
||||
#ifndef COLORRACE_AUDIOSYSTEM_H
|
||||
#define COLORRACE_AUDIOSYSTEM_H
|
||||
#include "ecs/EntityRegistry.h"
|
||||
|
||||
|
||||
namespace engine::audio {
|
||||
class AudioSystem {
|
||||
public:
|
||||
explicit AudioSystem(EntityRegistry& registry) : m_registry(registry) {}
|
||||
void update(float deltaTime) const;
|
||||
private:
|
||||
EntityRegistry& m_registry;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COLORRACE_AUDIOSYSTEM_H
|
||||
10
engine/src/core/audio/ecs/BlockingSoundComponent.h
Normal file
10
engine/src/core/audio/ecs/BlockingSoundComponent.h
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by sebastian on 05.08.26.
|
||||
//
|
||||
|
||||
#ifndef COLORRACE_BLOCKINGSOUNDCOMPONENT_H
|
||||
#define COLORRACE_BLOCKINGSOUNDCOMPONENT_H
|
||||
namespace engine::audio {
|
||||
struct BlockingSoundComponent {};
|
||||
}
|
||||
#endif //COLORRACE_BLOCKINGSOUNDCOMPONENT_H
|
||||
22
engine/src/core/audio/ecs/PlaySoundComponent.h
Normal file
22
engine/src/core/audio/ecs/PlaySoundComponent.h
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by sebastian on 05.08.26.
|
||||
//
|
||||
|
||||
#ifndef COLORRACE_PLAYSOUNDCOMPONENT_H
|
||||
#define COLORRACE_PLAYSOUNDCOMPONENT_H
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "../SoundBuffer.h"
|
||||
|
||||
namespace engine::audio {
|
||||
struct PlaySoundComponent {
|
||||
std::shared_ptr<SoundBuffer> soundBuffer;
|
||||
float gain = 1.f;
|
||||
bool started = false;
|
||||
bool blocking = false;
|
||||
std::function<void()> onFinished;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //COLORRACE_PLAYSOUNDCOMPONENT_H
|
||||
8
engine/src/core/events/EventBus.cpp
Normal file
8
engine/src/core/events/EventBus.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by sebastian on 05.08.26.
|
||||
//
|
||||
|
||||
#include "EventBus.h"
|
||||
|
||||
namespace engine {
|
||||
} // engine
|
||||
29
engine/src/core/events/EventBus.h
Normal file
29
engine/src/core/events/EventBus.h
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// Created by sebastian on 05.08.26.
|
||||
//
|
||||
|
||||
#ifndef COLORRACE_EVENTBUS_H
|
||||
#define COLORRACE_EVENTBUS_H
|
||||
#include <functional>
|
||||
|
||||
namespace engine {
|
||||
template<typename Event>
|
||||
class EventBus {
|
||||
public:
|
||||
using Handler = std::function<void(Event&)>;
|
||||
|
||||
void subscribe(Handler handler) {
|
||||
m_handlers.push_back(handler);
|
||||
}
|
||||
|
||||
void publish(Event& event) const {
|
||||
for (const auto& handler : m_handlers) {
|
||||
handler(event);
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::vector<Handler> m_handlers;
|
||||
};
|
||||
} // engine
|
||||
|
||||
#endif //COLORRACE_EVENTBUS_H
|
||||
@ -8,6 +8,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Layer.h"
|
||||
#include "core/events/EventBus.h"
|
||||
#include "loader/assets/AssetManager.h"
|
||||
#include "loader/assets/AssetRequests.h"
|
||||
#include "loader/assets/LoadedAssets.h"
|
||||
|
||||
@ -4,25 +4,34 @@
|
||||
|
||||
#include "AudioLayer.h"
|
||||
|
||||
#include "../../engine/src/core/audio/ecs/PlaySoundComponent.h"
|
||||
#include "core/audio/ecs/BlockingSoundComponent.h"
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
void ludo::AudioLayer::onUpdate(float deltaTime) {
|
||||
Layer::onUpdate(deltaTime);
|
||||
if (getKeyboard().keyPressEvent(GLFW_KEY_P)) {
|
||||
for (auto& soundSource : soundSources) {
|
||||
soundSource.play();
|
||||
}
|
||||
}
|
||||
|
||||
m_audioSystem.update(deltaTime);
|
||||
|
||||
}
|
||||
|
||||
void ludo::AudioLayer::onAttachImpl() {
|
||||
Layer::onAttachImpl();
|
||||
auto rollingDiceSoundBufffer = m_assetManager.getSound("rolling_dice");
|
||||
|
||||
auto rollingDiceSoundSource = engine::audio::SoundSource();
|
||||
rollingDiceSoundSource.setBuffer(*rollingDiceSoundBufffer);
|
||||
rollingDiceSoundSource.setPosition(0.0f, 0.0f, 0.0f);
|
||||
rollingDiceSoundSource.setGain(1.0f);
|
||||
auto rollingDiceSoundBuffer = m_assetManager.getSound("rolling_dice");
|
||||
m_diceSoundEntity = m_registry.createEntity();
|
||||
m_registry.addComponent<engine::audio::SoundSource>(m_diceSoundEntity, engine::audio::SoundSource());
|
||||
|
||||
soundSources.push_back(std::move(rollingDiceSoundSource));
|
||||
m_eventBus.subscribe([this, rollingDiceSoundBuffer](const ludo::LudoEvent& event) {
|
||||
std::visit([this, rollingDiceSoundBuffer]<typename T>(const T& e) {
|
||||
if constexpr (std::is_same_v<T, ludo::DiceRolledEvent>) {
|
||||
engine::audio::PlaySoundComponent playSound;
|
||||
playSound.soundBuffer = rollingDiceSoundBuffer;
|
||||
playSound.gain = 1.0f;
|
||||
playSound.blocking = true;
|
||||
m_registry.addComponent<engine::audio::PlaySoundComponent>(m_diceSoundEntity, playSound);
|
||||
m_registry.addComponent<engine::audio::BlockingSoundComponent>(m_diceSoundEntity, engine::audio::BlockingSoundComponent());
|
||||
}
|
||||
}, event);
|
||||
});
|
||||
}
|
||||
|
||||
@ -4,15 +4,24 @@
|
||||
|
||||
#ifndef COLORRACE_AUDIOLAYER_H
|
||||
#define COLORRACE_AUDIOLAYER_H
|
||||
#include <utility>
|
||||
|
||||
#include "core/audio/SoundSource.h"
|
||||
#include "core/audio/ecs/AudioSystem.h"
|
||||
#include "core/events/EventBus.h"
|
||||
#include "layer/Layer.h"
|
||||
#include "loader/assets/AssetManager.h"
|
||||
#include "ludo/LudoGameMode.h"
|
||||
|
||||
|
||||
|
||||
namespace ludo {
|
||||
class AudioLayer :public engine::Layer {
|
||||
public:
|
||||
AudioLayer(engine::AssetManager& assetManager, engine::Keyboard &keyboard, engine::Mouse &mouse): Layer(keyboard, mouse), m_assetManager(assetManager) {
|
||||
AudioLayer(engine::AssetManager& assetManager, engine::Keyboard &keyboard, engine::Mouse &mouse, std::shared_ptr<LudoGameMode> gameMode,
|
||||
engine::EntityRegistry& registry, engine::EventBus<LudoEvent>& eventBus)
|
||||
: Layer(keyboard, mouse), m_assetManager(assetManager), m_gameMode(std::move(gameMode)), m_registry(registry),
|
||||
m_eventBus(eventBus), m_audioSystem(m_registry) {
|
||||
}
|
||||
|
||||
void onUpdate(float deltaTime) override;
|
||||
@ -21,7 +30,11 @@ namespace ludo {
|
||||
void onAttachImpl() override;
|
||||
private:
|
||||
engine::AssetManager& m_assetManager;
|
||||
std::vector<engine::audio::SoundSource> soundSources;
|
||||
std::shared_ptr<ludo::LudoGameMode> m_gameMode;
|
||||
engine::EntityRegistry& m_registry;
|
||||
engine::Entity m_diceSoundEntity;
|
||||
engine::EventBus<LudoEvent>& m_eventBus;
|
||||
engine::audio::AudioSystem m_audioSystem;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,8 @@
|
||||
|
||||
#include "core/animation/components/BlockingAnimationComponent.h"
|
||||
#include "core/audio/SoundSource.h"
|
||||
#include "core/audio/ecs/BlockingSoundComponent.h"
|
||||
#include "core/audio/ecs/PlaySoundComponent.h"
|
||||
#include "GLFW/glfw3.h"
|
||||
using namespace engine;
|
||||
void GameLayer::onAttachImpl() {
|
||||
@ -56,15 +58,19 @@ void GameLayer::renderHud() {
|
||||
|
||||
}
|
||||
|
||||
bool GameLayer::isAnimationBlocking() {
|
||||
bool GameLayer::isAnimationBlocking() const {
|
||||
return m_entityRegistry.getPool<animation::BlockingAnimationComponent>().size() > 0;
|
||||
}
|
||||
|
||||
bool GameLayer::isSoundBlocking() const {
|
||||
return m_entityRegistry.getPool<audio::BlockingSoundComponent>().size() > 0;
|
||||
}
|
||||
|
||||
void GameLayer::onUpdate(float deltaTime) {
|
||||
Layer::onUpdate(deltaTime);
|
||||
m_cameraController->update(getKeyboard(), *m_camera, deltaTime);
|
||||
m_animationSystem.update(deltaTime);
|
||||
if (isAnimationBlocking()) return;
|
||||
if (isAnimationBlocking() || isSoundBlocking()) return;
|
||||
|
||||
for (auto& ai : aiControllers) {
|
||||
ai.update(deltaTime);
|
||||
|
||||
@ -66,8 +66,9 @@ private:
|
||||
|
||||
|
||||
void renderHud();
|
||||
bool isAnimationBlocking();
|
||||
bool isAnimationBlocking() const;
|
||||
|
||||
bool isSoundBlocking() const;
|
||||
};
|
||||
|
||||
#endif //COLORRACE_GAMELAYER_H
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
GameScene::GameScene(engine::InputContextStack& inputStack, engine::Keyboard& keyboard, engine::Mouse& mouse) : Scene(inputStack, keyboard, mouse), m_camera(std::make_unique<engine::Camera>()) {
|
||||
m_pointLight = std::make_shared<engine::PointLight>(glm::vec3(.0f, 10.f, -5.0f), glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
const std::vector<unsigned int> players = {0,1,2,3};
|
||||
m_gameMode = std::make_shared<ludo::LudoGameMode>(players);
|
||||
m_gameMode = std::make_shared<ludo::LudoGameMode>(m_eventBus, players);
|
||||
}
|
||||
|
||||
void GameScene::onEnter() {
|
||||
@ -39,7 +39,7 @@ void GameScene::onEnter() {
|
||||
pieceModels["Green"] = assetManager->getModel("pawn_green");
|
||||
pieceModels["Yellow"] = assetManager->getModel("pawn_yellow");
|
||||
|
||||
addLayer(std::make_unique<ludo::AudioLayer>(*assetManager, m_keyboard, m_mouse));
|
||||
addLayer(std::make_unique<ludo::AudioLayer>(*assetManager, m_keyboard, m_mouse, m_gameMode, entityRegistry, m_eventBus));
|
||||
addLayer(std::make_unique<engine::DebugLayer>(*m_camera, entityRegistry, m_keyboard, m_mouse, engine::SphereFactory::createUVSphere(1.0f)));
|
||||
addLayer(std::make_unique<GameLayer>(m_gameMode, entityRegistry, m_camera, m_pointLight, m_keyboard, m_mouse, assetManager->getModel("gameboard"), pieceModels));
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#define COLORRACE_GAMESCENE_H
|
||||
#include "layer/Scene.h"
|
||||
#include "ludo/LudoGameMode.h"
|
||||
|
||||
#include "renderer/entities/PointLight.h"
|
||||
|
||||
|
||||
@ -15,10 +16,13 @@ public:
|
||||
void onEnter() override;
|
||||
void onExit() override;
|
||||
std::vector<engine::AssetRequest> getRequiredAssets() const override;
|
||||
engine::EventBus<ludo::LudoEvent>& getEventBus() { return m_eventBus; } //Todo: Maybe introduce virtual base Event class to move this into engine
|
||||
private:
|
||||
std::shared_ptr<engine::Camera> m_camera;
|
||||
std::shared_ptr<engine::PointLight> m_pointLight;
|
||||
std::shared_ptr<ludo::LudoGameMode> m_gameMode;
|
||||
|
||||
engine::EventBus<ludo::LudoEvent> m_eventBus;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -89,12 +89,12 @@ ludo::LudoGameMode::MoveResult ludo::LudoGameMode::movePieceInternal(int pieceIn
|
||||
|
||||
void ludo::LudoGameMode::autoReleasePiece(int pieceIndex) {
|
||||
auto result = movePieceInternal(pieceIndex, m_gameState.getDiceValue());
|
||||
m_pendingEvents.emplace_back(PieceMovedEvent::create(pieceIndex, result.fromPosition, result.toPosition, result.captured, result.startState, result.targetState));
|
||||
publishEvent(PieceMovedEvent::create(pieceIndex, result.fromPosition, result.toPosition, result.captured, result.startState, result.targetState));
|
||||
if (result.captured) {
|
||||
//Todo: Determine real toPosition Index dependent on home belegung
|
||||
std::vector<int> freeHomePositions = m_gameState.getFreeHomePositions(m_gameState.getColorOfPieceIndex(result.capturedPieceIndex));
|
||||
const int smallestFreeHomePosition = *std::ranges::min_element(freeHomePositions);
|
||||
m_pendingEvents.emplace_back(PieceMovedEvent::create(result.capturedPieceIndex, result.fromPosition, smallestFreeHomePosition, result.captured, result.startState, result.targetState));
|
||||
publishEvent(PieceMovedEvent::create(result.capturedPieceIndex, result.fromPosition, smallestFreeHomePosition, result.captured, result.startState, result.targetState));
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ void ludo::LudoGameMode::handle(const RollDiceCommand &command) {
|
||||
if (!isCurrentPlayer(command.player) || m_gameState.m_phase != TurnPhase::AwaitingRoll) return;
|
||||
|
||||
m_gameState.m_diceValue = rollDice();
|
||||
m_pendingEvents.emplace_back(DiceRolledEvent(command.player, m_gameState.m_diceValue));
|
||||
publishEvent(DiceRolledEvent(command.player, m_gameState.m_diceValue));
|
||||
|
||||
if (m_gameState.m_diceValue == 6) {
|
||||
if (auto homeIndex = findLowestHomeSlotPiece(getColorOf(command.player))) {
|
||||
@ -147,10 +147,10 @@ void ludo::LudoGameMode::handle(const MovePieceCommand &command) {
|
||||
spdlog::info("MovePieceCommand akzeptiert: pieceIndex={}", command.pieceIndex);
|
||||
|
||||
auto result = movePieceInternal(command.pieceIndex, m_gameState.m_diceValue);
|
||||
m_pendingEvents.emplace_back(PieceMovedEvent{command.pieceIndex, result.fromPosition, result.toPosition, result.captured, result.targetState, result.startState});
|
||||
publishEvent(PieceMovedEvent{command.pieceIndex, result.fromPosition, result.toPosition, result.captured, result.targetState, result.startState});
|
||||
if (result.captured) {
|
||||
spdlog::info("MovePieceCommand: gegnerische Figur auf {} geworfen", result.toPosition);
|
||||
m_pendingEvents.emplace_back(PieceMovedEvent{result.capturedPieceIndex, result.toPosition, -1, false});
|
||||
publishEvent(PieceMovedEvent{result.capturedPieceIndex, result.toPosition, -1, false});
|
||||
}
|
||||
finishTurn();
|
||||
}
|
||||
@ -164,7 +164,7 @@ void ludo::LudoGameMode::finishTurn() {
|
||||
|
||||
endTurn(extraTurn);
|
||||
m_gameState.m_phase = TurnPhase::AwaitingRoll;
|
||||
m_pendingEvents.emplace_back(TurnChangedEvent{getCurrentPlayer()});
|
||||
publishEvent(TurnChangedEvent{getCurrentPlayer()});
|
||||
}
|
||||
|
||||
std::vector<int> ludo::LudoGameMode::getMoveablePieceIndices(PlayerColor color, int diceValue) const {
|
||||
@ -223,6 +223,11 @@ bool ludo::LudoGameMode::isBlockedByOwnPiece(PlayerColor owner, PieceState state
|
||||
return false;
|
||||
}
|
||||
|
||||
void ludo::LudoGameMode::publishEvent(LudoEvent event) {
|
||||
m_pendingEvents.push_back(event);
|
||||
m_eventBus.publish(event);
|
||||
}
|
||||
|
||||
namespace {
|
||||
int stateOrder(ludo::PieceState state) {
|
||||
switch (state) {
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "DiceSource.h"
|
||||
#include "LudoGameState.h"
|
||||
#include "LudoTypes.h"
|
||||
#include "core/events/EventBus.h"
|
||||
#include "game/TurnBasedGameMode.h"
|
||||
|
||||
namespace ludo {
|
||||
@ -30,8 +31,8 @@ namespace ludo {
|
||||
|
||||
class LudoGameMode: public engine::TurnBasedGameMode<LudoCommand, LudoEvent, LudoGameState> {
|
||||
public:
|
||||
explicit LudoGameMode(std::vector<engine::PlayerID> players, std::optional<unsigned int> seed = std::nullopt) : TurnBasedGameMode(std::move(players)),
|
||||
m_diceSource(std::make_unique<RandomDiceSource>()), m_gameState(getPlayerOrder()) {}
|
||||
explicit LudoGameMode(engine::EventBus<LudoEvent>& eventBus, std::vector<engine::PlayerID> players, std::optional<unsigned int> seed = std::nullopt) : TurnBasedGameMode(std::move(players)),
|
||||
m_diceSource(std::make_unique<RandomDiceSource>()), m_gameState(getPlayerOrder()), m_eventBus(eventBus) {}
|
||||
void sendCommand(const std::variant<MovePieceCommand, RollDiceCommand> &command) override;
|
||||
std::vector<LudoEvent> pollEvents() override;
|
||||
|
||||
@ -46,6 +47,7 @@ namespace ludo {
|
||||
|
||||
void setDiceSource(std::unique_ptr<IDiceSource> diceSource) { m_diceSource = std::move(diceSource); }
|
||||
private:
|
||||
engine::EventBus<LudoEvent>& m_eventBus;
|
||||
struct MoveResult {
|
||||
int fromPosition = 0;
|
||||
int toPosition = 0;
|
||||
@ -81,6 +83,7 @@ namespace ludo {
|
||||
|
||||
[[nodiscard]] bool isBlockedByOwnPiece(PlayerColor owner, PieceState state, int position) const;
|
||||
|
||||
void publishEvent(LudoEvent event);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user