explosion working

This commit is contained in:
HENRY Benjamin
2021-06-09 16:40:02 +02:00
41 changed files with 688 additions and 78 deletions
+10
View File
@@ -81,6 +81,15 @@ set(SOURCES
sources/Component/Animator/AnimatorComponent.hpp
sources/System/Animator/AnimatorSystem.cpp
sources/System/Animator/AnimatorSystem.hpp
sources/Component/Tag/TagComponent.hpp
sources/Component/Music/MusicComponent.cpp
sources/Component/Music/MusicComponent.hpp
sources/Component/Sound/SoundComponent.hpp
sources/Component/Sound/SoundComponent.cpp
sources/System/Sound/PlayerSoundManagerSystem.cpp
sources/System/Sound/PlayerSoundManagerSystem.hpp
sources/System/Music/MusicSystem.hpp
sources/System/Music/MusicSystem.cpp
)
add_executable(bomberman
sources/main.cpp
@@ -92,6 +101,7 @@ target_link_libraries(bomberman PUBLIC wal ray)
add_executable(unit_tests EXCLUDE_FROM_ALL
${SOURCES}
tests/CacheTest.cpp
tests/EntityTests.cpp
tests/MainTest.cpp
tests/EngineTests.cpp
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+8 -2
View File
@@ -10,8 +10,8 @@
RAY::Cache<::Music> RAY::Audio::Music::_musicsCache(LoadMusicStream, UnloadMusicStream);
RAY::Audio::Music::Music(const std::string &path):
_music(this->_musicsCache.fetch(path.c_str()))
RAY::Audio::Music::Music(const std::string &path, bool lonely):
_music(this->_musicsCache.fetch(path, lonely))
{
}
@@ -55,3 +55,9 @@ RAY::Audio::Music &RAY::Audio::Music::setPitch(float pitch)
SetMusicPitch(*_music, pitch);
return *this;
}
RAY::Audio::Music &RAY::Audio::Music::updateMusicStream(void)
{
UpdateMusicStream(*_music);
return *this;
}
+4 -1
View File
@@ -19,7 +19,8 @@ namespace RAY::Audio
public:
//! @brief Load Music stream from file
Music(const std::string &path);
//! @param lonely: should be set to true if the entity's loaded data must be independant from others
Music(const std::string &path, bool lonely = false);
//! @brief Default destructor
~Music() = default;
@@ -51,6 +52,8 @@ namespace RAY::Audio
// Set pitch for a Music (1.0 is base level)
Music &setPitch(float pitch) override;
Music &updateMusicStream(void);
private:
std::shared_ptr<::Music> _music;
+2 -2
View File
@@ -9,8 +9,8 @@
RAY::Cache<::Sound> RAY::Audio::Sound::_soundsCache(LoadSound, UnloadSound);
RAY::Audio::Sound::Sound(const std::string &path):
_sound(_soundsCache.fetch(path.c_str()))
RAY::Audio::Sound::Sound(const std::string &path, bool lonely):
_sound(_soundsCache.fetch(path, lonely))
{
}
+2 -1
View File
@@ -20,7 +20,8 @@ namespace RAY::Audio
public:
//! @brief Load Sound stream from file
Sound(const std::string &path);
//! @param lonely: should be set to true if the entity's loaded data must be independant from others
Sound(const std::string &path, bool lonely = false);
//! @brief Default destructor
~Sound() = default;
+2 -2
View File
@@ -12,9 +12,9 @@
namespace RAY {
Cache<::Image> Image::_imagesCache(LoadImage, UnloadImage);
Image::Image(const std::string &filename):
Image::Image(const std::string &filename, bool lonely):
Rectangle(Vector2(0, 0), Vector2(0, 0), WHITE),
_image(_imagesCache.fetch(filename))
_image(_imagesCache.fetch(filename, lonely))
{
this->_dimensions = Vector2(this->_image->width, this->_image->height);
}
+2 -1
View File
@@ -21,7 +21,8 @@ namespace RAY
public:
//! @brief Create an image, loading a file
//! @param filename: path to file to load
Image(const std::string &filename);
//! @param lonely: should be set to true if the entity's loaded data must be independant from others
Image(const std::string &filename, bool lonely = false);
//! @brief A default copy constructor
Image(const Image &image) = default;
+2 -2
View File
@@ -11,8 +11,8 @@ namespace RAY {
Cache<::Texture> Texture::_texturesCache(LoadTexture, UnloadTexture);
Texture::Texture(const std::string &filename):
_texture(_texturesCache.fetch(filename)),
Texture::Texture(const std::string &filename, bool lonely):
_texture(_texturesCache.fetch(filename, lonely)),
_resourcePath(filename)
{
}
+2 -1
View File
@@ -19,7 +19,8 @@ namespace RAY
public:
//! @brief Create an texture, loading a file
//! @param filename: path to file to load
Texture(const std::string &filename);
//! @param lonely: should be set to true if the entity's loaded data must be independant from others
Texture(const std::string &filename, bool lonely = false);
//! @brief A texture is copy constructable
Texture(const Texture &) = default;
+2 -2
View File
@@ -9,8 +9,8 @@
RAY::Cache<::Font> RAY::Font::_fontsCache(LoadFont, UnloadFont);
RAY::Font::Font(const std::string &filename):
_font(_fontsCache.fetch(filename))
RAY::Font::Font(const std::string &filename, bool lonely):
_font(_fontsCache.fetch(filename, lonely))
{
}
+2 -1
View File
@@ -19,7 +19,8 @@ namespace RAY
public:
//! @brief Create an font, loading a file
//! @param filename: path to file to load
Font(const std::string &filename);
//! @param lonely: should be set to true if the entity's loaded data must be independant from others
Font(const std::string &filename, bool lonely = false);
//! @brief A default copy constructor
Font(const Font &) = default;
+2 -2
View File
@@ -19,9 +19,9 @@ namespace RAY::Drawables::Drawables3D {
const RAY::Vector3 &scale,
const RAY::Vector3 &position,
const RAY::Vector3 &rotationAxis,
float rotationAngle)
float rotationAngle, bool lonely)
: ADrawable3D(position, WHITE),
_model(_modelsCache.fetch(filename)),
_model(_modelsCache.fetch(filename, lonely)),
_rotationAxis(rotationAxis),
_rotationAngle(rotationAngle),
_scale(scale)
+2 -1
View File
@@ -25,12 +25,13 @@ namespace RAY::Drawables::Drawables3D {
//! @brief Create an model, loading a file
//! @param filePath: path to file to load
//! @param lonely: should be set to true if the entity's loaded data must be independant from others
Model(const std::string &filePath,
std::optional<std::pair<MaterialType, std::string>> texture = std::nullopt,
const RAY::Vector3 &scale = RAY::Vector3(1, 1, 1),
const RAY::Vector3 &position = {0, 0, 0},
const RAY::Vector3 &rotationAxis = RAY::Vector3(0, 1, 0),
float rotationAngle = 0);
float rotationAngle = 0, bool lonely = false);
//! @brief Create an model, loading a file
//! @param mesh: mesh to load
+25 -9
View File
@@ -10,6 +10,10 @@
#include <unordered_map>
#include <functional>
#include <raylib.h>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
namespace RAY {
//! @brief A templated class used to cache ressources, indexed with a string
@@ -31,16 +35,28 @@ namespace RAY {
Cache &operator=(const Cache &) = default;
//! @param path path of the file
//! @param lonely: should be set to true if the loaded data must be held by no other active entites
//! @return a newly loaded ressource if it hasn't be previously loaded, or one from cache
std::shared_ptr<T>fetch(const std::string &path)
std::shared_ptr<T>fetch(const std::string &path, bool lonely = false)
{
if (this->_cache.find(path) == this->_cache.end())
this->_cache.emplace(path, std::shared_ptr<T>(
new T(this->_dataLoader(path.c_str())), [this](T *p) {
this->_dataUnloader(*p);
delete p;
}));
return _cache[path];
if (!this->_cache.contains(path))
this->_cache.emplace(path, std::vector<std::shared_ptr<T>>());
std::vector<std::shared_ptr<T>> &matchingDataVector = this->_cache.at(path);
if (matchingDataVector.size()) {
for (std::shared_ptr<T> &i: matchingDataVector) {
if (!lonely)
return i;
if (lonely && i.use_count() == 1)
return i;
}
}
matchingDataVector.push_back(std::shared_ptr<T>(
new T(this->_dataLoader(path.c_str())), [this](T *p) {
this->_dataUnloader(*p);
delete p;
}));
return matchingDataVector.back();
};
private:
//! @brief function to call to load data
@@ -50,7 +66,7 @@ namespace RAY {
std::function<void(T)> _dataUnloader;
//! @brief map storing shared ptr of caches
std::unordered_map<std::string, std::shared_ptr<T>> _cache;
std::unordered_map<std::string, std::vector<std::shared_ptr<T>>> _cache;
};
template<>
+2
View File
@@ -49,6 +49,7 @@ bool RAY::Window::open(void)
}
InitWindow(this->_dimensions.x, this->_dimensions.y, this->_title.c_str());
this->_isOpen = true;
InitAudioDevice();
return true;
}
@@ -60,6 +61,7 @@ bool RAY::Window::shouldClose(void) const
void RAY::Window::close(void)
{
CloseWindow();
CloseAudioDevice();
}
bool RAY::Window::isFocused(void) const
@@ -0,0 +1,65 @@
//
// Created by Tom Augier on 05/06/2021
//
#include <iostream>
#include "MusicComponent.hpp"
namespace BBM
{
float MusicComponent::volume = 0.75;
MusicComponent::MusicComponent(WAL::Entity &entity, const std::string &musicPath)
: WAL::Component(entity),
_musicPath(musicPath),
_music(RAY::Audio::Music(musicPath))
{
}
WAL::Component *MusicComponent::clone(WAL::Entity &entity) const
{
return new MusicComponent(entity, this->_musicPath);
}
void MusicComponent::playMusic(void)
{
if (!this->_music.isPlaying()) {
this->_music.play();
}
}
void MusicComponent::stopMusic(void)
{
if (this->_music.isPlaying())
this->_music.stop();
}
void MusicComponent::pauseMusic(void)
{
this->_music.pause();
}
void MusicComponent::setVolume(float &volumeUpdate)
{
if (volumeUpdate >= 0) {
this->volume = volumeUpdate;
this->_music.setVolume(this->volume);
}
}
void MusicComponent::setPitch(float &pitch)
{
this->_music.setPitch(pitch);
}
bool MusicComponent::isPlaying(void)
{
return (this->_music.isPlaying());
}
void MusicComponent::updateMusicStream(void)
{
this->_music.updateMusicStream();
}
} // namespace WAL
@@ -0,0 +1,55 @@
//
// Created by Tom Augier on 05/06/2021
//
#pragma once
#include "Component/Component.hpp"
#include <map>
#include "Audio/Music.hpp"
namespace BBM
{
//! @brief A basic Music component
class MusicComponent : public WAL::Component
{
public:
//! @brief start music
void playMusic();
//! @brief stop music
void stopMusic();
//! @brief put music on hold
void pauseMusic();
//! @brief set music volume
void setVolume(float &);
//! @brief set pitch volume
void setPitch(float &);
//! @brief is music playing
bool isPlaying(void);
//! @brief update music stream
void updateMusicStream(void);
//! @inherit
WAL::Component *clone(WAL::Entity &entity) const override;
//! @brief Create a new MusicComponent at a certain Music
explicit MusicComponent(WAL::Entity &entity, const std::string &musicPath);
//! @brief A Music component is copy constructable
MusicComponent(const MusicComponent &) = default;
//! @brief A default destructor
~MusicComponent() override = default;
//! @brief A Music component is not assignable
MusicComponent &operator=(const MusicComponent &) = delete;
//! @brief Volume of the muisc
static float volume;
private:
//! @brief music of this entity
RAY::Audio::Music _music;
//! @brief patht to the music assets
const std::string _musicPath;
};
} // namespace BBM
@@ -0,0 +1,91 @@
//
// Created by Tom Augier on 05/06/2021
//
#include <iostream>
#include <memory>
#include "SoundComponent.hpp"
namespace BBM
{
float SoundComponent::volume = 0.75;
SoundComponent::SoundComponent(WAL::Entity &entity,
const std::map<SoundComponent::SoundIndex, std::string> &soundPath)
: WAL::Component(entity),
_soundIndex(IDLE),
_soundPath(soundPath)
{
for (int i = 0; i <= DEATH; i++) {
this->_isSoundLoad[static_cast<SoundIndex>(i)] = false;
}
for (auto &soundPath : soundPath)
{
this->_isSoundLoad[soundPath.first] = true;
this->_soundList[soundPath.first] = std::make_unique<RAY::Audio::Sound>(soundPath.second);
}
}
WAL::Component *SoundComponent::clone(WAL::Entity &entity) const
{
return new SoundComponent(entity, this->_soundPath);
}
void SoundComponent::playSound()
{
if (!this->_isSoundLoad.at(this->_soundIndex))
return;
if (!this->_soundList[this->_soundIndex].get()->isPlaying())
this->_soundList[this->_soundIndex].get()->play();
}
void SoundComponent::stopSound()
{
if (!this->_isSoundLoad.at(this->_soundIndex))
return;
if (this->_soundList[this->_soundIndex].get()->isPlaying())
this->_soundList[this->_soundIndex].get()->stop();
}
void SoundComponent::pauseSound()
{
if (!this->_isSoundLoad.at(this->_soundIndex))
return;
this->_soundList[this->_soundIndex].get()->pause();
}
void SoundComponent::setVolume(float &volumeUpdate)
{
if (!this->_isSoundLoad.at(this->_soundIndex))
return;
if (volumeUpdate >= 0) {
this->volume = volumeUpdate;
this->_soundList[this->_soundIndex].get()->setVolume(this->volume);
}
}
void SoundComponent::setPitch(float &pitch)
{
if (!this->_isSoundLoad.at(this->_soundIndex))
return;
this->_soundList[this->_soundIndex].get()->setPitch(pitch);
}
bool SoundComponent::isPlaying()
{
if (!this->_isSoundLoad.at(this->_soundIndex))
return (false);
return (this->_soundList[this->_soundIndex].get()->isPlaying());
}
void SoundComponent::setIndex(SoundIndex index)
{
this->_soundIndex = index;
}
SoundComponent::SoundIndex SoundComponent::getIndex()
{
return (this->_soundIndex);
}
} // namespace WAL
@@ -0,0 +1,78 @@
//
// Created by Tom Augier on 05/06/2021
//
#pragma once
#include "Component/Component.hpp"
#include <map>
#include "Audio/Sound.hpp"
namespace BBM
{
//! @brief A basic Sound component
class SoundComponent : public WAL::Component
{
public:
//! @brief All sounds of the player
enum SoundIndex {
IDLE,
JUMP,
BOMB,
MOVE,
HURT,
THROW,
DEATH
};
//! @brief to set what sound should be played
void setIndex(SoundIndex index);
//! @brief to know which sound is selected
SoundIndex getIndex();
//! @brief start sound
void playSound();
//! @brief stop sound
void stopSound();
//! @brief put Sound on hold
void pauseSound();
//! @brief set Sound volume
void setVolume(float &);
//! @brief set pitch volume
void setPitch(float &);
//! @brief is Sound playing
bool isPlaying();
//! @inherit
WAL::Component *clone(WAL::Entity &entity) const override;
//! @brief Create a new SoundComponent at a certain Sound
explicit SoundComponent(WAL::Entity &entity, const std::map<SoundIndex, std::string> &);
//! @brief A Sound component is copy constructable
SoundComponent(const SoundComponent &) = default;
//! @brief A default destructor
~SoundComponent() override = default;
//! @brief A Sound component is not assignable
SoundComponent &operator=(const SoundComponent &) = delete;
//! @brief Volume of the sounds
static float volume;
private:
//! @brief Sounds of this entity
std::map<SoundIndex, std::shared_ptr<RAY::Audio::Sound>> _soundList;
//! @brief map to know if sound is loaded
std::map<SoundIndex, bool> _isSoundLoad;
//! @brief All sounds path
const std::map<SoundIndex, std::string> _soundPath;
//! SoundIndex
SoundIndex _soundIndex;
};
} // namespace BBM
+54
View File
@@ -0,0 +1,54 @@
//
// Created by Zoe Roux on 6/9/21.
//
#pragma once
#include <Component/Component.hpp>
#include <string_view>
namespace BBM
{
template<std::size_t I>
struct StringLiteral
{
public:
char value[I];
//! @brief Implicitly convert an array of char to a string literal.
constexpr StringLiteral(const char (&str)[I]) // NOLINT(google-explicit-constructor)
: value()
{
std::copy_n(str, I, value);
}
//! @brief A string literal is copy constructable.
constexpr StringLiteral(const StringLiteral &) = default;
//! @brief A default destructor
constexpr ~StringLiteral() = default;
//! @brief A string literal is assignable.
constexpr StringLiteral &operator=(const StringLiteral &) = default;
};
template <StringLiteral name>
class TagComponent : public WAL::Component
{
public:
Component *clone(WAL::Entity &entity) const override
{
return new TagComponent<name>(entity);
}
//! @brief Create a new empty tag component.
explicit TagComponent(WAL::Entity &entity)
: WAL::Component(entity)
{}
//! @brief A default copy constructor.
TagComponent(const TagComponent &) = default;
//! @brief A default destructor
~TagComponent() override = default;
//! @brief A tag component is not assignable.
TagComponent &operator=(const TagComponent &) = delete;
};
constexpr const char Blowable[] = "Blowable";
}
+20 -28
View File
@@ -6,7 +6,7 @@
#include "Component/Collision/CollisionComponent.hpp"
#include "System/Collision/CollisionSystem.hpp"
#include "Map.hpp"
#include <iostream>
#include <Component/Tag/TagComponent.hpp>
namespace RAY3D = RAY::Drawables::Drawables3D;
@@ -23,7 +23,7 @@ namespace BBM
if (collidedAxis & CollisionComponent::CollidedAxis::X)
mov->_velocity.x = 0;
if (collidedAxis & CollisionComponent::CollidedAxis::Y)
mov->_velocity.x = 0;
mov->_velocity.y = 0;
if (collidedAxis & CollisionComponent::CollidedAxis::Z)
mov->_velocity.z = 0;
}
@@ -56,6 +56,7 @@ namespace BBM
if (!(i % 2) && !(j % 2)) {
scene->addEntity("Unbreakable Wall")
.addComponent<PositionComponent>(i, 0, j)
.addComponent<TagComponent<Blowable>>()
.addComponent<CollisionComponent>(
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
&MapGenerator::wallCollide, 0.25, .75)
@@ -73,25 +74,28 @@ namespace BBM
scene->addEntity("Bottom Wall")
.addComponent<PositionComponent>(Vector3f((width + 1) / 2, 0, -1))
.addComponent<TagComponent<Blowable>>()
.addComponent<CollisionComponent>(
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
&MapGenerator::wallCollide, 0.25, .75)
&MapGenerator::wallCollide, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75))
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
RAY::Vector3(width + 3, 1, 1));
scene->addEntity("Upper Wall")
.addComponent<PositionComponent>(Vector3f((width + 1) / 2, 0, height + 1))
.addComponent<TagComponent<Blowable>>()
.addComponent<CollisionComponent>(
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
&MapGenerator::wallCollide, 0.25, .75)
&MapGenerator::wallCollide, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75))
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
RAY::Vector3(width + 3, 1, 1));
scene->addEntity("Left Wall")
.addComponent<PositionComponent>(Vector3f(width + 1, 0, height / 2))
.addComponent<TagComponent<Blowable>>()
.addComponent<CollisionComponent>(
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
&MapGenerator::wallCollide, 0.25, .75)
&MapGenerator::wallCollide, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1))
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
RAY::Vector3(1, 1, height + 1));
@@ -99,7 +103,7 @@ namespace BBM
.addComponent<PositionComponent>(Vector3f(-1, 0, height / 2))
.addComponent<CollisionComponent>(
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
&MapGenerator::wallCollide, 0.25, .75)
&MapGenerator::wallCollide, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1))
.addComponent<Drawable3DComponent, RAY3D::Model>(unbreakableObj,
std::make_pair(MAP_DIFFUSE, unbreakablePnj),
RAY::Vector3(1, 1, height + 1));
@@ -129,7 +133,6 @@ namespace BBM
{HOLE, &createHole},
{FLOOR, &createFloor},
{BUMPER, &createBumper},
{STAIRS, &createStairs},
{UPPERFLOOR, &createUpperFloor},
};
@@ -148,6 +151,7 @@ namespace BBM
scene->addEntity("Breakable Block")
.addComponent<PositionComponent>(coords)
.addComponent<TagComponent<Blowable>>()
.addComponent<HealthComponent>(1, &MapGenerator::wallDestroyed)
.addComponent<CollisionComponent>(
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
@@ -184,6 +188,7 @@ namespace BBM
scene->addEntity("Unbreakable Block")
.addComponent<PositionComponent>(coords)
.addComponent<TagComponent<Blowable>>()
.addComponent<CollisionComponent>(
WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
&MapGenerator::wallCollide, 0.25, .75)
@@ -231,17 +236,6 @@ namespace BBM
}); */
}
void MapGenerator::createStairs(Vector3f coords, std::shared_ptr<WAL::Scene> scene)
{
static const std::string stairsObj = stairsPath + objExtension;
static const std::string stairsPng = stairsPath + imageExtension;
scene->addEntity("Stairs Block")
.addComponent<PositionComponent>(coords)
//.addComponent<CollisionComponent>(1)
.addComponent<Drawable3DComponent, RAY3D::Model>(stairsObj, std::make_pair(MAP_DIFFUSE, stairsPng));
}
bool MapGenerator::isCloseToBlockType(std::map<std::tuple<int, int, int>, BlockType> map, int x, int y, int z,
BlockType blockType)
{
@@ -273,10 +267,10 @@ namespace BBM
map[std::make_tuple(i, 1, 0)] = map[std::make_tuple(i, 0, 0)];
map[std::make_tuple(i, 0, 0)] = UPPERFLOOR;
}
map[std::make_tuple(0, 0, height - 1)] = STAIRS;
map[std::make_tuple(0, 0, 1)] = STAIRS;
map[std::make_tuple(width, 0, height - 1)] = STAIRS;
map[std::make_tuple(width, 0, 1)] = STAIRS;
map[std::make_tuple(0, -1, height - 1)] = BUMPER;
map[std::make_tuple(0, -1, 1)] = BUMPER;
map[std::make_tuple(width, -1, height - 1)] = BUMPER;
map[std::make_tuple(width, -1, 1)] = BUMPER;
map[std::make_tuple(width / 2, -1, height - 1)] = BUMPER;
map[std::make_tuple(width / 2, -1, 1)] = BUMPER;
}
@@ -289,10 +283,10 @@ namespace BBM
map[std::make_tuple(i, 0, j)] = UPPERFLOOR;
}
}
map[std::make_tuple(width / 2 - width / 8, 0, height / 2 + height / 4 + 1)] = STAIRS;
map[std::make_tuple(width / 2 + width / 8, 0, height / 2 - height / 4 - 1)] = STAIRS;
map[std::make_tuple(width / 2 - width / 4 - 1, 0, height / 2 - height / 8)] = STAIRS;
map[std::make_tuple(width / 2 + width / 4 + 1, 0, height / 2 + height / 8)] = STAIRS;
map[std::make_tuple(width / 2 - width / 8, -1, height / 2 + height / 4 + 1)] = BUMPER;
map[std::make_tuple(width / 2 + width / 8, -1, height / 2 - height / 4 - 1)] = BUMPER;
map[std::make_tuple(width / 2 - width / 4 - 1, -1, height / 2 - height / 8)] = BUMPER;
map[std::make_tuple(width / 2 + width / 4 + 1, -1, height / 2 + height / 8)] = BUMPER;
}
return map;
}
@@ -311,8 +305,6 @@ namespace BBM
{
for (int i = 0; i < width + 1; i++)
for (int j = 0; j < height; j++) {
if (map[std::make_tuple(i, 0, j)] == BREAKABLE && isCloseToBlockType(map, i, 0, j, STAIRS))
map[std::make_tuple(i, 0, j)] = NOTHING;
if (map[std::make_tuple(i, 0, j)] == BREAKABLE && map[std::make_tuple(i, -1, j)] == BUMPER)
map[std::make_tuple(i, 0, j)] = NOTHING;
}
-7
View File
@@ -37,7 +37,6 @@ namespace BBM
UPPERFLOOR,
FLOOR,
BUMPER,
STAIRS,
SPAWNER,
UNBREAKABLE
};
@@ -109,12 +108,6 @@ namespace BBM
//! @brief Create upper floor of the map
static void createUpperFloor(Vector3f coords, std::shared_ptr<WAL::Scene> scene);
//! @param coords coords of the element
//! @param scene Scene where the map is instanced
//! @brief Create stair of the map
static void createStairs(Vector3f coords, std::shared_ptr<WAL::Scene> scene);
//! @param map Map to load with block declared inside
//! @param width Width of the map
//! @param height Height of the map
+5
View File
@@ -168,6 +168,11 @@ namespace BBM
return (point * this) / std::pow(this->magnitude(), 2) * this;
}
Vector3<T> round() const requires(std::is_floating_point_v<T>)
{
return Vector3<T>(std::round(this->x), std::round(this->y), std::round(this->z));
}
operator RAY::Vector3() const requires(std::is_same_v<T, float>)
{
return RAY::Vector3(this->x, this->y, this->z);
+16 -1
View File
@@ -28,9 +28,14 @@
#include <System/Health/HealthSystem.hpp>
#include <System/Animator/AnimatorSystem.hpp>
#include <Component/Animator/AnimatorComponent.hpp>
#include <Component/Tag/TagComponent.hpp>
#include "Component/Animation/AnimationsComponent.hpp"
#include "System/Animation/AnimationsSystem.hpp"
#include "Map/Map.hpp"
#include "Component/Music/MusicComponent.hpp"
#include "Component/Sound/SoundComponent.hpp"
#include "System/Sound/PlayerSoundManagerSystem.hpp"
#include "System/Music/MusicSystem.hpp"
namespace RAY3D = RAY::Drawables::Drawables3D;
@@ -56,7 +61,9 @@ namespace BBM
.addSystem<EventSystem>()
.addSystem<HealthSystem>()
.addSystem<CollisionSystem>()
.addSystem<MovableSystem>();
.addSystem<MovableSystem>()
.addSystem<PlayerSoundManagerSystem>()
.addSystem<MusicSystem>();
}
void enableRaylib(WAL::Wal &wal)
@@ -71,16 +78,24 @@ namespace BBM
std::shared_ptr<WAL::Scene> loadGameScene()
{
auto scene = std::make_shared<WAL::Scene>();
std::map<SoundComponent::SoundIndex, std::string> soundPath ={
{SoundComponent::JUMP, "assets/sounds/jump.wav"},
{SoundComponent::MOVE, "assets/sounds/move.ogg"},
{SoundComponent::BOMB, "assets/sounds/bomb_drop.ogg"},
{SoundComponent::DEATH, "assets/sounds/death.ogg"}
};
scene->addEntity("player")
.addComponent<PositionComponent>()
.addComponent<Drawable3DComponent, RAY3D::Model>("assets/player/player.iqm", std::make_pair(MAP_DIFFUSE, "assets/player/blue.png"))
.addComponent<ControllableComponent>()
.addComponent<AnimatorComponent>()
.addComponent<KeyboardComponent>()
.addComponent<TagComponent<Blowable>>()
//.addComponent<GamepadComponent>(0)
.addComponent<AnimationsComponent>(RAY::ModelAnimations("assets/player/player.iqm"), 3)
.addComponent<CollisionComponent>(BBM::Vector3f{0.25, 0, 0.25}, BBM::Vector3f{.75, 2, .75})
.addComponent<MovableComponent>()
.addComponent<SoundComponent>(soundPath)
.addComponent<BombHolderComponent>()
.addComponent<HealthComponent>(1, [](WAL::Entity &entity) {
auto &animation = entity.getComponent<AnimationsComponent>();
+35 -14
View File
@@ -8,6 +8,10 @@
#include "Component/Renderer/Drawable3DComponent.hpp"
#include "BombHolderSystem.hpp"
#include "Component/Health/HealthComponent.hpp"
#include <functional>
#include <Map/Map.hpp>
#include "Component/Collision/CollisionComponent.hpp"
#include "Component/Tag/TagComponent.hpp"
using namespace std::chrono_literals;
namespace RAY3D = RAY::Drawables::Drawables3D;
@@ -15,34 +19,51 @@ namespace RAY3D = RAY::Drawables::Drawables3D;
namespace BBM
{
std::chrono::nanoseconds BombHolderSystem::explosionTimer = 3s;
float BombHolderSystem::explosionRadius = 3;
BombHolderSystem::BombHolderSystem(WAL::Wal &wal)
: System(wal)
{}
void BombHolderSystem::_dispatchExplosion(Vector3f position, WAL::Wal &wal, int count)
{
if (count <= 0)
return;
wal.scene->scheduleNewEntity("explosion")
.addComponent<PositionComponent>(position)
.addComponent<TimerComponent>(1s, [](WAL::Entity &explosion, WAL::Wal &wal) {
explosion.scheduleDeletion();
})
.addComponent<Drawable3DComponent, RAY3D::Model>("assets/bombs/explosion/explosion.glb",
std::make_pair(MAP_DIFFUSE, "assets/bombs/explosion/blast.png"));
wal.getSystem<EventSystem>().dispatchEvent([position, count](WAL::Wal &wal) {
for (auto &[entity, pos, _] : wal.scene->view<PositionComponent, TagComponent<Blowable>>()) {
if (pos.position.round() == position) {
if (auto *health = entity.tryGetComponent<HealthComponent>())
health->takeDmg(1);
return;
}
}
_dispatchExplosion(position + Vector3f(1, 0, 0), wal, count - 1);
_dispatchExplosion(position + Vector3f(-1, 0, 0), wal, count - 1);
_dispatchExplosion(position + Vector3f(0, 0, 1), wal, count - 1);
_dispatchExplosion(position + Vector3f(0, 0, -1), wal, count - 1);
});
}
void BombHolderSystem::_bombExplosion(WAL::Entity &bomb, WAL::Wal &wal)
{
bomb.scheduleDeletion();
auto &bombPosition = bomb.getComponent<PositionComponent>();
wal.getSystem<EventSystem>().dispatchEvent([&bombPosition, &wal](WAL::Entity &entity){
auto *health = entity.tryGetComponent<HealthComponent>();
auto *pos = entity.tryGetComponent<PositionComponent>();
if (!health || !pos)
return;
if (pos->position.distance(bombPosition.position) > BombHolderSystem::explosionRadius)
return;
// TODO do a raycast here to only remove health to entities that are not behind others.
health->takeDmg(1);
});
auto position = bomb.getComponent<PositionComponent>().position.round();
_dispatchExplosion(position, wal, 3);
}
void BombHolderSystem::_spawnBomb(Vector3f position)
{
this->_wal.scene->scheduleNewEntity("Bomb")
.addComponent<PositionComponent>(position)
.addComponent<PositionComponent>(position.round())
.addComponent<TimerComponent>(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion)
// .addComponent<CollisionComponent>(WAL::Callback<WAL::Entity &, const WAL::Entity &, CollisionComponent::CollidedAxis>(),
// &MapGenerator::wallCollide, 0.25, .75)
.addComponent<Drawable3DComponent, RAY3D::Model>("assets/bombs/bomb.obj",
std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png"));
}
@@ -20,6 +20,9 @@ namespace BBM
//! @brief Spawn a bomb at the specified position.
void _spawnBomb(Vector3f position);
//! @brief Spawn a bomb at the specified position.
static void _dispatchExplosion(Vector3f position, WAL::Wal &, int count);
//! @brief The method triggered when the bomb explode.
static void _bombExplosion(WAL::Entity &bomb, WAL::Wal &);
public:
+8
View File
@@ -15,6 +15,11 @@ namespace BBM
this->_events.emplace_back(event);
}
void EventSystem::dispatchEvent(const std::function<void(WAL::Wal &)> &event)
{
this->_globalEvents.emplace_back(event);
}
void EventSystem::onUpdate(WAL::ViewEntity<> &entity, std::chrono::nanoseconds)
{
for (auto &event : this->_events)
@@ -23,6 +28,9 @@ namespace BBM
void EventSystem::onSelfUpdate()
{
for (auto &event : this->_globalEvents)
event(this->_wal);
this->_events.clear();
this->_globalEvents.clear();
}
}
+6 -1
View File
@@ -14,11 +14,16 @@ namespace BBM
{
private:
//! @brief The list of events that occurred in the last update.
std::vector<std::function<void (WAL::Entity &)>> _events;
std::list<std::function<void (WAL::Entity &)>> _events;
//! @brief The list of events that occurred in the last update.
std::list<std::function<void (WAL::Wal &)>> _globalEvents;
public:
//! @brief Inform the system that a new event has occurred and it should run the given method on every entities.
void dispatchEvent(const std::function<void (WAL::Entity &)>& event);
//! @brief Inform the system that a new event has occurred and it should run the given method on every entities.
void dispatchEvent(const std::function<void (WAL::Wal &)>& event);
//! @inherit
void onUpdate(WAL::ViewEntity<> &entity, std::chrono::nanoseconds dtime) override;
//! @inherit
+24
View File
@@ -0,0 +1,24 @@
//
// Created by Tom Augier on 05/06/2021
//
#include "MusicSystem.hpp"
#include <map>
namespace BBM {
MusicSystem::MusicSystem(WAL::Wal &wal)
: System(wal)
{}
void MusicSystem::onFixedUpdate(WAL::ViewEntity<MusicComponent> &entity)
{
auto &music = entity.get<MusicComponent>();
music.setVolume(music.volume);
if (!music.isPlaying()) {
music.playMusic();
}
music.updateMusicStream();
}
}
+31
View File
@@ -0,0 +1,31 @@
//
// Created by Tom Augier on 05/06/2021
//
#pragma once
#include "System/System.hpp"
#include "Window.hpp"
#include "Component/Music/MusicComponent.hpp"
#include "Component/Health/HealthComponent.hpp"
#include <Component/Controllable/ControllableComponent.hpp>
#include "Wal.hpp"
namespace BBM
{
class MusicSystem : public WAL::System<MusicComponent>
{
public:
//! @inherit
void onFixedUpdate(WAL::ViewEntity<MusicComponent> &entity) override;
//! @brief ctor
MusicSystem(WAL::Wal &wal);
//! @brief Default copy ctor
MusicSystem(const MusicSystem &) = default;
//! @brief Default dtor
~MusicSystem() override = default;
//! @brief A MusicManager screen system can't be assigned.
MusicSystem &operator=(const MusicSystem &) = delete;
};
}
@@ -0,0 +1,34 @@
//
// Created by Tom Augier on 05/06/2021
//
#include "PlayerSoundManagerSystem.hpp"
#include <map>
namespace BBM {
PlayerSoundManagerSystem::PlayerSoundManagerSystem(WAL::Wal &wal)
: System(wal)
{}
void PlayerSoundManagerSystem::onFixedUpdate(WAL::ViewEntity<SoundComponent, ControllableComponent, HealthComponent> &entity)
{
const auto &controllable = entity.get<ControllableComponent>();
auto &sound = entity.get<SoundComponent>();
auto &health = entity.get<HealthComponent>();
sound.setVolume(sound.volume);
std::map<bool, SoundComponent::SoundIndex> soundIndex = {
{health.getHealthPoint() <= 0, SoundComponent::DEATH},
{controllable.bomb, SoundComponent::BOMB},
{controllable.jump, SoundComponent::JUMP},
{controllable.move.x != 0 || controllable.move.y != 0, SoundComponent::MOVE}
};
for (auto &a : soundIndex) {
if (a.first) {
sound.setIndex(a.second);
sound.playSound();
}
}
}
}
@@ -0,0 +1,31 @@
//
// Created by Tom Augier on 05/06/2021
//
#pragma once
#include "System/System.hpp"
#include "Window.hpp"
#include "Component/Sound/SoundComponent.hpp"
#include "Component/Health/HealthComponent.hpp"
#include <Component/Controllable/ControllableComponent.hpp>
#include "Wal.hpp"
namespace BBM
{
class PlayerSoundManagerSystem : public WAL::System<SoundComponent, ControllableComponent, HealthComponent>
{
public:
//! @inherit
void onFixedUpdate(WAL::ViewEntity<SoundComponent, ControllableComponent, HealthComponent> &entity) override;
//! @brief ctor
PlayerSoundManagerSystem(WAL::Wal &wal);
//! @brief Default copy ctor
PlayerSoundManagerSystem(const PlayerSoundManagerSystem &) = default;
//! @brief Default dtor
~PlayerSoundManagerSystem() override = default;
//! @brief A SoundManager screen system can't be assigned.
PlayerSoundManagerSystem &operator=(const PlayerSoundManagerSystem &) = delete;
};
}
+57
View File
@@ -0,0 +1,57 @@
#include <catch2/catch.hpp>
#define private public
#include <Drawables/Image.hpp>
#include <Audio/Sound.hpp>
#include <Audio/Music.hpp>
#include <TraceLog.hpp>
#include <iostream>
TEST_CASE("Cache test - New Load - Not lonely", "[Cache]")
{
RAY::TraceLog::setLevel(RAY::TraceLog::Level::LOG_NONE);
RAY::Image myImage("assets/icon.png", false);
REQUIRE(RAY::Image::_imagesCache._cache.size() == 1);
REQUIRE(RAY::Image::_imagesCache._cache.contains("assets/icon.png"));
REQUIRE(RAY::Image::_imagesCache._cache["assets/icon.png"].size() == 1);
REQUIRE(myImage._image.use_count() == 2);
RAY::Image::_imagesCache._cache.clear();
}
TEST_CASE("Cache test - New Load - Lonely", "[Cache][segf]")
{
RAY::TraceLog::setLevel(RAY::TraceLog::Level::LOG_NONE);
RAY::Image myImage("assets/icon.png", false);
REQUIRE(RAY::Image::_imagesCache._cache.size() == 1);
REQUIRE(RAY::Image::_imagesCache._cache.contains("assets/icon.png"));
REQUIRE(RAY::Image::_imagesCache._cache["assets/icon.png"].size() == 1);
REQUIRE(myImage._image.use_count() == 2);
}
TEST_CASE("Cache test - Already loaded - Lonely", "[Cache]")
{
RAY::Audio::Sound mySound("assets/sounds/crate_break.ogg", false);
RAY::Audio::Sound mySound2("assets/sounds/crate_break.ogg", true);
REQUIRE(RAY::Audio::Sound::_soundsCache._cache.size() == 1);
REQUIRE(RAY::Audio::Sound::_soundsCache._cache.contains("assets/sounds/crate_break.ogg"));
REQUIRE(RAY::Audio::Sound::_soundsCache._cache["assets/sounds/crate_break.ogg"].size() == 2);
REQUIRE(mySound._sound.use_count() == 2);
REQUIRE(mySound2._sound.use_count() == 2);
}
TEST_CASE("Cache test - Already loaded - Not lonely", "[Cache]")
{
RAY::Audio::Music myMusic("assets/musics/music_result.ogg", false);
RAY::Audio::Music myMusic2("assets/musics/music_result.ogg", false);
REQUIRE(RAY::Audio::Music::_musicsCache._cache.size() == 1);
REQUIRE(RAY::Audio::Music::_musicsCache._cache.contains("assets/musics/music_result.ogg"));
REQUIRE(RAY::Audio::Music::_musicsCache._cache["assets/musics/music_result.ogg"].size() == 1);
REQUIRE(myMusic._music.use_count() == 3);
REQUIRE(myMusic2._music.use_count() == 3);
}
+6
View File
@@ -97,4 +97,10 @@ TEST_CASE("Collsion test with movable", "[Component][System]")
REQUIRE(entity.getComponent<PositionComponent>().position.x == 0.0);
REQUIRE(entity.getComponent<PositionComponent>().position.y == 0.0);
REQUIRE(entity.getComponent<PositionComponent>().position.z == 0.0);
}
TEST_CASE("Vector round", "[Vector]")
{
Vector3f v(1.3, 1.5, 1.7);
REQUIRE(v.round() == Vector3f(1, 2, 2));
}