From 0b67aa406e4c19edd9c264ce6f1447aee8ff4c8e Mon Sep 17 00:00:00 2001 From: Robert Špalek Date: Sat, 7 Nov 2009 11:45:13 +0000 Subject: Debugged updating the position of the hero during walking. I project the hero immediately to the end of each edge for the time being though. svn-id: r45722 --- engines/draci/game.cpp | 42 ++++++++++++++-------------- engines/draci/game.h | 13 ++++++--- engines/draci/script.cpp | 7 ++++- engines/draci/walking.cpp | 71 ++++++++++++++++++++++++----------------------- engines/draci/walking.h | 5 +++- 5 files changed, 77 insertions(+), 61 deletions(-) diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index dde305d848..f18b2fda32 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -954,18 +954,25 @@ void Game::runDialogueProg(GPL2Program prog, int offset) { deleteAnimationsAfterIndex(lastAnimIndex); } -void Game::playHeroAnimation(int anim_index) { +int Game::playHeroAnimation(int anim_index) { const GameObject *dragon = getObject(kDragonObject); const int current_anim_index = playingObjectAnimation(dragon); - if (anim_index == current_anim_index) { - return; - } - const int animID = dragon->_anim[anim_index]; Animation *anim = _vm->_anims->getAnimation(animID); - stopObjectAnimations(dragon); + + if (anim_index == current_anim_index) { + anim->markDirtyRect(_vm->_screen->getSurface()); + } else { + stopObjectAnimations(dragon); + } positionAnimAsHero(anim); - _vm->_anims->play(animID); + if (anim_index == current_anim_index) { + anim->markDirtyRect(_vm->_screen->getSurface()); + } else { + _vm->_anims->play(animID); + } + + return anim->currentFrameNum(); } void Game::redrawWalkingPath(int id, byte colour, const WalkingPath &path) { @@ -981,12 +988,6 @@ void Game::setHeroPosition(const Common::Point &p) { _hero = p; } -void Game::positionHero(const Common::Point &p, SightDirection dir) { - setHeroPosition(p); - Common::Point mousePos(_vm->_mouse->getPosX(), _vm->_mouse->getPosY()); - playHeroAnimation(WalkingState::animationForSightDirection(dir, _hero, mousePos, WalkingPath())); -} - Common::Point Game::findNearestWalkable(int x, int y) const { Surface *surface = _vm->_screen->getSurface(); return _walkingMap.findNearestWalkable(x, y, surface->getDimensions()); @@ -1493,6 +1494,12 @@ void Game::positionAnimAsHero(Animation *anim) { anim->setScaleFactors(scale, scale); anim->setRelative(p.x, p.y); + + // Clear the animation's shift so that the real sprite stays at place + // regardless of what the current phase is. If the animation starts + // from the beginning, the shift is already [0,0], but if it is in the + // middle, it may be different. + anim->clearShift(); } void Game::positionHeroAsAnim(Animation *anim) { @@ -1502,17 +1509,10 @@ void Game::positionHeroAsAnim(Animation *anim) { // Update our hero coordinates (don't forget that our control point is // elsewhere). + // TODO: what about rounding errors? Drawable *frame = anim->getCurrentFrame(); _hero.x += (int) (anim->getScaleX() * frame->getWidth() / 2); _hero.y += (int) (anim->getScaleY() * frame->getHeight()); - - // Clear the animation's shift so that by updating the coordinates the - // animation will stay in place. - anim->clearShift(); - - // Call the inverse procedure to calculate new scaling factors. - // TODO: what about rounding errors? - positionAnimAsHero(anim); } void Game::pushNewRoom() { diff --git a/engines/draci/game.h b/engines/draci/game.h index d905f68bd8..5414195c6e 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -209,14 +209,19 @@ public: Common::Point findNearestWalkable(int x, int y) const; void heroAnimationFinished() { _walkingState.heroAnimationFinished(); } void stopWalking() { _walkingState.stopWalking(); } // and clear callback - void positionHero(const Common::Point &p, SightDirection dir); // teleport the dragon void walkHero(int x, int y, SightDirection dir); // start walking and leave callback as is void setHeroPosition(const Common::Point &p); - int getHeroX() const { return _hero.x; } - int getHeroY() const { return _hero.y; } + const Common::Point &getHeroPosition() const { return _hero; } void positionAnimAsHero(Animation *anim); void positionHeroAsAnim(Animation *anim); - void playHeroAnimation(int anim_index); + + // Makes sure animation anim_index plays on the hero. If the hero's + // position has changed, it updates the animation position. If the new + // animation is different, it stops the old one and starts the new one, + // otherwise it just marks dirty rectangles for moving the position. + // Returns the current animation phase of the new animation (usually 0 + // unless the animation hasn't changed). + int playHeroAnimation(int anim_index); int loadAnimation(uint animNum, uint z); void loadOverlays(); diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index f47cda4567..7d9dd4126f 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -664,8 +664,13 @@ void Script::stayOn(Common::Queue ¶ms) { SightDirection dir = static_cast (params.pop()); // Jumps into the given position regardless of the walking map. + Common::Point heroPos(_vm->_game->findNearestWalkable(x, y)); + Common::Point mousePos(_vm->_mouse->getPosX(), _vm->_mouse->getPosY()); + _vm->_game->stopWalking(); - _vm->_game->positionHero(_vm->_game->findNearestWalkable(x, y), dir); + _vm->_game->setHeroPosition(heroPos); + _vm->_game->playHeroAnimation(WalkingState::animationForSightDirection( + dir, heroPos, mousePos, WalkingPath())); } void Script::walkOn(Common::Queue ¶ms) { diff --git a/engines/draci/walking.cpp b/engines/draci/walking.cpp index fed91dd8ef..af64daf522 100644 --- a/engines/draci/walking.cpp +++ b/engines/draci/walking.cpp @@ -457,7 +457,7 @@ void WalkingState::startWalking(const Common::Point &p1, const Common::Point &p2 } // Going to start with the first segment. - _segment = _lastAnimPhase = _position = _length = -1; + _segment = _lastAnimPhase = -1; turnForTheNextSegment(); } @@ -489,13 +489,13 @@ void WalkingState::callback() { bool WalkingState::continueWalking() { const GameObject *dragon = _vm->_game->getObject(kDragonObject); - const Movement anim_index = static_cast (_vm->_game->playingObjectAnimation(dragon)); + const Movement movement = static_cast (_vm->_game->playingObjectAnimation(dragon)); // If the current animation is a turning animation, wait a bit more. // When this animation has finished, heroAnimationFinished() callback // will be called, which starts a new scheduled one, so the code never // gets here if it hasn't finished yet. - if (isTurningMovement(anim_index)) { + if (isTurningMovement(movement)) { return true; } @@ -509,41 +509,51 @@ bool WalkingState::continueWalking() { // Read the dragon's animation's current phase. Determine if it has // changed from the last time. If not, wait until it has. - const int animID = dragon->_anim[anim_index]; + const int animID = dragon->_anim[movement]; Animation *anim = _vm->_anims->getAnimation(animID); const int animPhase = anim->currentFrameNum(); const bool wasUpdated = animPhase != _lastAnimPhase; if (!wasUpdated) { return true; } - _lastAnimPhase = animPhase; - - debugC(3, kDraciWalkingDebugLevel, "Continuing walking in segment %d and position %d/%d", _segment, _position, _length); // We are walking in the middle of an edge. The animation phase has - // just changed. Update the position of the hero. + // just changed. + + // Read the position of the hero from the animation object, and project + // it to the current edge. _vm->_game->positionHeroAsAnim(anim); - // TODO: take the [XY] coordinate determined by the animation, update - // the other one so that the hero stays on the edge, remove _position - // and _length, and instead test reaching the destination by computing - // the scalar product - _position += 4; - // Common::Point newPos = WalkingMap::interpolate( - // _path[_segment], _path[_segment+1], _position, _length); - // _vm->_game->setHeroPosition(newPos); - // _vm->_game->positionAnimAsHero(anim); + const Common::Point &hero = _vm->_game->getHeroPosition(); + Common::Point newHero = hero; + const bool reachedEnd = alignHeroToEdge(_path[_segment], _path[_segment+1], &newHero); + + debugC(3, kDraciWalkingDebugLevel, "Continuing walking in segment %d and position [%d,%d] projected to [%d,%d]", + _segment, hero.x, hero.y, newHero.x, newHero.y); + + // Update the hero position to the projected one. The animation number + // is not changing, so this will just move the sprite and return the + // current frame number. + _vm->_game->setHeroPosition(newHero); + _lastAnimPhase = _vm->_game->playHeroAnimation(movement); // If the hero has reached the end of the edge, start transition to the // next phase. This will increment _segment, either immediately (if no // transition is needed) or in the callback (after the transition is - // done). - if (_position >= _length) { + // done). The position is equal to the end-point of the edge thanks to + // alignHeroToEdge(). + if (reachedEnd) { turnForTheNextSegment(); } return true; } +bool WalkingState::alignHeroToEdge(const Common::Point &p1, const Common::Point &p2, Common::Point *hero) { + // TODO + *hero = p2; + return true; +} + void WalkingState::turnForTheNextSegment() { const GameObject *dragon = _vm->_game->getObject(kDragonObject); const Movement currentAnim = static_cast (_vm->_game->playingObjectAnimation(dragon)); @@ -565,37 +575,30 @@ void WalkingState::turnForTheNextSegment() { anim->registerCallback(&Animation::tellWalkingState); debugC(2, kDraciWalkingDebugLevel, "Starting turning animation %d", transition); + _lastAnimPhase = -1; } } void WalkingState::heroAnimationFinished() { // The hero is turned well for the next line segment or for facing the - // target direction. + // target direction. It is also standing on the right spot thanks to + // the entry condition for turnForTheNextSegment(). - // Start the desired next animation. playHeroAnimation() takes care of - // stopping the current animation. + // Start the desired next animation and retrieve the current animation + // phase. // Don't use any callbacks, because continueWalking() will decide the // end on its own and after walking is done callbacks shouldn't be // called either. It wouldn't make much sense anyway, since the // walking/staying/talking animations are cyclic. Movement nextAnim = directionForNextPhase(); - _vm->_game->playHeroAnimation(nextAnim); - - // Retrieve the current animation phase. Don't just use 0, because we - // cannot assume that nextAnim has just started. If it was already - // playing before, then playHeroAnimation(nextAnim) does nothing. - const GameObject *dragon = _vm->_game->getObject(kDragonObject); - const int animID = dragon->_anim[nextAnim]; - Animation *anim = _vm->_anims->getAnimation(animID); - _lastAnimPhase = anim->currentFrameNum(); + _lastAnimPhase = _vm->_game->playHeroAnimation(nextAnim); debugC(2, kDraciWalkingDebugLevel, "Turned for segment %d, starting animation %d", _segment+1, nextAnim); if (++_segment < (int) (_path.size() - 1)) { // We are on an edge: track where the hero is on this edge. - _position = 0; - _length = WalkingMap::pointsBetween(_path[_segment], _path[_segment+1]); - debugC(2, kDraciWalkingDebugLevel, "Next segment %d has length %d", _segment, _length); + int length = WalkingMap::pointsBetween(_path[_segment], _path[_segment+1]); + debugC(2, kDraciWalkingDebugLevel, "Next segment %d has length %d", _segment, length); } else { // Otherwise we are done. continueWalking() will return false next time. debugC(2, kDraciWalkingDebugLevel, "We have walked the whole path"); diff --git a/engines/draci/walking.h b/engines/draci/walking.h index a3dae88eb7..e2d86a5653 100644 --- a/engines/draci/walking.h +++ b/engines/draci/walking.h @@ -142,7 +142,6 @@ private: SightDirection _dir; int _segment; - int _position, _length; int _lastAnimPhase; const GPL2Program *_callback; @@ -168,6 +167,10 @@ private: static bool isTurningMovement(Movement m) { return m >= kFirstTurning && m <= kLastTurning; } + + // Projects hero to the given edge, but not behind p2. Returns true + // when hero has reached at least p2. + static bool alignHeroToEdge(const Common::Point &p1, const Common::Point &p2, Common::Point *hero); }; } // End of namespace Draci -- cgit v1.2.3