소스 검색

Merge pull request #2679 from Laserlicht/smooth_scroll

Smooth scroll
Nordsoft91 2 년 전
부모
커밋
ffc4b989f0

+ 4 - 2
client/CMusicHandler.cpp

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

+ 6 - 0
client/eventsSDL/InputHandler.cpp

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

+ 3 - 0
client/eventsSDL/InputHandler.h

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

+ 53 - 0
client/mapView/MapView.cpp

@@ -25,6 +25,7 @@
 #include "../render/Canvas.h"
 #include "../render/IImage.h"
 #include "../renderSDL/SDL_Extensions.h"
+#include "../eventsSDL/InputHandler.h"
 
 #include "../../CCallback.h"
 
@@ -82,6 +83,14 @@ void BasicMapView::showAll(Canvas & to)
 	render(to, true);
 }
 
+void MapView::tick(uint32_t msPassed)
+{
+	if(settings["adventure"]["smoothDragging"].Bool())
+		postSwipe(msPassed);
+
+	BasicMapView::tick(msPassed);
+}
+
 void MapView::show(Canvas & to)
 {
 	actions->setContext(controller->getContext());
@@ -94,6 +103,9 @@ MapView::MapView(const Point & offset, const Point & dimensions)
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
 	actions = std::make_shared<MapViewActions>(*this, model);
 	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()
@@ -115,9 +127,50 @@ void MapView::onMapScrolled(const Point & distance)
 
 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());
 }
 
+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)
 {
 	controller->setViewCenter(tile);

+ 11 - 0
client/mapView/MapView.h

@@ -49,7 +49,18 @@ class MapView : public BasicMapView
 {
 	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:
+	void tick(uint32_t msPassed) override;
 	void show(Canvas & to) override;
 
 	MapView(const Point & offset, const Point & dimensions);

+ 2 - 0
client/mapView/MapViewActions.cpp

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

+ 2 - 1
client/mapView/MapViewActions.h

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

+ 5 - 1
config/schemas/settings.json

@@ -221,7 +221,7 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"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" : {
 				"heroMoveTime" : {
 					"type" : "number",
@@ -265,6 +265,10 @@
 				"leftButtonDrag" : {
 					"type" : "boolean",
 					"default" : false
+				},
+				"smoothDragging" : {
+					"type" : "boolean",
+					"default" : true
 				}
 			}
 		},

+ 5 - 0
lib/Point.h

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