From 19a32074595a4a2797eaeb978f8bd302f736f6a6 Mon Sep 17 00:00:00 2001 From: Andy Date: Thu, 19 Jan 2017 09:14:12 -0500 Subject: Limb animation actually works --- assets/NPC_Sheet.png | Bin 531 -> 763 bytes assets/player/player.png | Bin 0 -> 840 bytes include/components.hpp | 81 ++++++++++++++++++++++++++++++++++++++--------- main.cpp | 4 +-- src/components.cpp | 34 +++++++++++++------- src/player.cpp | 5 ++- src/world.cpp | 40 +++++++++++++++++------ todo.sh | 1 + xml/entities.xml | 32 ++++++++++++++++--- 9 files changed, 152 insertions(+), 45 deletions(-) create mode 100644 assets/player/player.png diff --git a/assets/NPC_Sheet.png b/assets/NPC_Sheet.png index 5537b5e..f0f6530 100644 Binary files a/assets/NPC_Sheet.png and b/assets/NPC_Sheet.png differ diff --git a/assets/player/player.png b/assets/player/player.png new file mode 100644 index 0000000..0f7f13a Binary files /dev/null and b/assets/player/player.png differ diff --git a/include/components.hpp b/include/components.hpp index 8e245a7..9a83d45 100644 --- a/include/components.hpp +++ b/include/components.hpp @@ -232,6 +232,8 @@ struct Sprite { } dim = vec2(ed.x - st.x, ed.y - st.y); + dim.x *= game::HLINE; + dim.y *= game::HLINE; return dim; } @@ -239,12 +241,62 @@ struct Sprite { bool faceLeft; }; -using Limb = std::vector>; +/** + * @struct Limb + * @brief Storage of frames for the limbs of a sprite. + * This will allow us to only update a certain limb. This was we can do mulitple animation types at once. + */ +struct Limb { + Limb() { + } -//TODO + // adds frame to the back of the frame stack + void addFrame(Frame fr) { + frame.push_back(fr); + } + + void nextFrame(Frame& duckmyass, float dt) { + updateCurrent -= dt; + if (updateCurrent <= 0) { + updateCurrent = updateRate; + } else { + return; + } + + + if (index < frame.size() - 1) + index++; + else + index = 0; + + for (auto &d : duckmyass) { + if (d.first.limb == limbID) { + for (auto &fa : frame.at(index)) { + if (fa.first.limb == limbID) { + d.first = fa.first; + d.second = fa.second; + } + } + } + } + + } + + float updateRate; /**< How often we will change each frame. */ + float updateCurrent; /**< How much has been updated in the current frame. */ + uint updateType; /**< What the updateRate will base it's updates off of. + ie: Movement, attacking, jumping. */ + uint limbID; /**< The id of the limb we will be updating */ + + uint index = 0; /**< The current sprite being used for the limb. */ + + std::vector frame; /**< The multiple frames of each limb. */ +}; + +//TODO kill clyne struct Animate { // COMMENT - Limb frame; + std::vector limb; // COMMENT uint index; @@ -253,19 +305,18 @@ struct Animate { } // COMMENT - void nextFrame(Frame sprite) { - if (index < frame.size() - 1) { - index++; - } else { - index = 0; - } - auto fa = frame.at(index); - if (sprite.size() > fa.first-1) - sprite.at(fa.first) = fa.second.at(fa.first); - } - void firstFrame(Frame sprite) { - sprite = frame.at(0).second; + void firstFrame(Frame &sprite) { + (void)sprite; + } + //TODO make updateType an enum + void updateAnimation(uint updateType, Frame& sprite, float dt) { + uint upid = updateType; //^see todo + for (auto &l : limb) { + if (l.updateType == upid) { + l.nextFrame(sprite, dt); + } + } } }; diff --git a/main.cpp b/main.cpp index a9ccac8..f04581a 100644 --- a/main.cpp +++ b/main.cpp @@ -106,9 +106,9 @@ int main(int argc, char *argv[]) // some basic OpenGL setup stuff // - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0); // enable v-sync (TODO but 1000 fps?) - SDL_GL_SetSwapInterval(1); + SDL_GL_SetSwapInterval(0); // hide the cursor SDL_ShowCursor(SDL_DISABLE); // switch to pixel grid diff --git a/src/components.cpp b/src/components.cpp index 7e6f204..3096d39 100644 --- a/src/components.cpp +++ b/src/components.cpp @@ -21,11 +21,12 @@ void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &e position.x += direction.x * dt; position.y += direction.y * dt; - /*if (entity.has_component() && entity.has_component()) { + if (entity.has_component() && entity.has_component()) { auto animate = entity.component(); - entity.component()->sprite = - (direction.x != 0) ? animate->nextFrame() : animate->firstFrame(); - }*/ + auto sprite = entity.component(); + + animate->updateAnimation(1, sprite->sprite, dt); + } if (entity.has_component() && entity.component()->talking) { direction.x = 0; } else { @@ -86,9 +87,11 @@ void RenderSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, float its = 0; float sz; - if (entity.has_component()) { + if (entity.has_component()) sz = entity.component()->width; - } + else + sz = sprite.getSpriteSize().x; + if(sprite.faceLeft) { glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(-1.0f,1.0f,1.0f)); glm::mat4 translate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f - sz - pos.x * 2.0f, 0.0f, 0.0f)); @@ -282,11 +285,16 @@ std::vector developFrame(XMLElement* xml) { Frame tmpf; std::vector tmp; + SpriteData* sd; + + uint limb = 0; vec2 foffset; vec2 fsize; vec2 fdraw; + tmp.clear(); + // this is the xml elements first child. It will only be the tag auto framexml = xml->FirstChildElement(); while (framexml) { @@ -294,7 +302,6 @@ std::vector developFrame(XMLElement* xml) std::string defframe = framexml->Name(); if (defframe == "frame") { tmpf.clear(); - tmp.clear(); // the xml element to parse each src of the frames auto sxml = framexml->FirstChildElement(); while (sxml) { @@ -304,17 +311,22 @@ std::vector developFrame(XMLElement* xml) str2coord(sxml->Attribute("offset")) : vec2(0,0); fdraw = (sxml->Attribute("drawOffset") != nullptr) ? str2coord(sxml->Attribute("drawOffset")) : vec2(0,0); - + if (sxml->Attribute("size") != nullptr) { fsize = str2coord(sxml->Attribute("size")); - tmpf.push_back(std::make_pair(SpriteData(sxml->GetText(), foffset, fsize), fdraw)); + sd = new SpriteData(sxml->GetText(), foffset, fsize); } else { - tmpf.push_back(std::make_pair(SpriteData(sxml->GetText(), foffset), fdraw)); + sd = new SpriteData(sxml->GetText(), foffset); } + if (sxml->QueryUnsignedAttribute("limb", &limb) == XML_NO_ERROR) + sd->limb = limb; + tmpf.push_back(std::make_pair(*sd, fdraw)); } sxml = sxml->NextSiblingElement(); } - tmp.push_back(tmpf); + // we don't want segfault + if (tmpf.size()) + tmp.push_back(tmpf); } // if it's not a frame we don't care diff --git a/src/player.cpp b/src/player.cpp index e83616d..c0710cc 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -9,7 +9,8 @@ static const char *spriteXML = " \ \ - assets/cat.png \ + assets/player/player.png \ + assets/player/player.png\ \ "; @@ -22,14 +23,12 @@ void PlayerSystem::create(void) //player.assign(-0.001f); player.assign(1); player.assign(-0.2f); - auto sprite = player.assign(); XMLDocument xmld; xmld.Parse(spriteXML); auto frame = developFrame(xmld.FirstChildElement("Sprite")); if (frame.size() > 0) sprite->sprite = frame.at(0); - vec2 dim = player.component().get()->getSpriteSize(); float cdat[2] = {dim.x, dim.y}; player.assign(cdat[0], cdat[1]); diff --git a/src/world.cpp b/src/world.cpp index c882256..95bf576 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -350,7 +350,7 @@ void WorldSystem::load(const std::string& file) else dim = entity.component()->getSpriteSize(); - float cdat[2] = {dim.x * game::HLINE, dim.y * game::HLINE}; + float cdat[2] = {dim.x, dim.y}; entity.assign(cdat[0], cdat[1]); } else if (tname == "Direction") { vec2 dir; @@ -390,19 +390,39 @@ void WorldSystem::load(const std::string& file) } else if (tname == "Animation") { auto entan = entity.assign(); auto animx = abcd->FirstChildElement(); - uint idtc = 0; + + uint limbid = 0; + float limbupdate = 0; + uint limbupdatetype = 0; + while (animx) { std::string animType = animx->Name(); if (animType == "movement") { + limbupdatetype = 1; auto limbx = animx->FirstChildElement(); while (limbx) { - auto frames = developFrame(limbx); - if (limbx->UnsignedAttribute("changeID") != XML_NO_ERROR) - idtc = 0; - else - idtc = limbx->UnsignedAttribute("changeID"); - for (const auto& f : frames) { - entan->frame.emplace_back(idtc, f); + std::string limbHopefully = limbx->Name(); + if (limbHopefully == "limb") { + auto frames = developFrame(limbx); + + entan->limb.push_back(Limb()); + entan->limb.back().updateType = limbupdatetype; + + if (limbx->QueryUnsignedAttribute("id", &limbid) == XML_NO_ERROR) { + entan->limb.back().limbID = limbid; + } + if (limbx->QueryFloatAttribute("update", &limbupdate) == XML_NO_ERROR) { + entan->limb.back().updateRate = limbupdate; + } + + // place our newly developed frames in the entities animation stack + for (auto &f : frames) { + entan->limb.back().addFrame(f); + for (auto &fr : entan->limb.back().frame) { + for (auto &sd : fr) + sd.first.limb = limbid; + } + } } limbx = limbx->NextSiblingElement(); } @@ -1160,7 +1180,7 @@ void WorldSystem::detect(entityx::TimeDelta dt) if (!vel.grounded) { vel.grounded = true; game::engine.getSystem()->addMultiple(20, ParticleType::SmallPoof, - [&](){ return vec2(loc.x + randGet() % static_cast(dim.width * game::HLINE), loc.y);}, 500, 30); + [&](){ return vec2(loc.x + randGet() % static_cast(dim.width), loc.y);}, 500, 30); } } } diff --git a/todo.sh b/todo.sh index 5f053a2..e065a76 100755 --- a/todo.sh +++ b/todo.sh @@ -25,3 +25,4 @@ do done echo "Found" $TODO_COUNT "TODOs." +vim TODOS diff --git a/xml/entities.xml b/xml/entities.xml index 23b9358..04faac5 100644 --- a/xml/entities.xml +++ b/xml/entities.xml @@ -11,12 +11,36 @@ - + - assets/NPC.png + assets/NPC_Sheet.png - assets/NPC_Walk.png + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png + + + assets/NPC_Sheet.png @@ -43,7 +67,7 @@ - + -- cgit v1.2.3