After a long hiatus, doing this major refactor is just not in the cards

right now
This commit is contained in:
Ethan 2025-05-31 11:47:31 -04:00
parent 43bbc9e21d
commit 961efc3b67
5 changed files with 239 additions and 43 deletions

View file

@ -7,9 +7,10 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include "utility/xmlloader.h"
#include "utility/direction.h" #include "utility/direction.h"
#include "graphics/sprite.h"
class SpriteAtlas;
class ResourceManager; class ResourceManager;
class EventManager; class EventManager;
@ -18,8 +19,66 @@ class EventManager;
// name of the animation, // name of the animation,
// type of animation ie. idle animation, directional, etc. // type of animation ie. idle animation, directional, etc.
// directory of the animation atlas containing the frames // directory of the animation atlas containing the frames
struct AnimationData;
struct Animation {
const AnimationData *data;
SpriteAtlas *spriteAtlas;
bool playing;
float FPS;
unsigned int elapsedTime = 0;
unsigned int lastFrameTick = 0;
unsigned int currentFrame;
int cycles;
Direction facingDir;
void reset() {
elapsedTime = 0;
lastFrameTick = 0;
currentFrame = 0;
};
void bind() {
spriteAtlas->bind();
}
void tick() {
Uint32 currentTime = SDL_GetTicks();
elapsedTime = currentTime - lastFrameTick;
if (elapsedTime >= 1000.0f / FPS) {
if (++currentFrame > spriteAtlas->size() - 1) {
currentFrame = 0;
cycles += 1;
}
lastFrameTick = currentTime;
}
}
void draw() {
if (playing) {
tick();
} else if (!data->directional) {
currentFrame = 0;
}
auto frame = (data->directional) ?
spriteAtlas->frame(currentFrame, facingDir) :
spriteAtlas->frame(currentFrame);
spriteAtlas->bindFrame(&frame);
spriteAtlas->draw();
}
};
struct AnimationComponent {
int entityID;
// anim-id animation
std::unordered_map<std::string, std::unique_ptr<Animation>> anims;
Animation *curAnim;
};
/*
class Animation class Animation
{ {
public: public:
@ -64,44 +123,29 @@ private:
void singleDraw(); void singleDraw();
void directionalDraw(Direction dir); void directionalDraw(Direction dir);
}; };
*/
// We will load our animation component with every loaded animation, // We will load our animation component with every loaded animation,
// this will be the handler for every animation an entity uses // this will be the handler for every animation an entity uses
class AnimationSet : public std::enable_shared_from_this<AnimationSet> class AnimationSystem
{ {
public: public:
AnimationSet(const int& entityid); AnimationSystem(std::weak_ptr<ResourceManager> resourceManger, std::weak_ptr<EventManager> eventManager);
AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<AnimationData*> animSet); // animID is the first two elements in the ID <TYPE>/<OBJ>. The prefix
AnimationSet(const int& entityid, std::unordered_map<std::string, std::unique_ptr<Animation>> animations); bool registerComponent(const int entityID, const std::string& animID);
Animation* operator [](std::string animType) { return anims[animType].get(); } void update();
void addAnimation(std::unique_ptr<Animation> anim) { std::string type = anim->getType(); anims.try_emplace(type, std::move(anim)); }
void setAnimation(const std::string& animType) { curAnim = anims[animType].get(); }
const int getEntityID() const { return entityid; }
const bool getDirectional() const { return isDirectional; }
void bind();
void draw(); void draw();
void play() { curAnim->play(); } ~AnimationSystem();
void stop() { curAnim->stop(); }
void setFacingDir(Direction& dir) { facing = dir; }
void attachEventManager(std::weak_ptr<EventManager> e);
private: private:
int entityid;
bool isDirectional;
Direction facing = Direction::Down; void registerEvents(AnimationComponent *component);
std::unordered_map<std::string, std::unique_ptr<Animation>> anims;
Animation* curAnim;
std::vector<std::unique_ptr<AnimationComponent>> animComponents;
std::weak_ptr<EventManager> eventManager; std::weak_ptr<EventManager> eventManager;
std::weak_ptr<ResourceManager> resourceManager;
}; };
#endif // _H_ANIMATION_H #endif // _H_ANIMATION_H

View file

@ -44,14 +44,13 @@ public:
std::unique_ptr<Weapon> loadWeapon(const std::string &name, std::unique_ptr<Weapon> loadWeapon(const std::string &name,
const unsigned weaponShaderID, const unsigned weaponShaderID,
const unsigned bulletShaderID); const unsigned bulletShaderID);
std::shared_ptr<AnimationSet> loadAnimationSet(const std::string &name,
int entityid = 0);
const unsigned loadShader(const std::string &name, const unsigned loadShader(const std::string &name,
const std::string &vertexPath, const std::string &vertexPath,
const std::string &fragPath); const std::string &fragPath);
const SceneData *loadScene(const std::string &id); const SceneData *loadScene(const std::string &id);
const TileSetData *loadTileSet(const std::string &name); const TileSetData *loadTileSet(const std::string &name);
const std::vector<AnimationData*>loadAnimationSet(const std::string &id);
// 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);

View file

@ -1,10 +1,165 @@
#include "graphics/animation.h" #include "graphics/animation.h"
#include "graphics/sprite.h"
#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 "utility/logger.h"
#include "util.h" #include "util.h"
AnimationSystem::AnimationSystem(std::weak_ptr<ResourceManager> resMan, std::weak_ptr<EventManager> eventMan)
{
eventManager = eventMan;
resourceManager = resMan;
}
/* TODO: UPDATES AND DRAWS, maybe remove the draw entirely and forward specific frame data to the renderer?? */
void AnimationSystem::update()
{
}
bool AnimationSystem::registerComponent(const int entityID, const std::string& animID)
{
if (auto res = resourceManager.lock()) {
auto animSet = res->loadAnimationSet(animID);
if (animSet.empty()) {
LOG(ERROR, "No animations with prefix '{}' found!", animID);
return false;
}
auto animComp = std::make_unique<AnimationComponent>();
animComp->entityID = entityID;
for (const auto& data : animSet) {
auto atlas = res->loadSpriteAtlas(data->id, data->frameSize);
auto type = UTIL::get_type(data->id);
if (atlas == nullptr) continue;
std::unique_ptr<Animation> anim = std::make_unique<Animation>();
anim->spriteAtlas = atlas;
anim->data = data;
anim->playing = false;
anim->FPS = data->FPS;
animComp->anims[type] = std::move(anim);
if (type == "idle") {
// Given this entity has an idle animation, we will have the entity animate off the hop.
animComp->curAnim->playing = true;
animComp->curAnim = animComp->anims[type].get();
}
}
// If the set does not contain an idle animation we will just set the current animation to the top of the set
if (animComp->curAnim == nullptr) {
animComp->curAnim = animComp->anims[UTIL::get_type(animSet[0]->id)].get();
if (animComp->curAnim == nullptr) {
LOG(ERROR, "Could not load any sprites for animation set '{}'", animID);
return false;
}
}
animComponents.push_back(std::move(animComp));
registerEvents(animComponents.back().get());
} else {
LOG(ERROR, "Could not obtain resource manager!", NULL);
return false;
}
return true;
}
void AnimationSystem::registerEvents(AnimationComponent *comp)
{
if (auto event = eventManager.lock()) {
event->subscribe<DirectionChangeEvent>([comp](const DirectionChangeEvent& e) {
if (comp) {
if (e.entityid == comp->entityID) {
Direction d = e.direction;
comp->curAnim->facingDir = d;
}
}
});
event->subscribe<EntityMoveEvent>([comp](const EntityMoveEvent& e) {
if (comp) {
if (e.entityid == comp->entityID)
{
if (comp->curAnim->data->directional)
{
if (comp->anims["move"] != NULL)
comp->curAnim = comp->anims["move"].get();
}
else
comp->curAnim->playing = true;
}
}
});
event->subscribe<EntityStopEvent>([comp](const EntityStopEvent& e) {
if (comp) {
if (e.entityid == comp->entityID)
{
if (comp->curAnim->data->directional)
{
if (comp->anims["idle"] != NULL)
comp->curAnim = comp->anims["idle"].get();
}
else
comp->curAnim->playing = false;
}
}
});
event->subscribe<EntityReloadEvent>([comp](const EntityReloadEvent& e) {
if (comp) {
if (e.entityid == comp->entityID)
{
if (comp->anims["reload"] != NULL)
{
comp->curAnim->reset();
comp->curAnim = comp->anims["reload"].get();
comp->curAnim->reset();
}
}
}
});
event->subscribe<EntityFinishReloadEvent>([comp](const EntityFinishReloadEvent& e) {
if (comp) {
if (e.entityid == comp->entityID)
{
if (comp->anims["idle"] != NULL) {
comp->curAnim->reset();
comp->curAnim = comp->anims["idle"].get();
comp->curAnim->reset();
}
}
}
});
event->subscribe<EntityFireEvent>([comp](const EntityFireEvent& e) {
if (comp) {
if (e.entityid == comp->entityID)
{
if (comp->anims["fire"] != NULL)
{
comp->curAnim = comp->anims["fire"].get();
comp->curAnim->reset();
float newFPS = (1000.f / e.fireDelay) * 15.f;
comp->curAnim->FPS = newFPS;
}
}
}
});
event->subscribe<AnimationFinishedEvent>([comp](const AnimationFinishedEvent& e) {
if (comp) {
if (e.entityid == comp->entityID && e.animType == "fire")
{
if (comp->anims["idle"] != NULL)
comp->curAnim = comp->anims["idle"].get();
}
}
});
}
Animation::Animation(const AnimationData* animData, ResourceManager* resourceManager) : Animation::Animation(const AnimationData* animData, ResourceManager* resourceManager) :
spriteAtlas(resourceManager->loadSpriteAtlas(animData->spriteAtlas, animData->frameSize, animData->directional)), spriteAtlas(resourceManager->loadSpriteAtlas(animData->spriteAtlas, animData->frameSize, animData->directional)),
FPS(animData->FPS), FPS(animData->FPS),

View file

@ -106,11 +106,8 @@ const SceneData *ResourceManager::loadScene(const std::string &id) {
return xmlLoader->getSceneData(id); return xmlLoader->getSceneData(id);
} }
std::shared_ptr<AnimationSet> const std::vector<AnimationData*> ResourceManager::loadAnimationSet(const std::string &prefix) {
ResourceManager::loadAnimationSet(const std::string &prefix, int entityid) { return xmlLoader->getAnimationSet(prefix);
auto animSetData = xmlLoader->getAnimationSet(prefix);
return std::make_shared<AnimationSet>(entityid, this, animSetData);
} }
void ResourceManager::clearResources() { void ResourceManager::clearResources() {

View file

@ -220,17 +220,18 @@ bool XMLLoader::loadEntityData(const char *xmlFile, SceneData *out) {
ERROR_LOG("Could not load position coordinates for entity. File: {}", ERROR_LOG("Could not load position coordinates for entity. File: {}",
xmlFile); xmlFile);
e->QueryStringAttribute("weapon", &weaponName); e->QueryStringAttribute("weapon", &weaponName);
e->QueryStringAttribute("monster_id", &monsterDef);
// If we find that the entity has a monster definition we will fill in the // If we find that the entity has a monster definition we will fill in the
// defaults Having a monster definition means we must be animated by default // defaults Having a monster definition means we must be animated by default
// and we will prefer the animated default for now. // and we will prefer the animated default for now.
if (monsterDef != NULL && monsters[monsterDef] != NULL) { if (e->QueryStringAttribute("monster_id", &monsterDef) == tinyxml2::XML_SUCCESS) {
// Setting up the defaults if (monsters[monsterDef]) {
data.animated = true; // Setting up the defaults
data.monsterDef = monsterDef; data.animated = true;
weaponID = monsters[monsterDef]->weapon.c_str(); data.monsterDef = monsterDef;
graphic = monsters[monsterDef]->anim.c_str(); weaponID = monsters[monsterDef]->weapon.c_str();
scriptID = monsters[monsterDef]->behaviour.c_str(); graphic = monsters[monsterDef]->anim.c_str();
scriptID = monsters[monsterDef]->behaviour.c_str();
}
} }
try { try {
// So if we look for the animation tag and there is no monster definition // So if we look for the animation tag and there is no monster definition