diff options
Diffstat (limited to 'src/animatedsprite.cpp')
-rw-r--r-- | src/animatedsprite.cpp | 408 |
1 files changed, 97 insertions, 311 deletions
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index c2f7f133..46369c80 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -34,381 +34,167 @@ #include "utils/xml.h" -AnimatedSprite::AnimatedSprite(const std::string& animationFile, int variant): - mAction(NULL), +#include <cassert> + +AnimatedSprite::AnimatedSprite(SpriteDef *sprite): mDirection(DIRECTION_DOWN), - mLastTime(0) + mLastTime(0), + mFrameIndex(0), + mFrameTime(0), + mSprite(sprite), + mAction(0), + mAnimation(0), + mFrame(0) { - int size; - ResourceManager *resman = ResourceManager::getInstance(); - char *data = (char*)resman->loadFile(animationFile.c_str(), size); - - if (!data) { - logger->error("Animation: Could not find " + animationFile + "!"); - } - - xmlDocPtr doc = xmlParseMemory(data, size); - free(data); - - if (!doc) { - logger->error( - "Animation: Error while parsing animation definition file!"); - } - - xmlNodePtr node = xmlDocGetRootElement(doc); - if (!node || !xmlStrEqual(node->name, BAD_CAST "sprite")) { - logger->error( - "Animation: this is not a valid animation definition file!"); - } - - // Get the variant - int variant_num = XML::getProperty(node, "variants", 0); - int variant_offset = XML::getProperty(node, "variant_offset", 0); - - if (variant_num > 0 && variant < variant_num ) { - variant_offset *= variant; - } else { - variant_offset = 0; - } + assert(mSprite); - for (node = node->xmlChildrenNode; node != NULL; node = node->next) - { - if (xmlStrEqual(node->name, BAD_CAST "imageset")) - { - int width = XML::getProperty(node, "width", 0); - int height = XML::getProperty(node, "height", 0); - std::string name = XML::getProperty(node, "name", ""); - std::string imageSrc = XML::getProperty(node, "src", ""); - - Spriteset *spriteset = - resman->getSpriteset(imageSrc, width, height); - - if (!spriteset) { - logger->error("Couldn't load spriteset!"); - } - - mSpritesets[name] = spriteset; - } - // get action - else if (xmlStrEqual(node->name, BAD_CAST "action")) - { - std::string actionName = XML::getProperty(node, "name", ""); - std::string imagesetName = XML::getProperty(node, "imageset", ""); - - SpritesetIterator si = mSpritesets.find(imagesetName); - if (si == mSpritesets.end()) { - logger->log("Warning: imageset \"%s\" not defined in %s", - imagesetName.c_str(), - animationFile.c_str()); - - // skip loading animations - continue; - } - Spriteset *imageset = si->second; - - SpriteAction actionType = makeSpriteAction(actionName); - if (actionType == ACTION_INVALID) - { - logger->log("Warning: Unknown action \"%s\" defined in %s", - actionName.c_str(), - animationFile.c_str()); - continue; - } - Action *action = new Action(); - mActions[actionType] = action; - - // When first action set it as default direction - if (mActions.empty()) - { - mActions[ACTION_DEFAULT] = action; - } - - - // get animations - for (xmlNodePtr animationNode = node->xmlChildrenNode; - animationNode != NULL; - animationNode = animationNode->next) - { - // We're only interested in animations - if (!xmlStrEqual(animationNode->name, BAD_CAST "animation")) - continue; - - std::string directionName = - XML::getProperty(animationNode, "direction", ""); - SpriteDirection directionType = - makeSpriteDirection(directionName); - - if (directionType == DIRECTION_INVALID) - { - logger->log("Warning: Unknown direction \"%s\" defined " - "for action %s in %s", - directionName.c_str(), - actionName.c_str(), - animationFile.c_str()); - continue; - } - - Animation *animation = new Animation(); - action->setAnimation(directionType, animation); - - // Get animation phases - for (xmlNodePtr phaseNode = animationNode->xmlChildrenNode; - phaseNode != NULL; - phaseNode = phaseNode->next) - { - int delay = XML::getProperty(phaseNode, "delay", 0); - - if (xmlStrEqual(phaseNode->name, BAD_CAST "frame")) - { - int index = XML::getProperty(phaseNode, "index", -1); - int offsetX = XML::getProperty(phaseNode, "offsetX", 0); - int offsetY = XML::getProperty(phaseNode, "offsetY", 0); - - offsetY -= imageset->getHeight() - 32; - offsetX -= imageset->getWidth() / 2 - 16; - Image *img = imageset->get(index + variant_offset); - animation->addPhase(img, delay, offsetX, offsetY); - } - else if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence")) - { - int start = XML::getProperty(phaseNode, "start", 0); - int end = XML::getProperty(phaseNode, "end", 0); - int offsetY = -imageset->getHeight() + 32; - int offsetX = -imageset->getWidth() / 2 + 16; - while (end >= start) - { - Image *img = imageset->get(start + variant_offset); - animation->addPhase(img, delay, offsetX, offsetY); - start++; - } - } - else if (xmlStrEqual(phaseNode->name, BAD_CAST "end")) - { - animation->addTerminator(); - } - } // for phaseNode - } // for animationNode - } // if "<imageset>" else if "<action>" - } // for node - - // Complete missing actions - substituteAction(ACTION_STAND, ACTION_DEFAULT); - substituteAction(ACTION_WALK, ACTION_STAND); - substituteAction(ACTION_WALK, ACTION_RUN); - substituteAction(ACTION_ATTACK, ACTION_STAND); - substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK); - substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING); - substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB); - substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING); - substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING); - substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC); - substituteAction(ACTION_SIT, ACTION_STAND); - substituteAction(ACTION_SLEEP, ACTION_SIT); - substituteAction(ACTION_HURT, ACTION_STAND); - substituteAction(ACTION_DEAD, ACTION_HURT); + // Take possession of the sprite + mSprite->incRef(); // Play the stand animation by default play(ACTION_STAND); - - xmlFreeDoc(doc); } -void -AnimatedSprite::substituteAction(SpriteAction complete, - SpriteAction with) +AnimatedSprite::AnimatedSprite(const std::string& filename, int variant): + mDirection(DIRECTION_DOWN), + mLastTime(0), + mFrameIndex(0), + mFrameTime(0), + mAnimation(0), + mFrame(0) { - if (mActions.find(complete) == mActions.end()) - { - ActionIterator i = mActions.find(with); - if (i != mActions.end()) { - mActions[complete] = i->second; - } - } + ResourceManager *resman = ResourceManager::getInstance(); + mSprite = resman->getSprite(filename, variant); + assert(mSprite); + + // Play the stand animation by default + play(ACTION_STAND); } AnimatedSprite::~AnimatedSprite() { - for (SpritesetIterator i = mSpritesets.begin(); i != mSpritesets.end(); ++i) - { - i->second->decRef(); - } - mSpritesets.clear(); + mSprite->decRef(); } void AnimatedSprite::reset() { - // Reset all defined actions (because of aliases some will be resetted - // multiple times, but this doesn't matter) - for (ActionIterator i = mActions.begin(); i != mActions.end(); ++i) - { - if (i->second) - { - i->second->reset(); - } - } + mFrameIndex = 0; + mFrameTime = 0; + mLastTime = 0; } void -AnimatedSprite::play(SpriteAction action) +AnimatedSprite::play(SpriteAction spriteAction) { - ActionIterator i = mActions.find(action); - - if (i == mActions.end()) + Action *action = mSprite->getAction(spriteAction); + if (!action) { - logger->log("Warning: no action \"%u\" defined!", action); - mAction = NULL; return; } - if (mAction != i->second) + mAction = action; + Animation *animation = mAction->getAnimation(mDirection); + + if (animation && animation != mAnimation && animation->getLength() > 0) { - mAction = i->second; - //mAction->reset(); + mAnimation = animation; + mFrame = mAnimation->getFrame(0); + + reset(); } } void AnimatedSprite::update(int time) { - bool finished = false; // Avoid freaking out at first frame or when tick_time overflows if (time < mLastTime || mLastTime == 0) + { mLastTime = time; + } // If not enough time has passed yet, do nothing - if (time > mLastTime && mAction) + if (time <= mLastTime || !mAnimation) { - Animation *animation = mAction->getAnimation(mDirection); - if (animation != NULL) { - finished = !animation->update((unsigned int)(time - mLastTime)); - } - mLastTime = time; + return; } - if (finished) + unsigned int dt = time - mLastTime; + mLastTime = time; + + if (!updateCurrentAnimation(dt)) { + // Animation finished, reset to default play(ACTION_STAND); } } bool -AnimatedSprite::draw(Graphics* graphics, Sint32 posX, Sint32 posY) const +AnimatedSprite::updateCurrentAnimation(unsigned int time) { - const AnimationPhase *phase = getCurrentPhase(); - if (!phase || !phase->image) + if (!mFrame || Animation::isTerminator(*mFrame)) { return false; } - Sint32 offsetX = phase->offsetX; - Sint32 offsetY = phase->offsetY; - return graphics->drawImage(phase->image, posX + offsetX, posY + offsetY); -} + mFrameTime += time; -int -AnimatedSprite::getWidth() const -{ - const AnimationPhase *phase = getCurrentPhase(); - return (phase && phase->image) ? phase->image->getWidth() : 0; -} + while (mFrameTime > mFrame->delay && mFrame->delay > 0) + { + mFrameTime -= mFrame->delay; + mFrameIndex++; -int -AnimatedSprite::getHeight() const -{ - const AnimationPhase *phase = getCurrentPhase(); - return (phase && phase->image) ? phase->image->getHeight() : 0; -} + if (mFrameIndex == mAnimation->getLength()) + { + mFrameIndex = 0; + } -const AnimationPhase* -AnimatedSprite::getCurrentPhase() const -{ - if (!mAction) - { - return NULL; - } + mFrame = mAnimation->getFrame(mFrameIndex); - Animation *animation = mAction->getAnimation(mDirection); - if (animation == NULL) - { - return NULL; + if (Animation::isTerminator(*mFrame)) + { + mAnimation = 0; + mFrame = 0; + return false; + } } - return animation->getCurrentPhase(); + return true; } -SpriteAction -AnimatedSprite::makeSpriteAction(const std::string& action) +bool +AnimatedSprite::draw(Graphics* graphics, int posX, int posY) const { - if (action == "" || action == "default") { - return ACTION_DEFAULT; - } - if (action == "stand") { - return ACTION_STAND; - } - else if (action == "walk") { - return ACTION_WALK; - } - else if (action == "run") { - return ACTION_RUN; - } - else if (action == "attack") { - return ACTION_ATTACK; - } - else if (action == "attack_swing") { - return ACTION_ATTACK_SWING; - } - else if (action == "attack_stab") { - return ACTION_ATTACK_STAB; - } - else if (action == "attack_bow") { - return ACTION_ATTACK_BOW; - } - else if (action == "attack_throw") { - return ACTION_ATTACK_THROW; - } - else if (action == "cast_magic") { - return ACTION_CAST_MAGIC; - } - else if (action == "use_item") { - return ACTION_USE_ITEM; - } - else if (action == "sit") { - return ACTION_SIT; - } - else if (action == "sleep") { - return ACTION_SLEEP; - } - else if (action == "hurt") { - return ACTION_HURT; - } - else if (action == "dead") { - return ACTION_DEAD; - } - else { - return ACTION_INVALID; + if (!mFrame || !mFrame->image) + { + return false; } + + return graphics->drawImage(mFrame->image, + posX + mFrame->offsetX, + posY + mFrame->offsetY); } -SpriteDirection -AnimatedSprite::makeSpriteDirection(const std::string& direction) +void +AnimatedSprite::setDirection(SpriteDirection direction) { - if (direction == "" || direction == "default") { - return DIRECTION_DEFAULT; - } - else if (direction == "up") { - return DIRECTION_UP; - } - else if (direction == "left") { - return DIRECTION_LEFT; - } - else if (direction == "right") { - return DIRECTION_RIGHT; - } - else if (direction == "down") { - return DIRECTION_DOWN; + if (mDirection != direction) + { + mDirection = direction; + + if (!mAction) + { + return; + } + + Animation *animation = mAction->getAnimation(mDirection); + + if (animation && animation != mAnimation && animation->getLength() > 0) + { + mAnimation = animation; + mFrame = mAnimation->getFrame(0); + reset(); + } } - else { - return DIRECTION_INVALID; - }; } |