WIP: implement full support for Steam Input
This commit is contained in:
parent
688c56a564
commit
c3167f663b
|
|
@ -0,0 +1,77 @@
|
|||
"In Game Actions"
|
||||
{
|
||||
"actions"
|
||||
{
|
||||
"GameControls"
|
||||
{
|
||||
"title" "#Set_GameControls"
|
||||
"StickPadGyro"
|
||||
{
|
||||
"move"
|
||||
{
|
||||
"title" "#Action_Move"
|
||||
"input_mode" "joystick_move"
|
||||
}
|
||||
"look"
|
||||
{
|
||||
"title" "#Action_Look"
|
||||
"input_mode" "absolute_mouse"
|
||||
}
|
||||
}
|
||||
"Button"
|
||||
{
|
||||
"interact" "#Action_Interact"
|
||||
"back" "#Action_Back"
|
||||
"crouch" "#Action_Crouch"
|
||||
"zoom" "#Action_Zoom"
|
||||
"skip" "#Action_Skip"
|
||||
"pause" "#Action_Pause"
|
||||
"summarize" "#Action_Summarize"
|
||||
}
|
||||
}
|
||||
"MenuControls"
|
||||
{
|
||||
"title" "#Set_MenuControls"
|
||||
"Button"
|
||||
{
|
||||
"menu_up" "#Menu_Up"
|
||||
"menu_down" "#Menu_Down"
|
||||
"menu_left" "#Menu_Left"
|
||||
"menu_right" "#Menu_Right"
|
||||
"accept" "#Menu_Accept"
|
||||
"cancel" "#Menu_Cancel"
|
||||
"focus_next" "#Menu_FocusNext"
|
||||
"focus_previous" "#Menu_FocusPrevious"
|
||||
"scroll_up" "#Menu_ScrollUp"
|
||||
"scroll_down" "#Menu_ScrollDown"
|
||||
}
|
||||
}
|
||||
}
|
||||
"localization"
|
||||
{
|
||||
"english"
|
||||
{
|
||||
"Set_GameControls" "Game Controls"
|
||||
"Set_MenuControls" "Menu Controls"
|
||||
"Action_Move" "Move"
|
||||
"Action_Look" "Look"
|
||||
"Action_Interact" "Pick up"
|
||||
"Action_Back" "Go Back"
|
||||
"Action_Crouch" "Crouch"
|
||||
"Action_Zoom" "Zoom"
|
||||
"Action_Skip" "Skip"
|
||||
"Action_Pause" "Pause Game"
|
||||
"Action_Summarize" "Summarize Content"
|
||||
"Menu_Up" "Menu Up"
|
||||
"Menu_Down" "Menu Down"
|
||||
"Menu_Left" "Menu Left"
|
||||
"Menu_Right" "Menu Right"
|
||||
"Menu_Accept" "Accept"
|
||||
"Menu_Canel" "Cancel"
|
||||
"Menu_FocusNext" "Focus Next"
|
||||
"Menu_FocusPrevious" "Focus Previous"
|
||||
"Menu_ScrollUp" "Scroll Up"
|
||||
"Menu_ScrollDown" "Scroll Down"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
class_name SteamInputGlypthDisplay extends TextureRect
|
||||
|
||||
@export var action_name: StringName
|
||||
|
||||
func _ready() -> void:
|
||||
SteamInputManager.glyphs_loaded.connect(_update_glyph)
|
||||
texture = PlaceholderTexture2D.new()
|
||||
texture.size = Vector2(64, 64)
|
||||
|
||||
func _update_glyph() -> void:
|
||||
texture = SteamInputManager.get_glyph(action_name)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cgfyo6u8wygjr
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
extends Node
|
||||
|
||||
signal glyphs_loaded
|
||||
|
||||
# True means analog action!
|
||||
const game_control_actios := {
|
||||
"move": true,
|
||||
"look": true,
|
||||
"interact": false,
|
||||
"back": false,
|
||||
"crouch": false,
|
||||
"zoom": false,
|
||||
"skip": false,
|
||||
"pause": false,
|
||||
"summarize": false
|
||||
}
|
||||
|
||||
const menu_control_actions := {
|
||||
"menu_up": false,
|
||||
"menu_down": false,
|
||||
"menu_left": false,
|
||||
"menu_right": false,
|
||||
"accept": false,
|
||||
"cancel": false,
|
||||
"focus_next": false,
|
||||
"focus_previous": false,
|
||||
"scroll_up": false,
|
||||
"scroll_down": false,
|
||||
}
|
||||
|
||||
var action_set_ids: Dictionary[StringName, int] = {"game_control_actios": -1, "menu_control_actions": -1}
|
||||
|
||||
var controller_id := -1
|
||||
var got_handles := false
|
||||
var actions := {}
|
||||
var analog_actions: PackedStringArray = []
|
||||
var action_states: Dictionary[StringName, SteamActionState] = {}
|
||||
|
||||
var current_action_set: int:
|
||||
set(value):
|
||||
if Steam.isSteamRunning():
|
||||
Steam.activateActionSet(controller_id, value)
|
||||
current_action_set = value
|
||||
|
||||
var action_glyphs: Dictionary[StringName, Texture2D]= {}
|
||||
var cooldown: float = 0.0
|
||||
var gdt_cooldown: float = 0.0
|
||||
|
||||
|
||||
func init() -> void:
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
Steam.input_device_connected.connect(_on_controller_connect)
|
||||
Steam.input_device_disconnected.connect(_on_controller_disconnect)
|
||||
Steam.runFrame()
|
||||
State.game_context_updated.connect(_on_set_change)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
Steam.runFrame()
|
||||
if cooldown > 0:
|
||||
cooldown -= delta
|
||||
if gdt_cooldown > 0:
|
||||
gdt_cooldown -= delta
|
||||
|
||||
if controller_id != -1 and State.last_input_source == State.InputSource.KEYBOARD_MOUSE:
|
||||
for action in actions.keys():
|
||||
if Steam.getDigitalActionData(controller_id, actions[action]).state:
|
||||
State.last_input_source = State.InputSource.JOYPAD
|
||||
break
|
||||
|
||||
func kill():
|
||||
State.game_context_updated.disconnect(_on_set_change)
|
||||
|
||||
|
||||
func si_to_godot(event_action: StringName):
|
||||
if State.last_input_source == State.InputSource.JOYPAD and gdt_cooldown <= 0:
|
||||
gdt_cooldown = 0.01
|
||||
var event := InputEventAction.new()
|
||||
event.action = event_action
|
||||
event.pressed = true
|
||||
Input.parse_input_event(event)
|
||||
|
||||
var event_release := InputEventAction.new()
|
||||
event_release.action = event_action
|
||||
event_release.pressed = false
|
||||
Input.parse_input_event(event_release)
|
||||
|
||||
|
||||
func get_handles() -> void:
|
||||
if controller_id != -1:
|
||||
for key in action_set_ids.keys():
|
||||
action_set_ids[key] = Steam.getActionSetHandle(key)
|
||||
action_set_ids[key] = Steam.getActionSetHandle(key)
|
||||
get_action_handles()
|
||||
got_handles = true
|
||||
|
||||
|
||||
func get_action_handles() -> void:
|
||||
for action_set_key in action_set_ids.keys():
|
||||
for action in get(action_set_key).keys():
|
||||
if game_control_actios[action]:
|
||||
actions[action] = Steam.getAnalogActionHandle(action)
|
||||
analog_actions.append(action)
|
||||
else:
|
||||
actions[action] = Steam.getDigitalActionHandle(action)
|
||||
|
||||
func get_action_strength(action: StringName, device: int = controller_id, exact_match: bool = false) -> float:
|
||||
if device != -1:
|
||||
if got_handles:
|
||||
return Steam.getAnalogActionData(device, actions[action]).x
|
||||
else:
|
||||
return 0
|
||||
return Input.get_action_strength(action, exact_match)
|
||||
|
||||
|
||||
func get_axis(base_name: StringName, device: int = controller_id) -> Vector2:
|
||||
if device != -1:
|
||||
if not got_handles: return Vector2.ZERO
|
||||
|
||||
var action_data = Steam.getAnalogActionData(device, actions[base_name])
|
||||
return Vector2(action_data.x, -action_data.y).normalized()
|
||||
return Vector2(Input.get_axis("%s_left" % base_name, "%s_right"), Input.get_axis("%s_positive", "%s_negative")).normalized()
|
||||
|
||||
|
||||
func is_action_pressed(action: StringName, device: int = controller_id, exact_match: bool = false) -> bool:
|
||||
if device != -1:
|
||||
if not got_handles: return false
|
||||
|
||||
var current_frame = Engine.get_process_frames()
|
||||
if State.last_input_source == State.InputSource.JOYPAD:
|
||||
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
|
||||
set_action_state(action, currently_held, current_frame)
|
||||
return currently_held
|
||||
|
||||
return Input.is_action_pressed(action, exact_match)
|
||||
|
||||
func is_action_just_pressed(action: StringName, device: int = controller_id, exact_match: bool = false) -> bool:
|
||||
if device >= 0:
|
||||
if not got_handles:
|
||||
return false
|
||||
|
||||
if cooldown <= 0:
|
||||
var current_frame = Engine.get_process_frames()
|
||||
if State.last_input_source == State.InputSource.JOYPAD:
|
||||
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
|
||||
var action_state = set_action_state(action, currently_held, current_frame)
|
||||
if currently_held:
|
||||
cooldown = 0.1
|
||||
return currently_held and action_state.press_frame == current_frame
|
||||
|
||||
else:
|
||||
return false
|
||||
|
||||
return Input.is_action_just_pressed(action, exact_match)
|
||||
|
||||
func is_action_just_released(action: StringName, device: int = controller_id, 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(action, currently_held, current_frame)
|
||||
return not currently_held and action_state.release_frame == current_frame
|
||||
|
||||
return Input.is_action_just_released(action, exact_match)
|
||||
|
||||
func get_action_state(action: String) -> SteamActionState:
|
||||
if not action_states.has(action):
|
||||
action_states[action] = SteamActionState.new()
|
||||
return action_states[action]
|
||||
|
||||
|
||||
func set_action_state(action: StringName, currently_held: bool, current_frame: int) -> SteamActionState:
|
||||
var previous_action_state = get_action_state(action)
|
||||
|
||||
if currently_held and not previous_action_state.held:
|
||||
action_states[action].pressed = true
|
||||
action_states[action].frame_pressed = current_frame
|
||||
|
||||
elif not currently_held and previous_action_state.pressed:
|
||||
action_states[action].pressed = false
|
||||
action_states[action].frame_released = current_frame
|
||||
|
||||
return action_states[action]
|
||||
|
||||
|
||||
|
||||
func _on_controller_connect(input_handle) -> void:
|
||||
controller_id = input_handle
|
||||
get_handles()
|
||||
# a timer for a delayed reload of glyphs/icons as sometimes, Steam loads the wrong ones
|
||||
|
||||
call_deferred("_delayed_reload", [10])
|
||||
|
||||
Steam.run_callbacks()
|
||||
Steam.runFrame()
|
||||
|
||||
_preload_glyphs()
|
||||
set_glyphs()
|
||||
|
||||
|
||||
func _on_controller_disconnect(_input_handle) -> void:
|
||||
actions.clear()
|
||||
action_states.clear()
|
||||
action_glyphs.clear()
|
||||
got_handles = false
|
||||
# to pause the game if controller is disconnected while in game
|
||||
get_node("/root/Game").on_controller_disconnect()
|
||||
controller_id = -1
|
||||
set_glyphs()
|
||||
State.last_input_source = State.InputSource.KEYBOARD_MOUSE
|
||||
|
||||
|
||||
func _on_set_change(new_context: State.GameContext) -> void:
|
||||
current_action_set = action_set_ids["game_control_actios"] if new_context == State.GameContext.WALK else action_set_ids["menu_control_actions"]
|
||||
|
||||
|
||||
func _preload_glyphs() -> void:
|
||||
var action_sets := action_set_ids.values()
|
||||
|
||||
for set_id in action_sets:
|
||||
Steam.activateActionSet(controller_id, set_id)
|
||||
Steam.runFrame()
|
||||
|
||||
for action_name in actions.keys():
|
||||
var origins := []
|
||||
|
||||
if analog_actions.has(action_name):
|
||||
origins = Steam.getAnalogActionOrigins(controller_id, set_id, actions[action_name])
|
||||
else:
|
||||
origins = Steam.getDigitalActionOrigins(controller_id, set_id, actions[action_name])
|
||||
|
||||
if origins.size() == 0:
|
||||
continue
|
||||
|
||||
var style := Steam.INPUT_GLYPH_STYLE_DARK | Steam.INPUT_GLYPH_STYLE_SOLID_ABXY
|
||||
var path = Steam.getGlyphPNGForActionOrigin(origins[0], Steam.INPUT_GLYPH_SIZE_LARGE, style)
|
||||
var img = Image.new()
|
||||
if img.load(path) == OK:
|
||||
var tex :Texture2D = ImageTexture.create_from_image(img)
|
||||
action_glyphs[action_name] = tex
|
||||
glyphs_loaded.emit()
|
||||
|
||||
|
||||
func get_glyph(action_name: StringName) -> Texture2D:
|
||||
if action_glyphs.has(action_name):
|
||||
return action_glyphs[action_name]
|
||||
else:
|
||||
var placeholder = PlaceholderTexture2D.new()
|
||||
placeholder.size = Vector2(64, 64)
|
||||
return placeholder
|
||||
|
||||
|
||||
func _delayed_reload(delay: float):
|
||||
await get_tree().create_timer(delay).timeout
|
||||
var current_set: int = current_action_set
|
||||
_preload_glyphs()
|
||||
set_glyphs()
|
||||
current_action_set = current_set
|
||||
Steam.runFrame()
|
||||
|
||||
func set_glyphs():
|
||||
pass
|
||||
|
||||
##TODO: update controller state in state!!!
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://10u2ea21g7sy
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
class_name SteamActionState extends Object
|
||||
|
||||
var pressed: bool
|
||||
var frame_pressed: int
|
||||
var frame_released: int
|
||||
|
||||
func _init(is_pressed: bool = false, first_frame_pressed: int = -1, first_frame_released: int = -1):
|
||||
self.pressed = is_pressed
|
||||
self.frame_pressed = first_frame_pressed
|
||||
self.frame_released = first_frame_released
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://ba1kym4lim7lq
|
||||
Loading…
Reference in New Issue