Compare commits

..

No commits in common. "render-logic-refactor-WIP" and "master" have entirely different histories.

5 changed files with 43 additions and 239 deletions

View file

@ -7,10 +7,9 @@
#include <string>
#include <unordered_map>
#include "utility/xmlloader.h"
#include "utility/direction.h"
#include "graphics/sprite.h"
class SpriteAtlas;
class ResourceManager;
class EventManager;
@ -19,66 +18,8 @@ class EventManager;
// name of the animation,
// type of animation ie. idle animation, directional, etc.
// 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
{
public:
@ -123,29 +64,44 @@ private:
void singleDraw();
void directionalDraw(Direction dir);
};
*/
// We will load our animation component with every loaded animation,
// this will be the handler for every animation an entity uses
class AnimationSystem
class AnimationSet : public std::enable_shared_from_this<AnimationSet>
{
public:
AnimationSystem(std::weak_ptr<ResourceManager> resourceManger, std::weak_ptr<EventManager> eventManager);
// animID is the first two elements in the ID <TYPE>/<OBJ>. The prefix
bool registerComponent(const int entityID, const std::string& animID);
AnimationSet(const int& entityid);
AnimationSet(const int& entityid, ResourceManager* resourceManager, std::vector<AnimationData*> animSet);
AnimationSet(const int& entityid, std::unordered_map<std::string, std::unique_ptr<Animation>> animations);
void update();
Animation* operator [](std::string animType) { return anims[animType].get(); }
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();
~AnimationSystem();
void play() { curAnim->play(); }
void stop() { curAnim->stop(); }
void setFacingDir(Direction& dir) { facing = dir; }
void attachEventManager(std::weak_ptr<EventManager> e);
private:
int entityid;
bool isDirectional;
void registerEvents(AnimationComponent *component);
Direction facing = Direction::Down;
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<ResourceManager> resourceManager;
};
#endif // _H_ANIMATION_H

View file

@ -44,13 +44,14 @@ public:
std::unique_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 SceneData *loadScene(const std::string &id);
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
Shader *getShaderByID(unsigned int ID);

View file

@ -1,165 +1,10 @@
#include "graphics/animation.h"
#include "graphics/sprite.h"
#include "utility/xmlloader.h"
#include "utility/resourcemanager.h"
#include "utility/events.h"
#include "utility/logger.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) :
spriteAtlas(resourceManager->loadSpriteAtlas(animData->spriteAtlas, animData->frameSize, animData->directional)),
FPS(animData->FPS),

View file

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

View file

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