Merge pull request #4905 from german77/AnalogFromButton
Allow to dial any angle with digital joystick
This commit is contained in:
		| @@ -2,6 +2,10 @@ | |||||||
| // Licensed under GPLv2 or any later version | // Licensed under GPLv2 or any later version | ||||||
| // Refer to the license.txt file included. | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <chrono> | ||||||
|  | #include <cmath> | ||||||
|  | #include <thread> | ||||||
|  | #include "common/math_util.h" | ||||||
| #include "input_common/analog_from_button.h" | #include "input_common/analog_from_button.h" | ||||||
|  |  | ||||||
| namespace InputCommon { | namespace InputCommon { | ||||||
| @@ -11,31 +15,104 @@ public: | |||||||
|     using Button = std::unique_ptr<Input::ButtonDevice>; |     using Button = std::unique_ptr<Input::ButtonDevice>; | ||||||
|  |  | ||||||
|     Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_, |     Analog(Button up_, Button down_, Button left_, Button right_, Button modifier_, | ||||||
|            float modifier_scale_) |            float modifier_scale_, float modifier_angle_) | ||||||
|         : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), |         : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), | ||||||
|           right(std::move(right_)), modifier(std::move(modifier_)), |           right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), | ||||||
|           modifier_scale(modifier_scale_) {} |           modifier_angle(modifier_angle_) { | ||||||
|  |         update_thread = std::thread(&Analog::UpdateStatus, this); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ~Analog() override { | ||||||
|  |         update_thread_running = false; | ||||||
|  |         if (update_thread.joinable()) { | ||||||
|  |             update_thread.join(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void MoveToDirection(bool enable, float to_angle) { | ||||||
|  |         if (!enable) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         constexpr float TAU = Common::PI * 2.0f; | ||||||
|  |         // Use wider angle to ease the transition. | ||||||
|  |         constexpr float aperture = TAU * 0.15f; | ||||||
|  |         const float top_limit = to_angle + aperture; | ||||||
|  |         const float bottom_limit = to_angle - aperture; | ||||||
|  |  | ||||||
|  |         if ((angle > to_angle && angle <= top_limit) || | ||||||
|  |             (angle + TAU > to_angle && angle + TAU <= top_limit)) { | ||||||
|  |             angle -= modifier_angle; | ||||||
|  |             if (angle < 0) { | ||||||
|  |                 angle += TAU; | ||||||
|  |             } | ||||||
|  |         } else if ((angle >= bottom_limit && angle < to_angle) || | ||||||
|  |                    (angle - TAU >= bottom_limit && angle - TAU < to_angle)) { | ||||||
|  |             angle += modifier_angle; | ||||||
|  |             if (angle >= TAU) { | ||||||
|  |                 angle -= TAU; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             angle = to_angle; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void UpdateStatus() { | ||||||
|  |         while (update_thread_running) { | ||||||
|  |             const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; | ||||||
|  |  | ||||||
|  |             bool r = right->GetStatus(); | ||||||
|  |             bool l = left->GetStatus(); | ||||||
|  |             bool u = up->GetStatus(); | ||||||
|  |             bool d = down->GetStatus(); | ||||||
|  |  | ||||||
|  |             // Eliminate contradictory movements | ||||||
|  |             if (r && l) { | ||||||
|  |                 r = false; | ||||||
|  |                 l = false; | ||||||
|  |             } | ||||||
|  |             if (u && d) { | ||||||
|  |                 u = false; | ||||||
|  |                 d = false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Move to the right | ||||||
|  |             MoveToDirection(r && !u && !d, 0.0f); | ||||||
|  |  | ||||||
|  |             // Move to the upper right | ||||||
|  |             MoveToDirection(r && u && !d, Common::PI * 0.25f); | ||||||
|  |  | ||||||
|  |             // Move up | ||||||
|  |             MoveToDirection(u && !l && !r, Common::PI * 0.5f); | ||||||
|  |  | ||||||
|  |             // Move to the upper left | ||||||
|  |             MoveToDirection(l && u && !d, Common::PI * 0.75f); | ||||||
|  |  | ||||||
|  |             // Move to the left | ||||||
|  |             MoveToDirection(l && !u && !d, Common::PI); | ||||||
|  |  | ||||||
|  |             // Move to the bottom left | ||||||
|  |             MoveToDirection(l && !u && d, Common::PI * 1.25f); | ||||||
|  |  | ||||||
|  |             // Move down | ||||||
|  |             MoveToDirection(d && !l && !r, Common::PI * 1.5f); | ||||||
|  |  | ||||||
|  |             // Move to the bottom right | ||||||
|  |             MoveToDirection(r && !u && d, Common::PI * 1.75f); | ||||||
|  |  | ||||||
|  |             // Move if a key is pressed | ||||||
|  |             if (r || l || u || d) { | ||||||
|  |                 amplitude = coef; | ||||||
|  |             } else { | ||||||
|  |                 amplitude = 0; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Delay the update rate to 100hz | ||||||
|  |             std::this_thread::sleep_for(std::chrono::milliseconds(10)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     std::tuple<float, float> GetStatus() const override { |     std::tuple<float, float> GetStatus() const override { | ||||||
|         constexpr float SQRT_HALF = 0.707106781f; |         return std::make_tuple(std::cos(angle) * amplitude, std::sin(angle) * amplitude); | ||||||
|         int x = 0, y = 0; |  | ||||||
|  |  | ||||||
|         if (right->GetStatus()) { |  | ||||||
|             ++x; |  | ||||||
|         } |  | ||||||
|         if (left->GetStatus()) { |  | ||||||
|             --x; |  | ||||||
|         } |  | ||||||
|         if (up->GetStatus()) { |  | ||||||
|             ++y; |  | ||||||
|         } |  | ||||||
|         if (down->GetStatus()) { |  | ||||||
|             --y; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; |  | ||||||
|         return std::make_tuple(static_cast<float>(x) * coef * (y == 0 ? 1.0f : SQRT_HALF), |  | ||||||
|                                static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |     bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | ||||||
| @@ -59,6 +136,11 @@ private: | |||||||
|     Button right; |     Button right; | ||||||
|     Button modifier; |     Button modifier; | ||||||
|     float modifier_scale; |     float modifier_scale; | ||||||
|  |     float modifier_angle; | ||||||
|  |     float angle{}; | ||||||
|  |     float amplitude{}; | ||||||
|  |     std::thread update_thread; | ||||||
|  |     bool update_thread_running{true}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { | ||||||
| @@ -69,8 +151,10 @@ std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::Para | |||||||
|     auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine)); |     auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine)); | ||||||
|     auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); |     auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); | ||||||
|     auto modifier_scale = params.Get("modifier_scale", 0.5f); |     auto modifier_scale = params.Get("modifier_scale", 0.5f); | ||||||
|  |     auto modifier_angle = params.Get("modifier_angle", 0.035f); | ||||||
|     return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left), |     return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left), | ||||||
|                                     std::move(right), std::move(modifier), modifier_scale); |                                     std::move(right), std::move(modifier), modifier_scale, | ||||||
|  |                                     modifier_angle); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace InputCommon | } // namespace InputCommon | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei