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 <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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue