From f534c12289cca1152fc57545aeab12d5973720ed Mon Sep 17 00:00:00 2001 From: Robert Špalek Date: Sat, 7 Nov 2009 04:56:28 +0000 Subject: Add helper functions to retrieve dragon position from the animation. To implement proper walking, I have to respect the relative shifts defined by the sprites as opposed to apply some constant velocity. svn-id: r45714 --- engines/draci/animation.cpp | 5 +++++ engines/draci/animation.h | 1 + engines/draci/game.cpp | 30 +++++++++++++++++++++++------- engines/draci/game.h | 1 + engines/draci/walking.cpp | 17 +++++++++++------ engines/draci/walking.h | 2 +- 6 files changed, 42 insertions(+), 14 deletions(-) diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp index 9d56c89674..ffdfa6c1e2 100644 --- a/engines/draci/animation.cpp +++ b/engines/draci/animation.cpp @@ -64,6 +64,11 @@ Displacement Animation::getCurrentFrameDisplacement() const { return dis; } +Common::Point Animation::getCurrentFramePosition() const { + Displacement dis = getCurrentFrameDisplacement(); + return Common::Point(dis.relX, dis.relY); +} + void Animation::setLooping(bool looping) { _looping = looping; debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d", diff --git a/engines/draci/animation.h b/engines/draci/animation.h index 9fd5a87f97..1fe5d4c814 100644 --- a/engines/draci/animation.h +++ b/engines/draci/animation.h @@ -99,6 +99,7 @@ public: int getRelativeY() const { return _displacement.relY; } const Displacement &getDisplacement() const { return _displacement; } // displacement of the whole animation Displacement getCurrentFrameDisplacement() const; // displacement of the current frame (includes _shift) + Common::Point getCurrentFramePosition() const; // with displacement and shift applied int getIndex() const { return _index; } void setIndex(int index) { _index = index; } diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index baaca70508..dde305d848 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -984,7 +984,7 @@ void Game::setHeroPosition(const Common::Point &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())); + playHeroAnimation(WalkingState::animationForSightDirection(dir, _hero, mousePos, WalkingPath())); } Common::Point Game::findNearestWalkable(int x, int y) const { @@ -1477,16 +1477,12 @@ void Game::positionAnimAsHero(Animation *anim) { // Fetch current frame Drawable *frame = anim->getCurrentFrame(); - // Fetch base dimensions of the frame - uint height = frame->getHeight(); - uint width = frame->getWidth(); - // We naturally want the dragon to position its feet to the location of the // click but sprites are drawn from their top-left corner so we subtract // the current height of the dragon's sprite Common::Point p = _hero; - p.x -= (int)(scale * width) / 2; - p.y -= (int)(scale * height); + p.x -= (int)(scale * frame->getWidth() / 2); + p.y -= (int)(scale * frame->getHeight()); // Since _persons[] is used for placing talking text, we use the non-adjusted x value // so the text remains centered over the dragon. @@ -1499,6 +1495,26 @@ void Game::positionAnimAsHero(Animation *anim) { anim->setRelative(p.x, p.y); } +void Game::positionHeroAsAnim(Animation *anim) { + // Check out where the hero has moved to by composing the relative + // shifts of the sprites. + _hero = anim->getCurrentFramePosition(); + + // Update our hero coordinates (don't forget that our control point is + // elsewhere). + 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() { _pushedNewRoom = _newRoom; _pushedNewGate = _newGate; diff --git a/engines/draci/game.h b/engines/draci/game.h index f57b917e91..d905f68bd8 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -215,6 +215,7 @@ public: int getHeroX() const { return _hero.x; } int getHeroY() const { return _hero.y; } void positionAnimAsHero(Animation *anim); + void positionHeroAsAnim(Animation *anim); void playHeroAnimation(int anim_index); int loadAnimation(uint animNum, uint z); diff --git a/engines/draci/walking.cpp b/engines/draci/walking.cpp index fc194bf9d8..fed91dd8ef 100644 --- a/engines/draci/walking.cpp +++ b/engines/draci/walking.cpp @@ -522,11 +522,16 @@ bool WalkingState::continueWalking() { // We are walking in the middle of an edge. The animation phase has // just changed. Update the position of the hero. - _position += 4; // TODO: compute shifts properly from the animation - Common::Point newPos = WalkingMap::interpolate( - _path[_segment], _path[_segment+1], _position, _length); - _vm->_game->setHeroPosition(newPos); - _vm->_game->positionAnimAsHero(anim); + _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); // If the hero has reached the end of the edge, start transition to the // next phase. This will increment _segment, either immediately (if no @@ -698,7 +703,7 @@ Movement WalkingState::transitionBetweenAnimations(Movement previous, Movement n } } -Movement WalkingState::animationForSightDirection(SightDirection dir, const Common::Point &hero, const Common::Point &mouse, const WalkingPath &path) const { +Movement WalkingState::animationForSightDirection(SightDirection dir, const Common::Point &hero, const Common::Point &mouse, const WalkingPath &path) { switch (dir) { case kDirectionMouse: return mouse.x < hero.x ? kStopLeft : kStopRight; diff --git a/engines/draci/walking.h b/engines/draci/walking.h index 6c8d9b9b07..a3dae88eb7 100644 --- a/engines/draci/walking.h +++ b/engines/draci/walking.h @@ -132,7 +132,7 @@ public: // direction. The direction can be smart and in that case this // function needs to know the whole last path, the current position of // the hero, or the mouse position. - Movement animationForSightDirection(SightDirection dir, const Common::Point &hero, const Common::Point &mouse, const WalkingPath &path) const; + static Movement animationForSightDirection(SightDirection dir, const Common::Point &hero, const Common::Point &mouse, const WalkingPath &path); private: DraciEngine *_vm; -- cgit v1.2.3