From 6f6d061b23c6c70c632fb3ec6aa3735325f701e0 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond Date: Sun, 27 Aug 2006 19:05:07 +0000 Subject: Implemented pixel-grained movements. --- ChangeLog | 3 ++- src/being.cpp | 61 +++++++++++++++++++++++++++++++++++++---------------- src/being.h | 15 ++++++------- src/engine.cpp | 10 ++++----- src/gui/gui.cpp | 6 +++--- src/localplayer.cpp | 34 +++++++++++++++++------------ 6 files changed, 81 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2d7cbdd9..ecaf0b13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,7 +30,8 @@ Being::mFrame field. * src/localplayer.cpp, src/player.cpp, src/monster.h, src/being.cpp, src/monster.cpp, src/player.h: Cleaned the logic members. - + * src/engine.cpp, src/localplayer.cpp, src/gui/gui.cpp, src/being.cpp, + src/being.h: Implemented pixel-grained movements. 2006-08-26 Bjørn Lindeijer diff --git a/src/being.cpp b/src/being.cpp index 46fb67bb..b497d58f 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -23,6 +23,7 @@ #include "being.h" #include +#include #include "animatedsprite.h" #include "equipment.h" @@ -48,7 +49,7 @@ PATH_NODE::PATH_NODE(Uint16 iX, Uint16 iY): Being::Being(Uint32 id, Uint16 job, Map *map): mJob(job), mX(0), mY(0), mDirection(DOWN), - mAction(0), + mAction(STAND), mWalkTime(0), mEmotion(0), mEmotionTime(0), mAttackSpeed(350), @@ -77,10 +78,31 @@ Being::~Being() void Being::setDestination(Uint16 destX, Uint16 destY) { - if (mMap) + if (!mMap || (mX == destX && mY == destY)) { - setPath(mMap->findPath(mX / 32, mY / 32, destX / 32, destY / 32)); + return; + } + + Path p; + if (mX / 32 != destX / 32 || mY / 32 != destY / 32) + { + p = mMap->findPath(mX / 32, mY / 32, destX / 32, destY / 32); + if (p.empty()) + { + setPath(p); + return; + } + // Remove last tile so that it can be replaced by the exact destination. + p.pop_back(); + for (Path::iterator i = p.begin(), i_end = p.end(); i != i_end; ++i) + { + // Set intermediate step to tile centers. + i->x = i->x * 32 + 16; + i->y = i->y * 32 + 16; + } } + p.push_back(PATH_NODE(destX, destY)); + setPath(p); } void @@ -96,8 +118,9 @@ Being::setPath(const Path &path) if (mAction != WALK && mAction != DEAD) { - nextStep(); mWalkTime = tick_time; + mStepTime = 0; + nextStep(); } } @@ -265,28 +288,31 @@ Being::nextStep() mPath.pop_front(); int dir = 0; - if (node.x > mX / 32) + if (node.x > mX) dir |= RIGHT; - else if (node.x < mX / 32) + else if (node.x < mX) dir |= LEFT; - if (node.y > mY / 32) + if (node.y > mY) dir |= DOWN; - else if (node.y < mY / 32) + else if (node.y < mY) dir |= UP; setDirection(dir); - mX = node.x * 32 + 16; - mY = node.y * 32 + 16; + mStepX = node.x - mX; + mStepY = node.y - mY; + mX = node.x; + mY = node.y; setAction(WALK); - mWalkTime += mWalkSpeed / 10; + mWalkTime += mStepTime / 10; + mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) / 32; } void Being::logic() { // Determine whether the being should take another step - if (mAction == WALK && get_elapsed_time(mWalkTime) >= mWalkSpeed) + if (mAction == WALK && get_elapsed_time(mWalkTime) >= mStepTime) { nextStep(); } @@ -435,24 +461,23 @@ Being::setWeaponById(Uint16 weapon) } } -int -Being::getOffset(char pos, char neg) const +int Being::getOffset(int step) const { // Check whether we're walking in the requested direction - if (mAction != WALK || !(mDirection & (pos | neg))) { + if (mAction != WALK || step == 0) { return 0; } - int offset = (get_elapsed_time(mWalkTime) * 32) / mWalkSpeed; + int offset = (get_elapsed_time(mWalkTime) * std::abs(step)) / mStepTime; // We calculate the offset _from_ the _target_ location - offset -= 32; + offset -= std::abs(step); if (offset > 0) { offset = 0; } // Going into negative direction? Invert the offset. - if (mDirection & pos) { + if (step < 0) { offset = -offset; } diff --git a/src/being.h b/src/being.h index 38c62dbb..7c08ab81 100644 --- a/src/being.h +++ b/src/being.h @@ -324,13 +324,13 @@ class Being : public Sprite * Get the current X pixel offset. */ int - getXOffset() const { return getOffset(LEFT, RIGHT); } + getXOffset() const { return getOffset(mStepX); } /** * Get the current Y pixel offset. */ int - getYOffset() const { return getOffset(UP, DOWN); } + getYOffset() const { return getOffset(mStepY); } std::auto_ptr mEquipment; int mVisibleEquipment[6]; /**< Visible equipments */ @@ -342,12 +342,6 @@ class Being : public Sprite void setPath(const Path &path); - /** - * Calculates the offset in the given directions. - * If walking in direction 'neg' the value is negated. - */ - int getOffset(char pos, char neg) const; - /** * Returns the sprite direction of this being. */ @@ -371,6 +365,11 @@ class Being : public Sprite Sint32 mPx, mPy; /**< Pixel coordinates */ std::vector mSprites; + + private: + Sint16 mStepX, mStepY; + Uint16 mStepTime; + int getOffset(int) const; }; #endif diff --git a/src/engine.cpp b/src/engine.cpp index f3aff6ce..eda154f3 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -176,8 +176,8 @@ void Engine::draw(Graphics *graphics) } } - camera_x = map_x / 32; - camera_y = map_y / 32; + camera_x = map_x; + camera_y = map_y; // Draw tiles and sprites if (mCurrentMap != NULL) @@ -202,11 +202,11 @@ void Engine::draw(Graphics *graphics) int mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); - int mouseTileX = mouseX / 32 + camera_x; - int mouseTileY = mouseY / 32 + camera_y; + int mouseTileX = (mouseX + map_x) / 32; + int mouseTileY = (mouseY + map_y) / 32; Path debugPath = mCurrentMap->findPath( - player_node->mX, player_node->mY, + player_node->mX / 32, player_node->mY / 32, mouseTileX, mouseTileY); graphics->setColor(gcn::Color(255, 0, 0)); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a3ec299b..5df26d63 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -245,8 +245,8 @@ Gui::mousePress(int mx, int my, int button) if (current_npc) return; - int tilex = mx / 32 + camera_x; - int tiley = my / 32 + camera_y; + int tilex = (mx + camera_x) / 32; + int tiley = (my + camera_y) / 32; // Right click might open a popup if (button == gcn::MouseInput::RIGHT) @@ -313,7 +313,7 @@ Gui::mousePress(int mx, int my, int button) Uint8 *keys = SDL_GetKeyState(NULL); if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT])) { - player_node->setDestination(tilex * 32 + 16, tiley * 32 + 16); + player_node->setDestination(mx + camera_x, my + camera_y); player_node->stopAttack(); } } diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 368bc8e3..9df3ac3f 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -161,30 +161,30 @@ void LocalPlayer::walk(unsigned char dir) return; } - Sint16 dx = 0, dy = 0; + int dx = 0, dy = 0; if (dir & UP) - dy--; + dy -= 32; if (dir & DOWN) - dy++; + dy += 32; if (dir & LEFT) - dx--; + dx -= 32; if (dir & RIGHT) - dx++; + dx += 32; // Prevent skipping corners over colliding tiles - if (dx && mMap->tileCollides(mX / 32 + dx, mY / 32)) - dx = 0; - if (dy && mMap->tileCollides(mX / 32, mY / 32 + dy)) - dy = 0; + if (dx && mMap->tileCollides((mX + dx) / 32, mY / 32)) + dx = 16 - mX % 32; + if (dy && mMap->tileCollides(mX / 32, (mY + dy) / 32)) + dy = 16 - mY % 32; // Choose a straight direction when diagonal target is blocked - if (dx && dy && !mMap->getWalk(mX / 32 + dx, mY / 32 + dy)) - dx = 0; + if (dx && dy && !mMap->getWalk((mX + dx) / 32, (mY + dy) / 32)) + dx = 16 - mX % 32; // Walk to where the player can actually go - if ((dx || dy) && mMap->getWalk(mX / 32 + dx, mY / 32 + dy)) + if ((dx || dy) && mMap->getWalk((mX + dx) / 32, (mY + dy) / 32)) { - setDestination(mX + dx * 32, mY + dy * 32); + setDestination(mX + dx, mY + dy); } else if (dir) { @@ -198,6 +198,14 @@ void LocalPlayer::walk(unsigned char dir) void LocalPlayer::setDestination(Uint16 x, Uint16 y) { + // Fix coordinates so that the player does not seem to dig into walls. + int tx = x / 32, ty = y / 32, fx = x % 32, fy = y % 32; + if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty)) fx = 16; + if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1)) fy = 16; + if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty + fy / 16 * 2 - 1)) fx = 16; + x = tx * 32 + fx; + y = ty * 32 + fy; + MessageOut msg(PGMSG_WALK); msg.writeShort(x); msg.writeShort(y); -- cgit v1.2.3-70-g09d2