diff options
author | Philipp Sehmisch <mana@crushnet.org> | 2011-03-14 20:56:40 +0100 |
---|---|---|
committer | Philipp Sehmisch <mana@crushnet.org> | 2011-03-15 18:23:37 +0100 |
commit | 91e2779891973cdbefc6e07ca3dee7a432a05112 (patch) | |
tree | 7b594b3aead19f6550d66384c342a3d3668ec086 | |
parent | 25a2abd09e3b76115ed0b6b1a02cdddc6c1c5bfc (diff) | |
download | mana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.tar.gz mana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.tar.bz2 mana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.tar.xz mana-client-91e2779891973cdbefc6e07ca3dee7a432a05112.zip |
Implemented a screen shake effect system in the viewport class.
The screen can either be "nudged" in a random direction with a specific
intensity or you can define an exact x and y intensity, decay factor and
duration. On a tmwAthena server an effect is triggered when the player
character dies. A method for stopping all shake effects is also
implemented, but not used yet. I added a netcode message for Manaserv to
trigger an effect server-sided. Because our protocol has currently no way
to transport floating point values, the decay is transported as a fixed
point value with 4 decimals which is entirely sufficient for this purpose.
-rw-r--r-- | src/gui/viewport.cpp | 38 | ||||
-rw-r--r-- | src/gui/viewport.h | 28 | ||||
-rw-r--r-- | src/net/manaserv/effecthandler.cpp | 38 | ||||
-rw-r--r-- | src/net/manaserv/effecthandler.h | 1 | ||||
-rw-r--r-- | src/net/manaserv/manaserv_protocol.h | 1 | ||||
-rw-r--r-- | src/net/tmwa/playerhandler.cpp | 1 |
6 files changed, 106 insertions, 1 deletions
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index ac910d5f..9d03cab5 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -42,6 +42,8 @@ #include "utils/stringutils.h" +#include <cmath> + extern volatile int tick_time; Viewport::Viewport(): @@ -121,9 +123,9 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) if (mScrollLaziness < 1) mScrollLaziness = 1; // Avoids division by zero - // Apply lazy scrolling while (lastTick < tick_time) { + // Apply lazy scrolling if (player_x > mPixelViewX + mScrollRadius) { mPixelViewX += (player_x - mPixelViewX - mScrollRadius) / @@ -144,6 +146,22 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) mPixelViewY += (player_y - mPixelViewY + mScrollRadius) / mScrollLaziness; } + + // manage shake effect + for (ShakeEffects::iterator i = mShakeEffects.begin(); + i != mShakeEffects.end(); + i++) + { + // apply the effect to viewport + mPixelViewX += i->x *= -i->decay; + mPixelViewY += i->y *= -i->decay; + // check death conditions + if (abs(i->x) + abs(i->y) < 1.0f || + (i->duration > 0 && --i->duration == 0)) + { + i = mShakeEffects.erase(i); + } + } lastTick++; } @@ -222,6 +240,24 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) WindowContainer::draw(gcnGraphics); } +void Viewport::shakeScreen(int intensity) +{ + float direction = rand()%628 / 100.0f; // random value between 0 and 2PI + float x = std::sin(direction) * intensity; + float y = std::cos(direction) * intensity; + shakeScreen(x, y); +} + +void Viewport::shakeScreen(float x, float y, float decay, unsigned duration) +{ + ShakeEffect effect; + effect.x = x; + effect.y = y; + effect.decay = decay; + effect.duration = duration; + mShakeEffects.push_back(effect); +} + void Viewport::logic() { WindowContainer::logic(); diff --git a/src/gui/viewport.h b/src/gui/viewport.h index 93e36b5b..f4db806b 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -29,6 +29,8 @@ #include <guichan/mouselistener.hpp> +#include <list> + class ActorSprite; class Being; class BeingPopup; @@ -153,6 +155,22 @@ class Viewport : public WindowContainer, public gcn::MouseListener, */ void hideBeingPopup(); + /** + * Makes the screen shake in a random direction + */ + void shakeScreen(int intensity); + + /** + * Makes the screen shake in a specific direction + */ + void shakeScreen(float x, float y, float decay = 0.95f, unsigned duration = 0); + + /** + * Stops all active screen shake effects + */ + void shakeScreenStop() + { mShakeEffects.clear(); } + void event(Channels channel, const Mana::Event &event); private: @@ -190,6 +208,16 @@ class Viewport : public WindowContainer, public gcn::MouseListener, float mPixelViewY; /**< Current viewpoint in pixels. */ int mShowDebugPath; /**< Show a path from player to pointer. */ + struct ShakeEffect + { + float x; + float y; + float decay; + unsigned duration; + }; + typedef std::list<ShakeEffect> ShakeEffects; + ShakeEffects mShakeEffects; + bool mPlayerFollowMouse; int mLocalWalkTime; /**< Timestamp before the next walk can be sent. */ diff --git a/src/net/manaserv/effecthandler.cpp b/src/net/manaserv/effecthandler.cpp index 2df3fe0b..7051bedd 100644 --- a/src/net/manaserv/effecthandler.cpp +++ b/src/net/manaserv/effecthandler.cpp @@ -25,6 +25,8 @@ #include "effectmanager.h" #include "log.h" +#include "gui/viewport.h" + #include "net/messagein.h" #include "net/manaserv/manaserv_protocol.h" @@ -36,6 +38,7 @@ EffectHandler::EffectHandler() static const Uint16 _messages[] = { GPMSG_CREATE_EFFECT_POS, GPMSG_CREATE_EFFECT_BEING, + GPMSG_SHAKE, 0 }; handledMessages = _messages; @@ -51,6 +54,9 @@ void EffectHandler::handleMessage(Net::MessageIn &msg) case GPMSG_CREATE_EFFECT_BEING: handleCreateEffectBeing(msg); break; + case GPMSG_SHAKE: + handleShake(msg); + break; default: break; } @@ -75,4 +81,36 @@ void EffectHandler::handleCreateEffectBeing(Net::MessageIn &msg) logger->log("Warning: CreateEffect called for unknown being #%d", bid); } +void EffectHandler::handleShake(Net::MessageIn &msg) +{ + int16_t intensityX = 0; + int16_t intensityY = 0; + float decay; + int duration; + + switch (msg.getUnreadLength()) + { + case 4: + intensityX = msg.readInt16(); + intensityY = msg.readInt16(); + viewport->shakeScreen(intensityX, intensityY); + break; + case 6: + intensityX = msg.readInt16(); + intensityY = msg.readInt16(); + decay = msg.readInt16() / 10000.0f; + viewport->shakeScreen(intensityX, intensityY, decay); + break; + case 8: + intensityX = msg.readInt16(); + intensityY = msg.readInt16(); + decay = msg.readInt16() / 10000.0f; + duration = msg.readInt16(); + viewport->shakeScreen(intensityX, intensityY, decay, duration); + break; + default: + logger->log("Warning: Received GPMSG_SHAKE message with unexpected length of %d bytes", msg.getUnreadLength()); + } +} + } // namespace ManaServ diff --git a/src/net/manaserv/effecthandler.h b/src/net/manaserv/effecthandler.h index a0445aad..d31c3421 100644 --- a/src/net/manaserv/effecthandler.h +++ b/src/net/manaserv/effecthandler.h @@ -36,6 +36,7 @@ class EffectHandler : public MessageHandler private: void handleCreateEffectPos(Net::MessageIn &msg); void handleCreateEffectBeing(Net::MessageIn &msg); + void handleShake(Net::MessageIn &msg); }; } // namespace ManaServ diff --git a/src/net/manaserv/manaserv_protocol.h b/src/net/manaserv/manaserv_protocol.h index 84f1c1a5..16e56183 100644 --- a/src/net/manaserv/manaserv_protocol.h +++ b/src/net/manaserv/manaserv_protocol.h @@ -163,6 +163,7 @@ enum { GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W amount }* GPMSG_CREATE_EFFECT_POS = 0x0320, // W effect id, W*2 position GPMSG_CREATE_EFFECT_BEING = 0x0321, // W effect id, W BeingID + GPMSG_SHAKE = 0x0330, // W intensityX, W intensityY, [W decay_times_10000, [W duration]] // Guild PCMSG_GUILD_CREATE = 0x0350, // S name diff --git a/src/net/tmwa/playerhandler.cpp b/src/net/tmwa/playerhandler.cpp index b82968a3..725a00cc 100644 --- a/src/net/tmwa/playerhandler.cpp +++ b/src/net/tmwa/playerhandler.cpp @@ -282,6 +282,7 @@ void PlayerHandler::handleMessage(Net::MessageIn &msg) if (PlayerInfo::getAttribute(HP) == 0 && !deathNotice) { + viewport->shakeScreen(100); deathNotice = new OkDialog(_("Message"), randomDeathMessage(), false); |