169 lines
6.5 KiB
GDScript
169 lines
6.5 KiB
GDScript
extends Node
|
|
|
|
## A globally accessible manager for device-specific actions using SteamInput for any controller
|
|
## and standard Godot Input for the keyboard.
|
|
##
|
|
## All methods in this class that have a "device" parameter can accept -1
|
|
## which means the keyboard device.
|
|
|
|
# The actions defined in the Steam .vdf file are listed here
|
|
# with true or false indicating if input is analog or digital.
|
|
# False is digital (buttons), true is analog (joysticks, triggers, etc).
|
|
|
|
var action_names := {
|
|
"move": true,
|
|
"jump": false,
|
|
"left": false,
|
|
"right": false,
|
|
"down": false,
|
|
"up": false,
|
|
"interact": false,
|
|
"pause": false,
|
|
}
|
|
|
|
var got_handles := false
|
|
var game_action_set
|
|
var current_action_set
|
|
var actions := {}
|
|
# Store the state of each action and the frame it entered that state.
|
|
var action_states := {}
|
|
|
|
|
|
func init() -> void:
|
|
Steam.input_device_connected.connect(_on_steam_input_device_connected)
|
|
Steam.input_device_disconnected.connect(_on_steam_input_device_disconnected)
|
|
|
|
|
|
func _on_steam_input_device_connected(input_handle: int) -> void:
|
|
if not got_handles:
|
|
get_handles()
|
|
|
|
Steam.activateActionSet(input_handle, current_action_set)
|
|
print("Device connected %s" % str(input_handle))
|
|
|
|
|
|
func _on_steam_input_device_disconnected(input_handle: int) -> void:
|
|
print("Device disconnected %s" % str(input_handle))
|
|
|
|
|
|
func get_handles() -> void:
|
|
got_handles = true
|
|
game_action_set = Steam.getActionSetHandle("GameControls")
|
|
current_action_set = game_action_set
|
|
get_action_handles(action_names)
|
|
|
|
|
|
func get_action_handles(action_names: Dictionary) -> void:
|
|
for action in action_names.keys():
|
|
if action_names[action]:
|
|
actions[action] = Steam.getAnalogActionHandle(action)
|
|
else:
|
|
actions[action] = Steam.getDigitalActionHandle(action)
|
|
|
|
|
|
func get_controllers() -> Array[int]:
|
|
var controllers: Array[int] = [-1]
|
|
var steam_controllers = Steam.getConnectedControllers()
|
|
if steam_controllers:
|
|
controllers.append_array(steam_controllers)
|
|
|
|
return controllers
|
|
|
|
|
|
func get_action_strength(device: int, action: StringName, exact_match: bool = false) -> float:
|
|
if device >= 0:
|
|
if not got_handles: return 0
|
|
var action_data = Steam.getAnalogActionData(device, actions[action])
|
|
return action_data.x
|
|
return Input.get_action_strength(action, exact_match)
|
|
|
|
|
|
func get_axis(device: int, negative_action: StringName, positive_action: StringName) -> float:
|
|
if device >= 0:
|
|
if not got_handles: return 0
|
|
var negative = Steam.getAnalogActionData(device, actions[negative_action])
|
|
var positive = Steam.getAnalogActionData(device, actions[positive_action])
|
|
return positive.x - negative.x
|
|
return Input.get_axis(negative_action, positive_action)
|
|
|
|
|
|
func get_vector(device: int, negative_x: StringName, positive_x: StringName, negative_y: StringName, positive_y: StringName, deadzone: float = -1.0) -> Vector2:
|
|
if device >= 0:
|
|
if not got_handles: return Vector2.ZERO
|
|
var negative_x_val = Steam.getAnalogActionData(device, actions[negative_x])
|
|
var positive_x_val = Steam.getAnalogActionData(device, actions[positive_x])
|
|
var negative_y_val = Steam.getAnalogActionData(device, actions[negative_y])
|
|
var positive_y_val = Steam.getAnalogActionData(device, actions[positive_y])
|
|
# Steam's y axis is inverted compared to Godot
|
|
return Vector2(positive_x_val - negative_x_val, -(positive_y_val - negative_y_val)).normalized()
|
|
return Input.get_vector(negative_x, positive_x, negative_y, positive_y, deadzone)
|
|
|
|
|
|
func get_move_input(device: int) -> Vector2:
|
|
if device >= 0:
|
|
if not got_handles: return Vector2.ZERO
|
|
# Get the analog stick movement
|
|
var action_data = Steam.getAnalogActionData(device, actions["Move"])
|
|
return Vector2(action_data.x, -action_data.y).normalized()
|
|
return Vector2(Input.get_axis("left", "right"), Input.get_axis("up", "down")).normalized()
|
|
|
|
|
|
func get_action_state(device: int, action: String) -> Dictionary:
|
|
# Get the current action, but create the defaults along the way if they don't exist.
|
|
if not action_states.get(device):
|
|
action_states[device] = {}
|
|
if not action_states[device].get(action):
|
|
action_states[device][action] = { "held": false, "press_frame": -1, "release_frame": -1 }
|
|
return action_states[device][action]
|
|
|
|
|
|
func set_action_state(device: int, action: StringName, currently_held: bool, current_frame: int) -> Dictionary:
|
|
# Get the state of the action last frame
|
|
var previous_action_state := get_action_state(device, action)
|
|
|
|
# If we're pressing the action now and we weren't pressing it last frame,
|
|
# track that we pressed the action this frame.
|
|
if currently_held and not previous_action_state.held:
|
|
action_states[device][action].held = true
|
|
action_states[device][action].press_frame = current_frame
|
|
# If we're not pressing it this frame but we were pressing it last frame,
|
|
# track that we released the action this frame.
|
|
elif not currently_held and previous_action_state.held:
|
|
action_states[device][action].held = false
|
|
action_states[device][action].release_frame = current_frame
|
|
|
|
# Return the current state of the action
|
|
return action_states[device][action]
|
|
|
|
|
|
func is_action_pressed(device: int, action: StringName, exact_match: bool = false) -> bool:
|
|
if device >= 0:
|
|
if not got_handles: return false
|
|
var current_frame := Engine.get_process_frames()
|
|
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
|
|
set_action_state(device, action, currently_held, current_frame)
|
|
return currently_held
|
|
# If keyboard, use normal Godot input system.
|
|
return Input.is_action_pressed(action, exact_match)
|
|
|
|
|
|
func is_action_just_pressed(device: int, action: StringName, exact_match: bool = false) -> bool:
|
|
if device >= 0:
|
|
if not got_handles: return false
|
|
var current_frame := Engine.get_process_frames()
|
|
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
|
|
var action_state := set_action_state(device, action, currently_held, current_frame)
|
|
return currently_held and action_state.press_frame == current_frame
|
|
# If keyboard, use normal Godot input system.
|
|
return Input.is_action_just_pressed(action, exact_match)
|
|
|
|
|
|
func is_action_just_released(device: int, action: StringName, exact_match: bool = false) -> bool:
|
|
if device >= 0:
|
|
if not got_handles: return false
|
|
var current_frame := Engine.get_process_frames()
|
|
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
|
|
var action_state := set_action_state(device, action, currently_held, current_frame)
|
|
return not currently_held and action_state.release_frame == current_frame
|
|
# If keyboard, use normal Godot input system.
|
|
return Input.is_action_just_released(action, exact_match) |