瀏覽代碼

[3.x] Allow getting Input axis/vector values from multiple actions

For get_vector, use raw values and handle deadzones appropriately
Aaron Franke 4 年之前
父節點
當前提交
69fb14256b
共有 4 個文件被更改,包括 82 次插入2 次删除
  1. 8 2
      core/os/input.cpp
  2. 3 0
      core/os/input.h
  3. 40 0
      doc/classes/Input.xml
  4. 31 0
      main/input_default.cpp

+ 8 - 2
core/os/input.cpp

@@ -61,6 +61,9 @@ void Input::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed);
 	ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released);
 	ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength);
+	ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action"), &Input::get_action_raw_strength);
+	ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
+	ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
 	ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
 	ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed);
@@ -125,10 +128,13 @@ void Input::_bind_methods() {
 void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
 #ifdef TOOLS_ENABLED
 
-	const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
+	const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\"";
 
 	String pf = p_function;
-	if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) {
+	if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" ||
+							  pf == "is_action_just_pressed" || pf == "is_action_just_released" ||
+							  pf == "get_action_strength" || pf == "get_action_raw_strength" ||
+							  pf == "get_axis" || pf == "get_vector")) {
 		List<PropertyInfo> pinfo;
 		ProjectSettings::get_singleton()->get_property_list(&pinfo);
 

+ 3 - 0
core/os/input.h

@@ -87,6 +87,9 @@ public:
 	virtual float get_action_strength(const StringName &p_action) const = 0;
 	virtual float get_action_raw_strength(const StringName &p_action) const = 0;
 
+	float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
+	Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
+
 	virtual float get_joy_axis(int p_device, int p_axis) const = 0;
 	virtual String get_joy_name(int p_idx) = 0;
 	virtual Array get_connected_joypads() = 0;

+ 40 - 0
doc/classes/Input.xml

@@ -54,6 +54,15 @@
 				[b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO]. On Android the unit of measurement for each axis is m/s² while on iOS and UWP it's a multiple of the Earth's gravitational acceleration [code]g[/code] (~9.81 m/s²).
 			</description>
 		</method>
+		<method name="get_action_raw_strength" qualifiers="const">
+			<return type="float">
+			</return>
+			<argument index="0" name="action" type="String">
+			</argument>
+			<description>
+				Returns a value between 0 and 1 representing the raw intensity of the given action, ignoring the action's deadzone. In most cases, you should use [method get_action_strength] instead.
+			</description>
+		</method>
 		<method name="get_action_strength" qualifiers="const">
 			<return type="float">
 			</return>
@@ -63,6 +72,18 @@
 				Returns a value between 0 and 1 representing the intensity of the given action. In a joypad, for example, the further away the axis (analog sticks or L2, R2 triggers) is from the dead zone, the closer the value will be to 1. If the action is mapped to a control that has no axis as the keyboard, the value returned will be 0 or 1.
 			</description>
 		</method>
+		<method name="get_axis" qualifiers="const">
+			<return type="float">
+			</return>
+			<argument index="0" name="negative_action" type="String">
+			</argument>
+			<argument index="1" name="positive_action" type="String">
+			</argument>
+			<description>
+				Get axis input by specifying two actions, one negative and one positive.
+				This is a shorthand for writing [code]Input.get_action_strength("positive_action") - Input.get_action_strength("negative_action")[/code].
+			</description>
+		</method>
 		<method name="get_connected_joypads">
 			<return type="Array">
 			</return>
@@ -205,6 +226,25 @@
 				Returns the mouse mode. See the constants for more information.
 			</description>
 		</method>
+		<method name="get_vector" qualifiers="const">
+			<return type="Vector2">
+			</return>
+			<argument index="0" name="negative_x" type="String">
+			</argument>
+			<argument index="1" name="positive_x" type="String">
+			</argument>
+			<argument index="2" name="negative_y" type="String">
+			</argument>
+			<argument index="3" name="positive_y" type="String">
+			</argument>
+			<argument index="4" name="deadzone" type="float" default="-1.0">
+			</argument>
+			<description>
+				Gets an input vector by specifying four actions for the positive and negative X and Y axes.
+				This method is useful when getting vector input, such as from a joystick, directional pad, arrows, or WASD. The vector has its length limited to 1 and has a circular deadzone, which is useful for using vector input as movement.
+				By default, the deadzone is automatically calculated from the average of the action deadzones. However, you can override the deadzone to be whatever you want (on the range of 0 to 1).
+			</description>
+		</method>
 		<method name="is_action_just_pressed" qualifiers="const">
 			<return type="bool">
 			</return>

+ 31 - 0
main/input_default.cpp

@@ -158,6 +158,37 @@ float InputDefault::get_action_raw_strength(const StringName &p_action) const {
 	return E->get().raw_strength;
 }
 
+float Input::get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const {
+	return get_action_strength(p_positive_action) - get_action_strength(p_negative_action);
+}
+
+Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone) const {
+	Vector2 vector = Vector2(
+			get_action_raw_strength(p_positive_x) - get_action_raw_strength(p_negative_x),
+			get_action_raw_strength(p_positive_y) - get_action_raw_strength(p_negative_y));
+
+	if (p_deadzone < 0.0f) {
+		// If the deadzone isn't specified, get it from the average of the actions.
+		p_deadzone = (InputMap::get_singleton()->action_get_deadzone(p_positive_x) +
+							 InputMap::get_singleton()->action_get_deadzone(p_negative_x) +
+							 InputMap::get_singleton()->action_get_deadzone(p_positive_y) +
+							 InputMap::get_singleton()->action_get_deadzone(p_negative_y)) /
+					 4;
+	}
+
+	// Circular length limiting and deadzone.
+	float length = vector.length();
+	if (length <= p_deadzone) {
+		return Vector2();
+	} else if (length > 1.0f) {
+		return vector / length;
+	} else {
+		// Inverse lerp length to map (p_deadzone, 1) to (0, 1).
+		return vector * (Math::inverse_lerp(p_deadzone, 1.0f, length) / length);
+	}
+	return vector;
+}
+
 float InputDefault::get_joy_axis(int p_device, int p_axis) const {
 	_THREAD_SAFE_METHOD_
 	int c = _combine_device(p_axis, p_device);