1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge pull request #2679 from Laserlicht/smooth_scroll

Smooth scroll
This commit is contained in:
Nordsoft91 2023-08-28 17:08:57 +04:00 committed by GitHub
commit ffc4b989f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 91 additions and 4 deletions

View File

@ -14,6 +14,7 @@
#include "CMusicHandler.h" #include "CMusicHandler.h"
#include "CGameInfo.h" #include "CGameInfo.h"
#include "renderSDL/SDLRWwrapper.h" #include "renderSDL/SDLRWwrapper.h"
#include "eventsSDL/InputHandler.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "../lib/JsonNode.h" #include "../lib/JsonNode.h"
@ -629,7 +630,8 @@ bool MusicEntry::play()
} }
} }
startTime = SDL_GetTicks(); startTime = GH.input().getTicks();
playing = true; playing = true;
return true; return true;
} }
@ -640,7 +642,7 @@ bool MusicEntry::stop(int fade_ms)
{ {
playing = false; playing = false;
loop = 0; loop = 0;
uint32_t endTime = SDL_GetTicks(); uint32_t endTime = GH.input().getTicks();
assert(startTime != uint32_t(-1)); assert(startTime != uint32_t(-1));
float playDuration = (endTime - startTime + startPosition) / 1000.f; float playDuration = (endTime - startTime + startPosition) / 1000.f;
owner->trackPositions[currentName] = playDuration; owner->trackPositions[currentName] = playDuration;

View File

@ -28,6 +28,7 @@
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
#include <SDL_events.h> #include <SDL_events.h>
#include <SDL_timer.h>
InputHandler::InputHandler() InputHandler::InputHandler()
: mouseHandler(std::make_unique<InputSourceMouse>()) : mouseHandler(std::make_unique<InputSourceMouse>())
@ -253,6 +254,11 @@ void InputHandler::hapticFeedback()
fingerHandler->hapticFeedback(); fingerHandler->hapticFeedback();
} }
uint32_t InputHandler::getTicks()
{
return SDL_GetTicks();
}
bool InputHandler::hasTouchInputDevice() const bool InputHandler::hasTouchInputDevice() const
{ {
return fingerHandler->hasTouchInputDevice(); return fingerHandler->hasTouchInputDevice();

View File

@ -68,6 +68,9 @@ public:
/// do a haptic feedback /// do a haptic feedback
void hapticFeedback(); void hapticFeedback();
/// Get the number of milliseconds since SDL library initialization
uint32_t getTicks();
/// returns true if system has active touchscreen /// returns true if system has active touchscreen
bool hasTouchInputDevice() const; bool hasTouchInputDevice() const;

View File

@ -25,6 +25,7 @@
#include "../render/Canvas.h" #include "../render/Canvas.h"
#include "../render/IImage.h" #include "../render/IImage.h"
#include "../renderSDL/SDL_Extensions.h" #include "../renderSDL/SDL_Extensions.h"
#include "../eventsSDL/InputHandler.h"
#include "../../CCallback.h" #include "../../CCallback.h"
@ -82,6 +83,14 @@ void BasicMapView::showAll(Canvas & to)
render(to, true); render(to, true);
} }
void MapView::tick(uint32_t msPassed)
{
if(settings["adventure"]["smoothDragging"].Bool())
postSwipe(msPassed);
BasicMapView::tick(msPassed);
}
void MapView::show(Canvas & to) void MapView::show(Canvas & to)
{ {
actions->setContext(controller->getContext()); actions->setContext(controller->getContext());
@ -94,6 +103,9 @@ MapView::MapView(const Point & offset, const Point & dimensions)
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
actions = std::make_shared<MapViewActions>(*this, model); actions = std::make_shared<MapViewActions>(*this, model);
actions->setContext(controller->getContext()); actions->setContext(controller->getContext());
// catch min 6 frames
postSwipeCatchIntervalMs = std::max(100, static_cast<int>(6.0 * 1000.0 * (1.0 / settings["video"]["targetfps"].Float())));
} }
void MapView::onMapLevelSwitched() void MapView::onMapLevelSwitched()
@ -115,9 +127,50 @@ void MapView::onMapScrolled(const Point & distance)
void MapView::onMapSwiped(const Point & viewPosition) void MapView::onMapSwiped(const Point & viewPosition)
{ {
if(settings["adventure"]["smoothDragging"].Bool())
swipeHistory.push_back(std::pair<uint32_t, Point>(GH.input().getTicks(), viewPosition));
controller->setViewCenter(model->getMapViewCenter() + viewPosition, model->getLevel()); controller->setViewCenter(model->getMapViewCenter() + viewPosition, model->getLevel());
} }
void MapView::postSwipe(uint32_t msPassed)
{
if(!actions->dragActive)
{
if(swipeHistory.size() > 1)
{
Point diff = Point(0, 0);
std::pair<uint32_t, Point> firstAccepted;
uint32_t now = GH.input().getTicks();
for (auto & x : swipeHistory) {
if(now - x.first < postSwipeCatchIntervalMs) { // only the last x ms are catched
if(firstAccepted.first == 0)
firstAccepted = x;
diff += x.second;
}
}
uint32_t timediff = swipeHistory.back().first - firstAccepted.first;
if(diff.length() > 0 && timediff > 0)
{
postSwipeAngle = diff.angle();
postSwipeSpeed = static_cast<double>(diff.length()) / static_cast<double>(timediff); // unit: pixel/millisecond
}
}
swipeHistory.clear();
} else
postSwipeSpeed = 0.0;
if(postSwipeSpeed > postSwipeMinimalSpeed) {
double len = postSwipeSpeed * static_cast<double>(msPassed);
Point delta = Point(len * cos(postSwipeAngle), len * sin(postSwipeAngle));
controller->setViewCenter(model->getMapViewCenter() + delta, model->getLevel());
postSwipeSpeed /= 1 + msPassed * postSwipeSlowdownSpeed;
}
}
void MapView::onCenteredTile(const int3 & tile) void MapView::onCenteredTile(const int3 & tile)
{ {
controller->setViewCenter(tile); controller->setViewCenter(tile);

View File

@ -49,7 +49,18 @@ class MapView : public BasicMapView
{ {
std::shared_ptr<MapViewActions> actions; std::shared_ptr<MapViewActions> actions;
std::vector<std::pair<uint32_t, Point>> swipeHistory;
double postSwipeAngle = 0.0;
double postSwipeSpeed = 0.0;
int postSwipeCatchIntervalMs;
const double postSwipeSlowdownSpeed = 0.006;
const double postSwipeMinimalSpeed = 0.1;
void postSwipe(uint32_t msPassed);
public: public:
void tick(uint32_t msPassed) override;
void show(Canvas & to) override; void show(Canvas & to) override;
MapView(const Point & offset, const Point & dimensions); MapView(const Point & offset, const Point & dimensions);

View File

@ -121,6 +121,8 @@ void MapViewActions::gesturePinch(const Point & centerPosition, double lastUpdat
void MapViewActions::gesture(bool on, const Point & initialPosition, const Point & finalPosition) void MapViewActions::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
{ {
dragActive = on;
pinchZoomFactor = 1.0; pinchZoomFactor = 1.0;
} }

View File

@ -24,7 +24,6 @@ class MapViewActions : public CIntObject
Point dragDistance; Point dragDistance;
double pinchZoomFactor; double pinchZoomFactor;
bool dragActive;
void handleHover(const Point & cursorPosition); void handleHover(const Point & cursorPosition);
@ -44,4 +43,6 @@ public:
void mouseMoved(const Point & cursorPosition, const Point & lastUpdateDistance) override; void mouseMoved(const Point & cursorPosition, const Point & lastUpdateDistance) override;
void mouseDragged(const Point & cursorPosition, const Point & lastUpdateDistance) override; void mouseDragged(const Point & cursorPosition, const Point & lastUpdateDistance) override;
void wheelScrolled(int distance) override; void wheelScrolled(int distance) override;
bool dragActive;
}; };

View File

@ -221,7 +221,7 @@
"type" : "object", "type" : "object",
"additionalProperties" : false, "additionalProperties" : false,
"default" : {}, "default" : {},
"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation", "forceQuickCombat", "borderScroll", "leftButtonDrag" ], "required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat", "objectAnimation", "terrainAnimation", "forceQuickCombat", "borderScroll", "leftButtonDrag", "smoothDragging" ],
"properties" : { "properties" : {
"heroMoveTime" : { "heroMoveTime" : {
"type" : "number", "type" : "number",
@ -265,6 +265,10 @@
"leftButtonDrag" : { "leftButtonDrag" : {
"type" : "boolean", "type" : "boolean",
"default" : false "default" : false
},
"smoothDragging" : {
"type" : "boolean",
"default" : true
} }
} }
}, },

View File

@ -116,6 +116,11 @@ public:
return std::sqrt(lengthSquared()); return std::sqrt(lengthSquared());
} }
double angle() const
{
return std::atan2(y, x); // rad
}
template <typename Handler> template <typename Handler>
void serialize(Handler &h, const int version) void serialize(Handler &h, const int version)
{ {