diff --git a/gui/input_mapping/controls.gd b/gui/input_mapping/controls.gd index d1ba10d7..3eb5b6f9 100644 --- a/gui/input_mapping/controls.gd +++ b/gui/input_mapping/controls.gd @@ -1,4 +1,3 @@ - extends Control # Note for the reader: @@ -12,45 +11,91 @@ extends Control # action and the node, e.g.: # button.connect("pressed", self, "wait_for_input", [ button, action ]) +# Constants +const INPUT_ACTIONS = [ "move_up", "move_down", "move_left", "move_right", "jump" ] +const CONFIG_FILE = "user://input.cfg" + # Member variables -var player_actions = [ "move_up", "move_down", "move_left", "move_right", "jump" ] var action # To register the action the UI is currently handling var button # Button node corresponding to the above action +# Load/save input mapping to a config file +# Changes done while testing the demo will be persistent, saved to CONFIG_FILE + +func load_config(): + var config = ConfigFile.new() + var err = config.load(CONFIG_FILE) + if err: # Assuming that file is missing, generate default config + for action_name in INPUT_ACTIONS: + var action_list = InputMap.get_action_list(action_name) + # There could be multiple actions in the list, but we save the first one by default + var scancode = OS.get_scancode_string(action_list[0].scancode) + config.set_value("input", action_name, scancode) + config.save(CONFIG_FILE) + else: # ConfigFile was properly loaded, initialize InputMap + for action_name in config.get_section_keys("input"): + # Get the key scancode corresponding to the saved human-readable string + var scancode = OS.find_scancode_from_string(config.get_value("input", action_name)) + # Create a new event object based on the saved scancode + var event = InputEventKey.new() + event.scancode = scancode + # Replace old action (key) events by the new one + for old_event in InputMap.get_action_list(action_name): + if old_event is InputEventKey: + InputMap.action_erase_event(action_name, old_event) + InputMap.action_add_event(action_name, event) + + +func save_to_config(section, key, value): + """Helper function to redefine a parameter in the settings file""" + var config = ConfigFile.new() + var err = config.load(CONFIG_FILE) + if err: + print("Error code when loading config file: ", err) + else: + config.set_value(section, key, value) + config.save(CONFIG_FILE) + + +# Input management + func wait_for_input(action_bind): action = action_bind # See note at the beginning of the script button = get_node("bindings").get_node(action).get_node("Button") - get_node("contextual_help").text="Press a key to assign to the '" + action + "' action." + get_node("contextual_help").text = "Press a key to assign to the '" + action + "' action." set_process_input(true) func _input(event): # Handle the first pressed key - if (event is InputEventKey): + if event is InputEventKey: # Register the event as handled and stop polling get_tree().set_input_as_handled() set_process_input(false) # Reinitialise the contextual help label - get_node("contextual_help").text="Click a key binding to reassign it, or press the Cancel action." - if (not event.is_action("ui_cancel")): + get_node("contextual_help").text = "Click a key binding to reassign it, or press the Cancel action." + if not event.is_action("ui_cancel"): # Display the string corresponding to the pressed key - button.text=OS.get_scancode_string(event.scancode) + var scancode = OS.get_scancode_string(event.scancode) + button.text = scancode # Start by removing previously key binding(s) for old_event in InputMap.get_action_list(action): InputMap.action_erase_event(action, old_event) # Add the new key binding InputMap.action_add_event(action, event) + save_to_config("input", action, scancode) func _ready(): + # Load config if existing, if not it will be generated with default values + load_config() # Initialise each button with the default key binding from InputMap - var input_event - for action in player_actions: + for action in INPUT_ACTIONS: # We assume that the key binding that we want is the first one (0), if there are several - input_event = InputMap.get_action_list(action)[0] + var input_event = InputMap.get_action_list(action)[0] # See note at the beginning of the script var button = get_node("bindings").get_node(action).get_node("Button") - button.text=OS.get_scancode_string(input_event.scancode) + button.text = OS.get_scancode_string(input_event.scancode) button.connect("pressed", self, "wait_for_input", [action]) diff --git a/gui/input_mapping/controls.scn b/gui/input_mapping/controls.scn deleted file mode 100644 index d2a80d39..00000000 Binary files a/gui/input_mapping/controls.scn and /dev/null differ diff --git a/gui/input_mapping/controls.tscn b/gui/input_mapping/controls.tscn new file mode 100644 index 00000000..41bbe764 --- /dev/null +++ b/gui/input_mapping/controls.tscn @@ -0,0 +1,348 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://controls.gd" type="Script" id=1] + +[node name="controls_ui" type="Control"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 40.0 +margin_bottom = 40.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 +script = ExtResource( 1 ) +__meta__ = { +"__editor_plugin_screen__": "2D" +} + +[node name="contextual_help" type="Label" parent="."] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 100.0 +margin_top = 50.0 +margin_right = 465.0 +margin_bottom = 89.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +size_flags_horizontal = 2 +size_flags_vertical = 0 +text = "Click on a key binding to reassign it, or press the Cancel action." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="bindings" type="Control" parent="."] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 50.0 +margin_top = 50.0 +margin_right = 90.0 +margin_bottom = 90.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 + +[node name="move_up" type="Control" parent="bindings"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 50.0 +margin_top = 50.0 +margin_right = 90.0 +margin_bottom = 90.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 + +[node name="Label" type="Label" parent="bindings/move_up"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 5.0 +margin_top = 8.0 +margin_right = 45.0 +margin_bottom = 21.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +size_flags_horizontal = 2 +size_flags_vertical = 0 +text = "Up" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Button" type="Button" parent="bindings/move_up"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 84.0 +margin_top = -1.0 +margin_right = 144.0 +margin_bottom = 29.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +flat = false + +[node name="move_down" type="Control" parent="bindings"] + +editor/display_folded = true +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 50.0 +margin_top = 100.0 +margin_right = 90.0 +margin_bottom = 140.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 + +[node name="Label" type="Label" parent="bindings/move_down"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 5.0 +margin_top = 8.0 +margin_right = 45.0 +margin_bottom = 21.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +size_flags_horizontal = 2 +size_flags_vertical = 0 +text = "Down" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Button" type="Button" parent="bindings/move_down"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 84.0 +margin_top = -1.0 +margin_right = 144.0 +margin_bottom = 29.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +flat = false + +[node name="move_left" type="Control" parent="bindings"] + +editor/display_folded = true +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 50.0 +margin_top = 150.0 +margin_right = 90.0 +margin_bottom = 190.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 + +[node name="Label" type="Label" parent="bindings/move_left"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 5.0 +margin_top = 8.0 +margin_right = 45.0 +margin_bottom = 21.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +size_flags_horizontal = 2 +size_flags_vertical = 0 +text = "Left" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Button" type="Button" parent="bindings/move_left"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 84.0 +margin_top = -1.0 +margin_right = 144.0 +margin_bottom = 29.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +flat = false + +[node name="move_right" type="Control" parent="bindings"] + +editor/display_folded = true +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 50.0 +margin_top = 200.0 +margin_right = 90.0 +margin_bottom = 240.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 + +[node name="Label" type="Label" parent="bindings/move_right"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 5.0 +margin_top = 8.0 +margin_right = 45.0 +margin_bottom = 21.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +size_flags_horizontal = 2 +size_flags_vertical = 0 +text = "Right" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Button" type="Button" parent="bindings/move_right"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 84.0 +margin_top = -1.0 +margin_right = 144.0 +margin_bottom = 29.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +flat = false + +[node name="jump" type="Control" parent="bindings"] + +editor/display_folded = true +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 50.0 +margin_top = 250.0 +margin_right = 90.0 +margin_bottom = 290.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 + +[node name="Label" type="Label" parent="bindings/jump"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 5.0 +margin_top = 8.0 +margin_right = 45.0 +margin_bottom = 21.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +size_flags_horizontal = 2 +size_flags_vertical = 0 +text = "Jump" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Button" type="Button" parent="bindings/jump"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 84.0 +margin_top = -1.0 +margin_right = 144.0 +margin_bottom = 29.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +size_flags_horizontal = 2 +size_flags_vertical = 2 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null +flat = false + + diff --git a/gui/input_mapping/icon.png.import b/gui/input_mapping/icon.png.import index 627820bd..42e94a35 100644 --- a/gui/input_mapping/icon.png.import +++ b/gui/input_mapping/icon.png.import @@ -21,3 +21,4 @@ process/HDR_as_SRGB=false stream=false size_limit=0 detect_3d=true +svg/scale=1.0 diff --git a/gui/input_mapping/project.godot b/gui/input_mapping/project.godot index 0ab591c3..601c23c7 100644 --- a/gui/input_mapping/project.godot +++ b/gui/input_mapping/project.godot @@ -1,18 +1,27 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + config_version=3 [application] config/name="Input Mapping GUI" -run/main_scene="res://controls.scn" +run/main_scene="res://controls.tscn" config/icon="res://icon.png" -icon="res://icon.png" -main_scene="res://controls.scn" -name="Input Mapping GUI" [display] -window/size/height=480 window/size/width=640 +window/size/height=480 + +[gdnative] + +singletons=[ ] [input]