Adjusted animation definition storage to be consistent

This commit is contained in:
Ethan 2025-04-02 19:33:13 -04:00
parent dccd19ac80
commit d3ad840169
30 changed files with 216 additions and 137 deletions

View file

@ -1,6 +1,8 @@
<!--
<animations> <animations>
<animation name="bubble_idle_anim" type="idle"> <animation name="bubble_idle_anim" type="idle">
<FPS>2</FPS> <FPS>2</FPS>
<sprite path="sprites/bubbleoAtlas64.png" frameSize="64.0"/> <sprite path="sprites/bubbleoAtlas64.png" frameSize="64.0"/>
</animation> </animation>
</animations> </animations>
-->

View file

@ -0,0 +1,22 @@
<!-- Player Animations -->
<animation id="character/player/idle" directional="true" FPS="5" frameSize="64.0" atlas="sprites/player3AtlasIdle64.png"/>
<animation id="character/player/move" directional="true" FPS="7" frameSize="64.0" atlas="sprites/player3AtlasMove64.png"/>
<!-- Fallback animations -->
<animation id="character/tmp/move" directional="false" FPS="7" frameSize="128.0" atlas="sprites/player2Atlas.png"/>
<!--
<animations directional="true">
<animation name="player_move_anim" type="move">
<FPS>7</FPS>
<sprite path="sprites/player3AtlasMove64.png" frameSize="64.0"/>
</animation>
<animation name="player_idle_anim" type="idle">
<FPS>5</FPS>
<sprite path="sprites/player3AtlasIdle64.png" frameSize="64.0"/>
</animation>
</animations>
-->

View file

@ -1,3 +1,4 @@
<!--
<animations> <animations>
<animation name="machine_gun_idle_anim" type="idle"> <animation name="machine_gun_idle_anim" type="idle">
<FPS>4</FPS> <FPS>4</FPS>
@ -8,3 +9,4 @@
<sprite path="sprites/machineGunAtlasReload256.png" frameSize="256.0"/> <sprite path="sprites/machineGunAtlasReload256.png" frameSize="256.0"/>
</animation> </animation>
</animations> </animations>
-->

View file

@ -0,0 +1,2 @@
<!-- Bubble -->
<animation id="obj/bubble/idle" FPS="2" frameSize="64.0" atlas="sprites/bubbleoAtlas64.png"/>

View file

@ -1,3 +1,4 @@
<!--
<animations> <animations>
<animation name="pistol_idle_anim" type="idle"> <animation name="pistol_idle_anim" type="idle">
<FPS>4</FPS> <FPS>4</FPS>
@ -8,3 +9,4 @@
<sprite path="sprites/pistolAtlasReload256.png" frameSize="256.0"/> <sprite path="sprites/pistolAtlasReload256.png" frameSize="256.0"/>
</animation> </animation>
</animations> </animations>
-->

View file

@ -1,11 +0,0 @@
<animations directional="true">
<animation name="player_move_anim" type="move">
<FPS>7</FPS>
<sprite path="sprites/player3AtlasMove64.png" frameSize="64.0"/>
</animation>
<animation name="player_idle_anim" type="idle">
<FPS>5</FPS>
<sprite path="sprites/player3AtlasIdle64.png" frameSize="64.0"/>
</animation>
</animations>

View file

@ -1,3 +1,4 @@
<!--
<animations> <animations>
<animation name="shot_gun_idle_anim" type="idle"> <animation name="shot_gun_idle_anim" type="idle">
<FPS>4</FPS> <FPS>4</FPS>
@ -12,3 +13,4 @@
<sprite path="sprites/shotGunReload128.png" frameSize="128.0"/> <sprite path="sprites/shotGunReload128.png" frameSize="128.0"/>
</animation> </animation>
</animations> </animations>
-->

View file

@ -1,6 +1,8 @@
<!--
<animations> <animations>
<animation name="tmp_enemy_move_anim" type="move"> <animation name="tmp_enemy_move_anim" type="move">
<FPS>7</FPS> <FPS>7</FPS>
<sprite path="sprites/player2Atlas.png" frameSize="128.0"/> <sprite path="sprites/player2Atlas.png" frameSize="128.0"/>
</animation> </animation>
</animations> </animations>
-->

View file

@ -0,0 +1,13 @@
<!-- Machine Gun -->
<animation id="gun/machine/idle" FPS="4" frameSize="256.0" atlas="sprites/machineGunAtlas256.png"/>
<animation id="gun/machine/reload" FPS="6" frameSize="256.0" atlas="sprites/machineGunAtlasReload256.png"/>
<!-- Pistol -->
<animation id="gun/pistol/idle" FPS="4" frameSize="256.0" atlas="sprites/pistolAtlas256.png"/>
<animation id="gun/pistol/reload" FPS="8" frameSize="256.0" atlas="sprites/pistolAtlasReload256.png"/>
<!-- Shotgun -->
<animation id="gun/shotgun/idle" FPS="4" frameSize="128.0" atlas="sprites/shotGunIdle128.png"/>
<animation id="gun/shotgun/fire" FPS="8" frameSize="128.0" atlas="sprites/shotGunFire128.png"/>
<animation id="gun/shotgun/reload" FPS="8" frameSize="128.0" atlas="sprites/shotGunReload128.png"/>

View file

@ -3,19 +3,19 @@
<scene type="shooter" id="000" bg="backgrounds/blue_sky.png"> <scene type="shooter" id="000" bg="backgrounds/blue_sky.png">
<map name="newmap"/> <map name="newmap"/>
<entities> <entities>
<player x="7" y="5" weapon="shotGun"> <player x="7" y="5" weapon="shotgun">
<animation name="player_anim"/> <animation id="character/player"/>
</player> </player>
<entity x="10" y="3" weapon="pistolGun"> <entity x="10" y="3" weapon="pistol">
<animation name="player_anim"/> <animation id="character/player"/>
<script file="scripts/ai/grunt_behaviour.lua"/> <script file="scripts/ai/grunt_behaviour.lua"/>
</entity> </entity>
<entity x="6" y="3" weapon="pistolGun"> <entity x="6" y="3" weapon="pistol">
<animation name="tmp_enemy_anim"/> <animation id="character/tmp"/>
<script file="scripts/ai/grunt_behaviour.lua"/> <script file="scripts/ai/grunt_behaviour.lua"/>
</entity> </entity>
<entity x="5" y="3" weapon="pistolGun"> <entity x="5" y="3" weapon="pistol">
<animation name="tmp_enemy_anim"/> <animation id="character/tmp"/>
<script file="scripts/ai/grunt_behaviour.lua"/> <script file="scripts/ai/grunt_behaviour.lua"/>
</entity> </entity>
</entities> </entities>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Shotgun Sounds -->
<sound id="gun/shotgun/shoot" spatial="true" path="sounds/gun/big_boom.ogg"/>
<!-- Pistol Sounds -->
<sound id="gun/pistol/shoot" spatial="true" path="sounds/gun/small_pew.ogg"/>
<!-- Generic Sounds -->
<sound id="gun/generic/shoot" spatial="true" path="sounds/gun/small_pew.ogg"/>

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<weapons> <weapons>
<weapon name="bubbleGun" fireSpeed="100.0" maxAmmo="40000" clipSize="1000"> <weapon name="bubblegun" fireSpeed="100.0" maxAmmo="40000" clipSize="1000">
<bullet anim="bubble_anim"> <bullet anim="obj/bubble">
<spread>60</spread> <spread>60</spread>
<speed>20.0</speed> <speed>20.0</speed>
<drop>250.0</drop> <drop>250.0</drop>
@ -11,9 +11,9 @@
</bullet> </bullet>
</weapon> </weapon>
<weapon name="shotGun" fireSpeed="1750.0" maxAmmo="64" clipSize="4"> <weapon name="shotgun" fireSpeed="1750.0" maxAmmo="64" clipSize="4">
<script file="scripts/weapons/shotgun_script.lua"/> <script file="scripts/weapons/shotgun_script.lua"/>
<animation name="shot_gun_anim"> <animation id="gun/shotgun">
<size x="55.0" y="55.0"/> <size x="55.0" y="55.0"/>
<offset x="-30.0" y="0.0"/> <offset x="-30.0" y="0.0"/>
</animation> </animation>
@ -26,8 +26,8 @@
</bullet> </bullet>
</weapon> </weapon>
<weapon name="machineGun" fireSpeed="50.0" maxAmmo="512" clipSize="64"> <weapon name="machine_gun" fireSpeed="50.0" maxAmmo="512" clipSize="64">
<animation name="machine_gun_anim"> <animation id="gun/machine">
<size x="55.0" y="55.0"/> <size x="55.0" y="55.0"/>
<offset x="-30.0" y="0.0"/> <offset x="-30.0" y="0.0"/>
</animation> </animation>
@ -40,8 +40,8 @@
</bullet> </bullet>
</weapon> </weapon>
<weapon name="pistolGun" fireSpeed="750.0" maxAmmo="512" clipSize="21"> <weapon name="pistol" fireSpeed="750.0" maxAmmo="512" clipSize="21">
<animation name="pistol_anim"> <animation id="gun/pistol">
<size x="55.0" y="55.0"/> <size x="55.0" y="55.0"/>
<offset x="-30.0" y="0.0"/> <offset x="-30.0" y="0.0"/>
</animation> </animation>

View file

@ -16,7 +16,7 @@ struct TileSetData;
class Map : public Drawable class Map : public Drawable
{ {
public: public:
Map(std::shared_ptr<MapData> mapData, const unsigned shaderID, std::shared_ptr<ResourceManager> resourceManager); Map(const MapData* mapData, const unsigned shaderID, std::shared_ptr<ResourceManager> resourceManager);
const std::vector<std::vector<int>> getCollisionMap() const { return collisionMap; } const std::vector<std::vector<int>> getCollisionMap() const { return collisionMap; }
@ -28,8 +28,8 @@ private:
size_t getTileSetIndex(int id) const; size_t getTileSetIndex(int id) const;
std::shared_ptr<MapData> mapData; const MapData* mapData;
std::vector<std::shared_ptr<TileSetData>> tileSetData; std::vector<const TileSetData*> tileSetData;
std::vector<std::shared_ptr<TileTextureInstance>> instanceHandles; std::vector<std::shared_ptr<TileTextureInstance>> instanceHandles;
std::vector<std::vector<std::vector<int>>> tileIds; std::vector<std::vector<std::vector<int>>> tileIds;

View file

@ -78,7 +78,7 @@ private:
std::shared_ptr<ResourceManager> resourceManager; std::shared_ptr<ResourceManager> resourceManager;
std::weak_ptr<EventManager> globalEventManager; std::weak_ptr<EventManager> globalEventManager;
std::shared_ptr<EventManager> eventManager; std::shared_ptr<EventManager> eventManager;
std::shared_ptr<SceneData> sceneData; const SceneData* sceneData;
}; };
#endif //_H_SCENE_H #endif //_H_SCENE_H

View file

@ -27,7 +27,7 @@ struct WeaponData;
class Weapon : public Entity, public std::enable_shared_from_this<Weapon> class Weapon : public Entity, public std::enable_shared_from_this<Weapon>
{ {
public: public:
Weapon(std::shared_ptr<WeaponData> data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager); Weapon(const WeaponData* data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager);
void setWielder(GameActor* wielder) { this->wielder = wielder; } void setWielder(GameActor* wielder) { this->wielder = wielder; }
void toggleInfiniteAmmo() { infiniteAmmo = !infiniteAmmo; } void toggleInfiniteAmmo() { infiniteAmmo = !infiniteAmmo; }

View file

@ -23,10 +23,11 @@ struct AnimationData;
class Animation class Animation
{ {
public: public:
Animation(const std::shared_ptr<AnimationData>& animData, ResourceManager* resourceManager); Animation(const AnimationData* animData, ResourceManager* resourceManager);
std::string getName() const { return animName; } std::string getPrefix() const { return prefix; }
std::string getType() const { return animType; } std::string getType() const { return type; }
std::string getID() const { return prefix + "/" + type; }
void bind(); void bind();
void draw(); void draw();
@ -34,7 +35,7 @@ public:
void play() { isPlaying = true; } void play() { isPlaying = true; }
void stop() { isPlaying = false; } void stop() { isPlaying = false; }
void reset() { currentFrame = 0; } void reset() { currentFrame = 0; lastFrameTick = 0; elapsedTime = 0; }
const bool getPlaying() const { return isPlaying; } const bool getPlaying() const { return isPlaying; }
const bool getDirectional() const { return isDirectional; } const bool getDirectional() const { return isDirectional; }
@ -43,8 +44,8 @@ public:
void setFPS(const float fps) { FPS = fps; } void setFPS(const float fps) { FPS = fps; }
private: private:
std::string animName; std::string prefix;
std::string animType; std::string type;
SpriteAtlas* spriteAtlas; SpriteAtlas* spriteAtlas;
@ -70,7 +71,7 @@ class AnimationSet : public std::enable_shared_from_this<AnimationSet>
{ {
public: public:
AnimationSet(const int& entityid); AnimationSet(const int& entityid);
AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<std::shared_ptr<AnimationData>> animSet); AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<AnimationData*> animSet);
AnimationSet(const int& entityid, std::unordered_map<std::string, std::unique_ptr<Animation>> animations); AnimationSet(const int& entityid, std::unordered_map<std::string, std::unique_ptr<Animation>> animations);
Animation* operator [](std::string animType) { return anims[animType].get(); } Animation* operator [](std::string animType) { return anims[animType].get(); }

View file

@ -26,13 +26,15 @@ class SoundEffect
public: public:
SoundEffect(const std::string& filename); SoundEffect(const std::string& filename);
ALuint getBuffer() const { return buffer; }
bool isValid() const { return valid; }
~SoundEffect(); ~SoundEffect();
private: private:
bool loadFile(const std::string &filename); bool loadFile(const std::string &filename);
ALuint buffer; ALuint buffer;
bool valid;
}; };
#endif // _H_SOUNDEFFECT_H #endif // _H_SOUNDEFFECT_H

View file

@ -12,8 +12,26 @@ namespace UTIL
} }
constexpr float INF_TIME = -99.6875f; constexpr float INF_TIME = -99.6875f;
constexpr auto split = [](const std::string& s, size_t *left, size_t *right, std::string *out) {
if ((*right = s.find("/", *left)) != std::string::npos) {
if (out) {
*out = s.substr(*left, *right - *left);
}
*left = *right + 1;
} else {
if (out) {
out->append(s.substr(*left));
}
}
};
constexpr auto get_type = [](const std::string& id) {
auto pos = id.find_last_of("/");
return (pos != std::string::npos) ? id.substr(pos + 1) : id;
};
void flip_surface(SDL_Surface* surface); void flip_surface(SDL_Surface* surface);
std::string parsePrefix(const std::string& id);
class RandomGenerator class RandomGenerator
{ {

View file

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "sound/soundeffect.h"
#include "utility/xmlloader.h" #include "utility/xmlloader.h"
#include "graphics/shader.h" #include "graphics/shader.h"
#include "graphics/sprite.h" #include "graphics/sprite.h"
@ -40,12 +41,12 @@ public:
Background* loadBackground (const std::string& path); Background* loadBackground (const std::string& path);
std::shared_ptr<AIScript> loadAIScript (const std::string& path); std::shared_ptr<AIScript> loadAIScript (const std::string& path);
std::shared_ptr<WeaponScript> loadWeaponScript (const std::string& path); std::shared_ptr<WeaponScript> loadWeaponScript (const std::string& path);
std::shared_ptr<Weapon> loadWeapon (const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID);
std::shared_ptr<AnimationSet> loadAnimationSet (const std::string& name, int entityid = 0);
const unsigned loadShader (const std::string& name, const std::string& vertexPath, const std::string& fragPath); const unsigned loadShader (const std::string& name, const std::string& vertexPath, const std::string& fragPath);
std::shared_ptr<Weapon> loadWeapon (const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID); const SceneData* loadScene (const std::string& id);
std::shared_ptr<SceneData> loadScene (const std::string& id); const TileSetData* loadTileSet (const std::string& name);
std::shared_ptr<AnimationSet> loadAnimationSet (const std::string& name, int entityid = 0);
std::shared_ptr<TileSetData> loadTileSet (const std::string& name);
// Returns a NON-OWNING pointer to a shader by ID // Returns a NON-OWNING pointer to a shader by ID
Shader* getShaderByID(unsigned int ID); Shader* getShaderByID(unsigned int ID);
@ -57,6 +58,7 @@ public:
private: private:
std::unordered_map<std::string, std::unique_ptr<Shader>> shaders; std::unordered_map<std::string, std::unique_ptr<Shader>> shaders;
std::unordered_map<unsigned, Shader*> shaderIDs; std::unordered_map<unsigned, Shader*> shaderIDs;
std::unordered_map<std::string, std::unique_ptr<SoundEffect>> sounds;
std::unordered_map<std::string, std::unique_ptr<Sprite>> sprites; std::unordered_map<std::string, std::unique_ptr<Sprite>> sprites;
std::unordered_map<std::string, std::shared_ptr<Weapon>> weapons; std::unordered_map<std::string, std::shared_ptr<Weapon>> weapons;
std::unordered_map<std::string, std::shared_ptr<Script>> scripts; std::unordered_map<std::string, std::shared_ptr<Script>> scripts;

View file

@ -19,7 +19,7 @@ struct EntityData {
bool animated; bool animated;
int x = 0, y = 0; int x = 0, y = 0;
std::string graphic; std::string graphic;
std::string weapon = "pistolGun"; std::string weapon = "pistol";
std::string script; std::string script;
}; };
@ -67,7 +67,7 @@ struct SceneData {
std::string type; std::string type;
std::string bgFile; std::string bgFile;
std::shared_ptr<MapData> map; const MapData* map;
std::vector<EntityData> entities; std::vector<EntityData> entities;
}; };
@ -78,7 +78,7 @@ struct WeaponData {
int maxAmmo = 512; int maxAmmo = 512;
std::string script = ""; std::string script = "";
std::string graphic; std::string graphic;
std::string animSet; std::string animPrefix;
bool animated = false; bool animated = false;
float sizeX = 50.f, sizeY = 50.f; float sizeX = 50.f, sizeY = 50.f;
float offsetX = 0.f, offsetY = 0.f; float offsetX = 0.f, offsetY = 0.f;
@ -89,22 +89,26 @@ struct WeaponData {
float modMin = 0.5f, modMax = 1.0f; float modMin = 0.5f, modMax = 1.0f;
}; };
// ID is the new tactic I've decided on.
// Each animationable object will be given a prefix
// denoting their type and object so <type>/<object>
// This prefix will be used to look up the animation on
// the animation map
struct AnimationData { struct AnimationData {
std::string name; std::string id;
std::string type;
std::string spriteAtlas; std::string spriteAtlas;
// Each entity will have a set of animations,
// this animation set is meant to keep each group
// of animations within their set.
// The actual set name is based on the file the animation
// is held in.
std::string animSet;
bool directional = false; bool directional = false;
bool oneShot; bool oneShot;
float FPS = 1.f; float FPS = 1.f;
float frameSize; float frameSize;
}; };
struct SoundData {
std::string id; // <type>/<object>/<state>
std::string path;
bool spatial;
};
class XMLLoader class XMLLoader
{ {
public: public:
@ -115,45 +119,45 @@ public:
bool loadTileSets(const char* tileSetFolder); bool loadTileSets(const char* tileSetFolder);
bool loadMaps(const char* mapFolder); bool loadMaps(const char* mapFolder);
const std::shared_ptr<SceneData> getSceneData(const std::string& id) const { const SceneData* getSceneData(const std::string& id) const {
try { try {
return scenes.at(id); return scenes.at(id).get();
} }
catch (std::exception&) { catch (std::exception&) {
return nullptr; return nullptr;
} }
} }
const std::shared_ptr<MapData> getMapData(const std::string& name) const { const MapData* getMapData(const std::string& name) const {
try { try {
return maps.at(name); return maps.at(name).get();
} }
catch (std::exception&) { catch (std::exception&) {
return nullptr; return nullptr;
} }
} }
const std::shared_ptr<WeaponData> getWeaponData(const std::string& name) const { const WeaponData* getWeaponData(const std::string& name) const {
try { try {
return weapons.at(name); return weapons.at(name).get();
} }
catch (std::exception&) { catch (std::exception&) {
return nullptr; return nullptr;
} }
} }
const std::shared_ptr<AnimationData> getAnimationData(const std::string& name) const { const AnimationData* getAnimationData(const std::string& id) const {
try { try {
return animations.at(name); return animations.at(id).get();
} }
catch (std::exception&) { catch (std::exception&) {
return nullptr; return nullptr;
} }
} }
const std::shared_ptr<TileSetData> getTileSetData(const std::string& name) const { const TileSetData* getTileSetData(const std::string& name) const {
try { try {
return tileSets.at(name); return tileSets.at(name).get();
} }
catch (std::exception&) { catch (std::exception&) {
return nullptr; return nullptr;
@ -163,11 +167,11 @@ public:
// return a full set of animations, may need further optimization. // return a full set of animations, may need further optimization.
// one idea is when loading animations we create a seperate map that holds each set by their reference, so we can just do a simple, // one idea is when loading animations we create a seperate map that holds each set by their reference, so we can just do a simple,
// hash table lookup. // hash table lookup.
std::vector<std::shared_ptr<AnimationData>> getAnimationSet(const std::string& set) const { std::vector<AnimationData*> getAnimationSet(const std::string& prefix) const {
std::vector<std::shared_ptr<AnimationData>> animSet; std::vector<AnimationData*> animSet;
animSet.reserve(animations.size()); animSet.reserve(animations.size());
for (const auto& [name, anim] : animations) { for (const auto& [id, anim] : animations) {
if (anim->animSet == set) animSet.push_back(anim); if (id.starts_with(prefix)) animSet.push_back(anim.get());
} }
animSet.shrink_to_fit(); animSet.shrink_to_fit();
return animSet; return animSet;
@ -180,11 +184,11 @@ protected:
bool loadTile(tinyxml2::XMLElement* tileElement, TileSetData::TileData* out); bool loadTile(tinyxml2::XMLElement* tileElement, TileSetData::TileData* out);
bool loadObject(tinyxml2::XMLElement* objectElement, TileSetData::TileData::ObjectData* out); bool loadObject(tinyxml2::XMLElement* objectElement, TileSetData::TileData::ObjectData* out);
private: private:
std::unordered_map<std::string, std::shared_ptr<SceneData>> scenes; std::unordered_map<std::string, std::unique_ptr<SceneData>> scenes;
std::unordered_map<std::string, std::shared_ptr<WeaponData>> weapons; std::unordered_map<std::string, std::unique_ptr<WeaponData>> weapons;
std::unordered_map<std::string, std::shared_ptr<AnimationData>> animations; std::unordered_map<std::string, std::unique_ptr<AnimationData>> animations;
std::unordered_map<std::string, std::shared_ptr<MapData>> maps; std::unordered_map<std::string, std::unique_ptr<MapData>> maps;
std::unordered_map<std::string, std::shared_ptr<TileSetData>> tileSets; std::unordered_map<std::string, std::unique_ptr<TileSetData>> tileSets;
}; };
#endif // _H_XMLLOADER_H #endif // _H_XMLLOADER_H

View file

@ -8,7 +8,7 @@
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
Map::Map(std::shared_ptr<MapData> mapData, const unsigned shaderID, std::shared_ptr<ResourceManager> resourceManager) : Map::Map(const MapData* mapData, const unsigned shaderID, std::shared_ptr<ResourceManager> resourceManager) :
mapData(mapData), mapData(mapData),
tileIds(mapData->tiles) tileIds(mapData->tiles)
{ {

View file

@ -88,7 +88,7 @@ void Scene::loadDebugShooterScene()
auto entitySprite = resourceManager->loadSpriteStatic(entityData.graphic); auto entitySprite = resourceManager->loadSpriteStatic(entityData.graphic);
entity->addComponent(std::make_unique<SpriteComponent>(entitySprite)); entity->addComponent(std::make_unique<SpriteComponent>(entitySprite));
} }
auto defaultWeapon = resourceManager->loadWeapon("pistolGun", weaponShader, bubbleShader); auto defaultWeapon = resourceManager->loadWeapon("pistol", weaponShader, bubbleShader);
auto entityWeapon = resourceManager->loadWeapon(entityData.weapon, weaponShader, bubbleShader); auto entityWeapon = resourceManager->loadWeapon(entityData.weapon, weaponShader, bubbleShader);
entity->pickupWeapon(defaultWeapon); entity->pickupWeapon(defaultWeapon);

View file

@ -14,7 +14,7 @@
// TODO: Regular clean up, make this mess readable! // TODO: Regular clean up, make this mess readable!
Weapon::Weapon(std::shared_ptr<WeaponData> data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager) Weapon::Weapon(const WeaponData* data, const unsigned weaponShaderID, const unsigned bulletShaderID, ResourceManager* resourceManager)
: :
Entity (weaponShaderID), Entity (weaponShaderID),
weaponType (data->name), weaponType (data->name),
@ -54,7 +54,7 @@ void Weapon::reload()
{ {
if (auto event = eventManager.lock()) if (auto event = eventManager.lock())
{ {
event->notify<EntityReloadEvent>((EntityReloadEvent){ entityid, wielder->getPosition(), weaponType }); event->notify<EntityReloadEvent>({ entityid, wielder->getPosition(), weaponType });
reloading = true; reloading = true;
if (weaponAmmo < weaponMagSize) { if (weaponAmmo < weaponMagSize) {
weaponMag = weaponAmmo; weaponMag = weaponAmmo;
@ -172,7 +172,7 @@ void Weapon::update(double deltaTime)
{ {
wasReloading = false; wasReloading = false;
if (auto event = eventManager.lock()) { if (auto event = eventManager.lock()) {
event->notify<EntityFinishReloadEvent>((EntityFinishReloadEvent){entityid}); event->notify<EntityFinishReloadEvent>({entityid});
} }
} }
} }
@ -258,7 +258,7 @@ void Weapon::createBullet(const Weapon::BulletData& data)
bullet->getPhysicsComponent()->rigidBody.velocity += bulletSpeed * data.direction / data.mass; bullet->getPhysicsComponent()->rigidBody.velocity += bulletSpeed * data.direction / data.mass;
if (auto event = eventManager.lock()) if (auto event = eventManager.lock())
event->notify<BulletFiredEvent>((BulletFiredEvent){bullet}); event->notify<BulletFiredEvent>({bullet});
bulletManager->addBullet(bullet); bulletManager->addBullet(bullet);
} }

View file

@ -3,17 +3,19 @@
#include "utility/xmlloader.h" #include "utility/xmlloader.h"
#include "utility/resourcemanager.h" #include "utility/resourcemanager.h"
#include "utility/events.h" #include "utility/events.h"
#include "util.h"
Animation::Animation(const std::shared_ptr<AnimationData>& animData, ResourceManager* resourceManager) : Animation::Animation(const AnimationData* animData, ResourceManager* resourceManager) :
animName(animData->name),
animType(animData->type),
spriteAtlas(resourceManager->loadSpriteAtlas(animData->spriteAtlas, animData->frameSize, animData->directional)), spriteAtlas(resourceManager->loadSpriteAtlas(animData->spriteAtlas, animData->frameSize, animData->directional)),
FPS(animData->FPS), FPS(animData->FPS),
currentFrame(0), currentFrame(0),
cycles(0), cycles(0),
isDirectional(animData->directional), isDirectional(animData->directional),
isPlaying(isDirectional) isPlaying(isDirectional)
{} {
prefix = UTIL::parsePrefix(animData->id);
type = UTIL::get_type(animData->id);
}
void Animation::bind() void Animation::bind()
{ {
@ -74,24 +76,25 @@ void Animation::frameTick()
} }
AnimationSet::AnimationSet(const int& entityid) : entityid(entityid), isDirectional(false) {}; AnimationSet::AnimationSet(const int& entityid) : entityid(entityid), isDirectional(false) {};
AnimationSet::AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<std::shared_ptr<AnimationData>> animSet) : entityid(entityid) AnimationSet::AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<AnimationData*> animSet) : entityid(entityid)
{ {
curAnim = nullptr; curAnim = nullptr;
for (const auto& anim : animSet) for (const auto& anim : animSet)
{ {
anims.try_emplace(anim->type, std::make_unique<Animation>(anim, resourceManager)); std::string type = UTIL::get_type(anim->id);
if (anim->type == "idle") anims.try_emplace(type, std::make_unique<Animation>(anim, resourceManager));
curAnim = anims[anim->type].get(); if (type == "idle")
curAnim = anims[type].get();
} }
// if we don't have an idle animation, we are just gonna set the current animation to the top of the set // if we don't have an idle animation, we are just gonna set the current animation to the top of the set
if (curAnim == nullptr) if (curAnim == nullptr)
curAnim = anims[animSet[0]->type].get(); curAnim = anims[UTIL::get_type(animSet[0]->id)].get();
isDirectional = curAnim->getDirectional(); isDirectional = curAnim->getDirectional();
} }
AnimationSet::AnimationSet(const int& entityid, std::unordered_map<std::string, std::unique_ptr<Animation>> animations) AnimationSet::AnimationSet(const int& entityid, std::unordered_map<std::string, std::unique_ptr<Animation>> animations)
: entityid(entityid), anims(std::move(animations)) : entityid(entityid), anims(std::move(animations))
{ {
for (auto& [type, anim] : animations) for (auto& [type, anim] : anims)
{ {
curAnim = anim.get(); curAnim = anim.get();
if (type == "idle") if (type == "idle")
@ -165,8 +168,10 @@ void AnimationSet::attachEventManager(std::weak_ptr<EventManager> e)
if (auto self = weakSelf.lock()) { if (auto self = weakSelf.lock()) {
if (e.entityid == self->entityid) if (e.entityid == self->entityid)
{ {
if (self->anims["idle"] != NULL) if (self->anims["idle"] != NULL) {
self->curAnim->reset();
self->curAnim = self->anims["idle"].get(); self->curAnim = self->anims["idle"].get();
}
} }
} }
}); });
@ -215,7 +220,7 @@ void AnimationSet::draw()
// If the animation has cycled, we send this event after every cycle // If the animation has cycled, we send this event after every cycle
if ((curAnim->getCycles() - lastCycle) > 0) { if ((curAnim->getCycles() - lastCycle) > 0) {
if (auto event = eventManager.lock()) { if (auto event = eventManager.lock()) {
event->notify((AnimationFinishedEvent){entityid, curAnim->getType()}); event->notify<AnimationFinishedEvent>({entityid, curAnim->getType()});
} }
} }
} }

View file

@ -4,9 +4,7 @@
SoundEffect::SoundEffect(const std::string& filename) SoundEffect::SoundEffect(const std::string& filename)
{ {
if (!loadFile(filename)) { valid = loadFile(filename);
return;
}
} }
// load the whole file into a buffer, this should only be used for small sound effects. Never with music or sounds exceeding 10MB! // load the whole file into a buffer, this should only be used for small sound effects. Never with music or sounds exceeding 10MB!

View file

@ -22,4 +22,16 @@ namespace UTIL
delete[] temp; delete[] temp;
SDL_UnlockSurface(surface); SDL_UnlockSurface(surface);
} }
std::string parsePrefix(const std::string& id)
{
std::string prefix;
size_t left = 0;
size_t right = 0;
UTIL::split(id, &left, &right, &prefix);
prefix += "/";
UTIL::split(id, &left, &right, &prefix);
return prefix;
}
} }

View file

@ -39,7 +39,7 @@ std::shared_ptr<WeaponScript> ResourceManager::loadWeaponScript(const std::strin
return std::make_shared<WeaponScript>(path.c_str()); return std::make_shared<WeaponScript>(path.c_str());
} }
std::shared_ptr<TileSetData> ResourceManager::loadTileSet(const std::string& name) const TileSetData* ResourceManager::loadTileSet(const std::string& name)
{ {
return xmlLoader->getTileSetData(name); return xmlLoader->getTileSetData(name);
} }
@ -79,21 +79,21 @@ Background* ResourceManager::loadBackground(const std::string& path)
// incomplete reference to our script. // incomplete reference to our script.
std::shared_ptr<Weapon> ResourceManager::loadWeapon(const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID) std::shared_ptr<Weapon> ResourceManager::loadWeapon(const std::string& name, const unsigned weaponShaderID, const unsigned bulletShaderID)
{ {
std::shared_ptr<WeaponData> data = xmlLoader->getWeaponData(name); const WeaponData* data = xmlLoader->getWeaponData(name);
auto weapon = std::make_shared<Weapon>(data, weaponShaderID, bulletShaderID, this); auto weapon = std::make_shared<Weapon>(data, weaponShaderID, bulletShaderID, this);
if (!data->script.empty()) if (!data->script.empty())
weapon->attachScript(loadWeaponScript(data->script)); weapon->attachScript(loadWeaponScript(data->script));
return weapon; return weapon;
} }
std::shared_ptr<SceneData> ResourceManager::loadScene(const std::string& id) const SceneData* ResourceManager::loadScene(const std::string& id)
{ {
return xmlLoader->getSceneData(id); return xmlLoader->getSceneData(id);
} }
std::shared_ptr<AnimationSet> ResourceManager::loadAnimationSet(const std::string& name, int entityid) std::shared_ptr<AnimationSet> ResourceManager::loadAnimationSet(const std::string& prefix, int entityid)
{ {
auto animSetData = xmlLoader->getAnimationSet(name); auto animSetData = xmlLoader->getAnimationSet(prefix);
return std::make_shared<AnimationSet>(entityid, this, animSetData); return std::make_shared<AnimationSet>(entityid, this, animSetData);
} }

View file

@ -1,6 +1,7 @@
#include "utility/xmlloader.h" #include "utility/xmlloader.h"
#include "utility/logger.h" #include "utility/logger.h"
#include <tinyxml2.h>
/* /*
Loading every scene in the scene folder and storing in hashmap scenes Loading every scene in the scene folder and storing in hashmap scenes
@ -18,7 +19,7 @@ bool XMLLoader::loadScenes(const char* sceneFolder)
SceneData scene; SceneData scene;
if (!loadXmlScene((const char*)file.path().string().c_str(), &scene)) if (!loadXmlScene((const char*)file.path().string().c_str(), &scene))
continue; continue;
scenes.try_emplace(scene.id, std::make_shared<SceneData>(scene)); scenes.try_emplace(scene.id, std::make_unique<SceneData>(scene));
} }
return true; return true;
} }
@ -76,7 +77,7 @@ bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
ERROR_LOG("Player element not found in scene! File: {}", xmlFile); ERROR_LOG("Player element not found in scene! File: {}", xmlFile);
EntityData playData; EntityData playData;
const char *graphic, *weaponName = "pistolGun"; const char *graphic, *weaponName = "pistol";
if (playerElement->QueryIntAttribute("x", &playData.x) != tinyxml2::XML_SUCCESS || if (playerElement->QueryIntAttribute("x", &playData.x) != tinyxml2::XML_SUCCESS ||
playerElement->QueryIntAttribute("y", &playData.y) != tinyxml2::XML_SUCCESS) playerElement->QueryIntAttribute("y", &playData.y) != tinyxml2::XML_SUCCESS)
@ -95,7 +96,7 @@ bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
else else
{ {
playData.animated = true; playData.animated = true;
if (anim->QueryStringAttribute("name", &graphic) != tinyxml2::XML_SUCCESS) if (anim->QueryStringAttribute("id", &graphic) != tinyxml2::XML_SUCCESS)
ERROR_LOG("Could not find 'name' attribute in 'animation' tag. File: {}", xmlFile); ERROR_LOG("Could not find 'name' attribute in 'animation' tag. File: {}", xmlFile);
} }
playData.isPlayer = true; playData.isPlayer = true;
@ -111,7 +112,7 @@ bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
for (tinyxml2::XMLElement* e = entities->FirstChildElement("entity"); e != NULL; e = e->NextSiblingElement("entity")) for (tinyxml2::XMLElement* e = entities->FirstChildElement("entity"); e != NULL; e = e->NextSiblingElement("entity"))
{ {
EntityData data; EntityData data;
const char *graphic, *weaponName = "pistolGun", *scriptPath; const char *graphic, *weaponName = "pistol", *scriptPath;
if (e->QueryIntAttribute("x", &data.x) != tinyxml2::XML_SUCCESS || if (e->QueryIntAttribute("x", &data.x) != tinyxml2::XML_SUCCESS ||
e->QueryIntAttribute("y", &data.y) != tinyxml2::XML_SUCCESS) e->QueryIntAttribute("y", &data.y) != tinyxml2::XML_SUCCESS)
ERROR_LOG("Could not load position coordinates for entity. File: {}", xmlFile); ERROR_LOG("Could not load position coordinates for entity. File: {}", xmlFile);
@ -129,7 +130,7 @@ bool XMLLoader::loadEntityData(const char* xmlFile, SceneData* out)
else else
{ {
data.animated = true; data.animated = true;
if (anim->QueryStringAttribute("name", &graphic) != tinyxml2::XML_SUCCESS) if (anim->QueryStringAttribute("id", &graphic) != tinyxml2::XML_SUCCESS)
continue; continue;
} }
tinyxml2::XMLElement* script = e->FirstChildElement("script"); tinyxml2::XMLElement* script = e->FirstChildElement("script");
@ -198,7 +199,7 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
if (anim) if (anim)
{ {
data.animated = true; data.animated = true;
if (anim->QueryStringAttribute("name", &graphic) != tinyxml2::XML_SUCCESS) if (anim->QueryStringAttribute("id", &graphic) != tinyxml2::XML_SUCCESS)
continue; continue;
if (anim->ChildElementCount() != 0) if (anim->ChildElementCount() != 0)
@ -272,14 +273,15 @@ bool XMLLoader::loadWeapons(const char* weaponFolder)
} }
LOG(DEBUG, "Loaded {} from {}", data.name, file.path().filename().generic_string()); LOG(DEBUG, "Loaded {} from {}", data.name, file.path().filename().generic_string());
weapons.try_emplace(data.name, std::make_shared<WeaponData>(data)); weapons.try_emplace(data.name, std::make_unique<WeaponData>(data));
} }
} }
return (!weapons.empty()); return (!weapons.empty());
} }
/* /*
Load every animation file and store inside of hashmap -> animations, filename is the hash key * Load each animation node and store inside a hashmap by their id. Each object that needs an animation will be given a prefix <type>/<object>.
* Which will be used to look up the corresponding animation
*/ */
bool XMLLoader::loadAnimations(const char* animationFolder) bool XMLLoader::loadAnimations(const char* animationFolder)
{ {
@ -295,35 +297,24 @@ bool XMLLoader::loadAnimations(const char* animationFolder)
if (doc.LoadFile(file.path().generic_string().c_str()) != tinyxml2::XML_SUCCESS) if (doc.LoadFile(file.path().generic_string().c_str()) != tinyxml2::XML_SUCCESS)
continue; continue;
tinyxml2::XMLElement* anims = doc.FirstChildElement("animations"); for (tinyxml2::XMLElement* e = doc.FirstChildElement("animation"); e != NULL; e = e->NextSiblingElement("animation"))
bool directional = false;
anims->QueryBoolAttribute("directional", &directional);
if (anims == NULL)
continue;
for (tinyxml2::XMLElement* e = anims->FirstChildElement("animation"); e != NULL; e = e->NextSiblingElement("animation"))
{ {
AnimationData animData; AnimationData animData;
const char *name, *type, *spriteAtlas; const char *id, *spriteAtlas;
if (e->QueryStringAttribute("name", &name) != tinyxml2::XML_SUCCESS || if (e->QueryStringAttribute("id", &id) != tinyxml2::XML_SUCCESS)
e->QueryStringAttribute("type", &type) != tinyxml2::XML_SUCCESS)
continue; continue;
tinyxml2::XMLElement* fps = e->FirstChildElement("FPS"); if (e->QueryStringAttribute("atlas", &spriteAtlas) != tinyxml2::XML_SUCCESS ||
fps->QueryFloatText(&animData.FPS); e->QueryFloatAttribute("frameSize", &animData.frameSize) != tinyxml2::XML_SUCCESS)
tinyxml2::XMLElement* sprite = e->FirstChildElement("sprite");
if (sprite->QueryStringAttribute("path", &spriteAtlas) != tinyxml2::XML_SUCCESS ||
sprite->QueryFloatAttribute("frameSize", &animData.frameSize) != tinyxml2::XML_SUCCESS)
continue; continue;
animData.name = name; e->QueryFloatAttribute("FPS", &animData.FPS);
animData.type = type; e->QueryBoolAttribute("directional", &animData.directional);
animData.id = id;
animData.spriteAtlas = spriteAtlas; animData.spriteAtlas = spriteAtlas;
animData.animSet = file.path().stem().string(); animations.try_emplace(animData.id, std::make_unique<AnimationData>(animData));
animData.directional = directional;
animations.try_emplace(animData.name, std::make_shared<AnimationData>(animData));
} }
} }
return true; return true;
@ -395,7 +386,7 @@ bool XMLLoader::loadTileSets(const char* tileSetFolder)
tileSetData.file = file.path().parent_path().string() + "/" + std::string(setFile); tileSetData.file = file.path().parent_path().string() + "/" + std::string(setFile);
std::string key = folder.filename().string() + "/" + file.path().filename().string(); std::string key = folder.filename().string() + "/" + file.path().filename().string();
tileSets.try_emplace(key, std::make_shared<TileSetData>(tileSetData)); tileSets.try_emplace(key, std::make_unique<TileSetData>(tileSetData));
} }
return true; return true;
} }
@ -589,7 +580,7 @@ bool XMLLoader::loadMaps(const char* mapFolder)
mapData.name = file.path().stem().string(); mapData.name = file.path().stem().string();
maps.try_emplace(mapData.name, std::make_shared<MapData>(mapData)); maps.try_emplace(mapData.name, std::make_unique<MapData>(mapData));
} }
return true; return true;
} }