Merge pull request #4905 from german77/AnalogFromButton
Allow to dial any angle with digital joystick
This commit is contained in:
		
						commit
						d1da7eb119
					
				| @ -2,6 +2,10 @@ | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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" | ||||
| 
 | ||||
| namespace InputCommon { | ||||
| @ -11,31 +15,104 @@ public: | ||||
|     using Button = std::unique_ptr<Input::ButtonDevice>; | ||||
| 
 | ||||
|     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_)), | ||||
|           right(std::move(right_)), modifier(std::move(modifier_)), | ||||
|           modifier_scale(modifier_scale_) {} | ||||
|           right(std::move(right_)), modifier(std::move(modifier_)), 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 { | ||||
|         constexpr float SQRT_HALF = 0.707106781f; | ||||
|         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)); | ||||
|         return std::make_tuple(std::cos(angle) * amplitude, std::sin(angle) * amplitude); | ||||
|     } | ||||
| 
 | ||||
|     bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | ||||
| @ -59,6 +136,11 @@ private: | ||||
|     Button right; | ||||
|     Button modifier; | ||||
|     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) { | ||||
| @ -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 modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); | ||||
|     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), | ||||
|                                     std::move(right), std::move(modifier), modifier_scale); | ||||
|                                     std::move(right), std::move(modifier), modifier_scale, | ||||
|                                     modifier_angle); | ||||
| } | ||||
| 
 | ||||
| } // namespace InputCommon
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei