Compare commits
1 commit
master
...
render-log
| Author | SHA1 | Date | |
|---|---|---|---|
| 961efc3b67 |
5 changed files with 239 additions and 43 deletions
|
|
@ -7,9 +7,10 @@
|
|||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "utility/xmlloader.h"
|
||||
#include "utility/direction.h"
|
||||
#include "graphics/sprite.h"
|
||||
|
||||
class SpriteAtlas;
|
||||
class ResourceManager;
|
||||
class EventManager;
|
||||
|
||||
|
|
@ -18,8 +19,66 @@ 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:
|
||||
|
|
@ -64,44 +123,29 @@ 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 AnimationSet : public std::enable_shared_from_this<AnimationSet>
|
||||
class AnimationSystem
|
||||
{
|
||||
public:
|
||||
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);
|
||||
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);
|
||||
|
||||
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 update();
|
||||
void draw();
|
||||
|
||||
void play() { curAnim->play(); }
|
||||
void stop() { curAnim->stop(); }
|
||||
|
||||
void setFacingDir(Direction& dir) { facing = dir; }
|
||||
|
||||
void attachEventManager(std::weak_ptr<EventManager> e);
|
||||
~AnimationSystem();
|
||||
|
||||
private:
|
||||
int entityid;
|
||||
bool isDirectional;
|
||||
|
||||
Direction facing = Direction::Down;
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<Animation>> anims;
|
||||
Animation* curAnim;
|
||||
void registerEvents(AnimationComponent *component);
|
||||
|
||||
std::vector<std::unique_ptr<AnimationComponent>> animComponents;
|
||||
std::weak_ptr<EventManager> eventManager;
|
||||
std::weak_ptr<ResourceManager> resourceManager;
|
||||
};
|
||||
|
||||
#endif // _H_ANIMATION_H
|
||||
|
|
|
|||
|
|
@ -44,14 +44,13 @@ 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);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,165 @@
|
|||
#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),
|
||||
|
|
|
|||
|
|
@ -106,11 +106,8 @@ const SceneData *ResourceManager::loadScene(const std::string &id) {
|
|||
return xmlLoader->getSceneData(id);
|
||||
}
|
||||
|
||||
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);
|
||||
const std::vector<AnimationData*> ResourceManager::loadAnimationSet(const std::string &prefix) {
|
||||
return xmlLoader->getAnimationSet(prefix);
|
||||
}
|
||||
|
||||
void ResourceManager::clearResources() {
|
||||
|
|
|
|||
|
|
@ -220,17 +220,18 @@ 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 (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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
try {
|
||||
// So if we look for the animation tag and there is no monster definition
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue