Compare commits

...

3 Commits

11 changed files with 163 additions and 50 deletions

1
.gitignore vendored
View File

@ -3,7 +3,6 @@
# Godot-specific ignores # Godot-specific ignores
.import/ .import/
override.cfg
export.cfg export.cfg
export_presets.cfg export_presets.cfg

View File

@ -1,4 +1,6 @@
keys,en keys,en
UI_UNSET,unset
UI_LISTEN,listening...
ACTION_camera_forward,"Forward (free camera)" ACTION_camera_forward,"Forward (free camera)"
ACTION_camera_back,"Backward (free camera)" ACTION_camera_back,"Backward (free camera)"
ACTION_camera_left,"Left (free camera)" ACTION_camera_left,"Left (free camera)"

1 keys en
2 UI_UNSET unset
3 UI_LISTEN listening...
4 ACTION_camera_forward Forward (free camera)
5 ACTION_camera_back Backward (free camera)
6 ACTION_camera_left Left (free camera)

View File

@ -13,6 +13,7 @@ config_version=5
config/name="GFOLF 2" config/name="GFOLF 2"
config/description="GFOLF: Combat Golf Action" config/description="GFOLF: Combat Golf Action"
run/main_scene="res://src/game/game.tscn" run/main_scene="res://src/game/game.tscn"
config/project_settings_override="user://settings.godot"
config/features=PackedStringArray("4.3", "Forward Plus") config/features=PackedStringArray("4.3", "Forward Plus")
run/max_fps=60 run/max_fps=60
@ -20,6 +21,7 @@ run/max_fps=60
ClubCatalog="*res://src/equipment/clubs/club_catalog.tscn" ClubCatalog="*res://src/equipment/clubs/club_catalog.tscn"
GameSettings="*res://src/game/game_settings.gd" GameSettings="*res://src/game/game_settings.gd"
BindingLoader="*res://src/game/binding_loader.gd"
[debug] [debug]
@ -163,6 +165,31 @@ select_putter={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":53,"key_label":0,"unicode":53,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":53,"key_label":0,"unicode":53,"location":0,"echo":false,"script":null)
] ]
} }
club_next={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(105, 13),"global_position":Vector2(114, 59),"factor":1.0,"button_index":8,"canceled":false,"pressed":true,"double_click":false,"script":null)
]
}
club_previous={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(277, 2),"global_position":Vector2(286, 48),"factor":1.0,"button_index":9,"canceled":false,"pressed":true,"double_click":false,"script":null)
]
}
ball_next={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
ball_previous={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
pause={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
debug_1={ debug_1={
"deadzone": 0.5, "deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194332,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194332,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
@ -183,30 +210,9 @@ debug_4={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194335,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194335,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
] ]
} }
pause={ debug_5={
"deadzone": 0.5, "deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) "events": []
]
}
ball_next={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
ball_previous={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
club_next={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(105, 13),"global_position":Vector2(114, 59),"factor":1.0,"button_index":8,"canceled":false,"pressed":true,"double_click":false,"script":null)
]
}
club_previous={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(277, 2),"global_position":Vector2(286, 48),"factor":1.0,"button_index":9,"canceled":false,"pressed":true,"double_click":false,"script":null)
]
} }
[internationalization] [internationalization]

View File

@ -0,0 +1,35 @@
class_name BindingLoaderType extends Node
## Handles persisting action input bindings.
const BINDINGS_FILE := "user://bindings.tres"
func _ready() -> void:
# Map may not be defined if no keybinds have been written
if FileAccess.file_exists(BINDINGS_FILE):
print_debug("Reading keybinds from ", BINDINGS_FILE)
var map: BindingMap = load(BINDINGS_FILE) as BindingMap
# Overwrite InputMap with loaded bindings
for action: StringName in map.bindings.keys():
# Clear existing bindings
InputMap.action_erase_events(action)
# Apply loaded binding
var event: InputEvent = map.bindings[action]
if event:
InputMap.action_add_event(action, event)
func write() -> void:
# Build map from input actions
var map: BindingMap = BindingMap.new()
for action: StringName in InputMap.get_actions():
var events := InputMap.action_get_events(action)
if events:
map.bindings[action] = events[0]
else:
map.bindings[action] = null
# Write to disk
print_debug("Writing keybinds to ", BINDINGS_FILE)
ResourceSaver.save(map, BINDINGS_FILE)

View File

@ -1,6 +1,8 @@
class_name GameSettingsType extends Node class_name GameSettingsType extends Node
## Container for project settings, for quick runtime access. ## Container for project settings, for quick runtime access.
var settings_file: String
var free_camera_speed: float var free_camera_speed: float
var x_sensitivity: float var x_sensitivity: float
var y_sensitivity: float var y_sensitivity: float
@ -16,6 +18,8 @@ func _init() -> void:
func _read_settings() -> void: func _read_settings() -> void:
settings_file = ProjectSettings.get_setting("application/config/project_settings_override")
free_camera_speed = ProjectSettings.get_setting("game/config/controls/camera/free_camera_speed") free_camera_speed = ProjectSettings.get_setting("game/config/controls/camera/free_camera_speed")
x_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/x_axis_sensitivity") x_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/x_axis_sensitivity")
y_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/y_axis_sensitivity") y_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/y_axis_sensitivity")

View File

@ -80,6 +80,11 @@ HeaderMedium/font_sizes/font_size = 24
HeaderSmall/font_sizes/font_size = 20 HeaderSmall/font_sizes/font_size = 20
HeaderXLarge/base_type = &"Label" HeaderXLarge/base_type = &"Label"
HeaderXLarge/font_sizes/font_size = 36 HeaderXLarge/font_sizes/font_size = 36
InputBindButton/base_type = &"UIButton"
InputBindButton/colors/font_color = Color(1, 1, 0.870588, 1)
InputBindButton/constants/outline_size = 8
InputBindButton/font_sizes/font_size = 32
InputBindButton/fonts/font = ExtResource("2_8kux8")
InputPrompt/base_type = &"Label" InputPrompt/base_type = &"Label"
InputPrompt/colors/font_color = Color(1, 1, 0.870588, 1) InputPrompt/colors/font_color = Color(1, 1, 0.870588, 1)
InputPrompt/constants/outline_size = 8 InputPrompt/constants/outline_size = 8

View File

@ -2,12 +2,21 @@ class_name ControlBinding extends CheckerContainer
## Input for rebinding an action. ## Input for rebinding an action.
const ACTION_KEY_FMT := "ACTION_{0}" const ACTION_KEY_FMT := "ACTION_{0}"
const LISTENING_TEXT := "UI_LISTEN"
const SCENE := preload("res://src/ui/menus/settings_menu/control_binding/control_binding.tscn") const SCENE := preload("res://src/ui/menus/settings_menu/control_binding/control_binding.tscn")
const MOTION_THRESHOLD := 0.5
@export var key: StringName @export var key: StringName
var listening: bool = false:
set(value):
if button:
button.disabled = value
listening = value
@onready var action: Label = %Action @onready var action: Label = %Action
@onready var binding: Label = %Binding @onready var button: Button = %Button
func _ready() -> void: func _ready() -> void:
@ -21,10 +30,73 @@ func _ready() -> void:
action.text = loc_action if loc_action else key action.text = loc_action if loc_action else key
# Set the binding label # Set the binding label
_set_label_from_binding()
func _set_label_from_binding() -> void:
var actions := InputMap.action_get_events(key) var actions := InputMap.action_get_events(key)
if actions: if actions:
var primary := actions[0] var primary := actions[0]
binding.text = PromptMap.from_event(primary) button.text = PromptMap.from_event(primary)
if button.text == PromptMap.UNKNOWN_INPUT_SYMBOL:
print_debug("No mapping for input event: ", primary)
# Special case: Can't rebind things bound to ESC
if primary is InputEventKey and (primary as InputEventKey).physical_keycode == KEY_ESCAPE:
button.disabled = true
func _input(event: InputEvent) -> void:
if not listening:
return
if event is InputEventKey:
var key_event: InputEventKey = event
if (
key_event.physical_keycode in [KEY_CTRL, KEY_ALT, KEY_SHIFT, KEY_META]
and key_event.pressed
):
# Ignore modifier key until release
return
if key_event.physical_keycode == KEY_ESCAPE:
get_viewport().set_input_as_handled()
cancel_rebinding()
return
if event is InputEventJoypadMotion:
var motion_event: InputEventJoypadMotion = event
if abs(motion_event.axis_value) < MOTION_THRESHOLD:
# Ignore axis motion unless it's over our threshold
return
if (
event is InputEventKey
or event is InputEventMouseButton
or event is InputEventJoypadButton
or event is InputEventJoypadMotion
):
get_viewport().set_input_as_handled()
rebind(event)
func start_listening() -> void:
button.text = LISTENING_TEXT
listening = true
func cancel_rebinding() -> void:
_set_label_from_binding()
listening = false
func rebind(event: InputEvent) -> void:
# Clear previous binding
InputMap.action_erase_events(key)
# Add new binding
InputMap.action_add_event(key, event)
# Update label
_set_label_from_binding()
listening = false
static func create(_key: StringName) -> ControlBinding: static func create(_key: StringName) -> ControlBinding:

View File

@ -28,21 +28,7 @@ text = "Action"
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(300, 42) custom_minimum_size = Vector2(300, 42)
layout_mode = 2 layout_mode = 2
theme_type_variation = &"InputBindButton"
text = "UI_UNSET"
[node name="Binding" type="Label" parent="MarginContainer/HBoxContainer/Button"] [connection signal="pressed" from="MarginContainer/HBoxContainer/Button" to="." method="start_listening"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -13.0
offset_top = -19.5
offset_right = 13.0
offset_bottom = 19.5
grow_horizontal = 2
grow_vertical = 2
theme_type_variation = &"InputPrompt"
text = "unset"
horizontal_alignment = 1

View File

@ -2,7 +2,6 @@ extends MarginContainer
## Menu allowing the user to adjust game configuration. ## Menu allowing the user to adjust game configuration.
const SETTINGS_GROUP := "Settings" const SETTINGS_GROUP := "Settings"
const SETTINGS_FILE := "override.cfg"
@onready var control_binding_list: VBoxContainer = %ControlBindingList @onready var control_binding_list: VBoxContainer = %ControlBindingList
@ -18,7 +17,6 @@ func _get_settings_elements() -> Array[Setting]:
func populate_control_bindings() -> void: func populate_control_bindings() -> void:
InputMap.get
for action: StringName in InputMap.get_actions(): for action: StringName in InputMap.get_actions():
if not action.begins_with("ui_"): if not action.begins_with("ui_"):
control_binding_list.add_child(ControlBinding.create(action)) control_binding_list.add_child(ControlBinding.create(action))
@ -37,7 +35,9 @@ func apply() -> void:
## Write all applied settings to disk. ## Write all applied settings to disk.
func save_settings() -> void: func save_settings() -> void:
ProjectSettings.save_custom(SETTINGS_FILE) print_debug("Writing settings to ", Game.settings.settings_file)
ProjectSettings.save_custom(Game.settings.settings_file)
BindingLoader.write()
## Apply settings and close menu. ## Apply settings and close menu.

4
src/util/binding_map.gd Normal file
View File

@ -0,0 +1,4 @@
class_name BindingMap extends Resource
## Serializable action input map. Used by `BindingLoader`.
@export var bindings: Dictionary

View File

@ -96,10 +96,10 @@ const MOUSE := {
MOUSE_BUTTON_LEFT: PromptFont.MOUSE_1, MOUSE_BUTTON_LEFT: PromptFont.MOUSE_1,
MOUSE_BUTTON_RIGHT: PromptFont.MOUSE_2, MOUSE_BUTTON_RIGHT: PromptFont.MOUSE_2,
MOUSE_BUTTON_MIDDLE: PromptFont.MOUSE_3, MOUSE_BUTTON_MIDDLE: PromptFont.MOUSE_3,
MOUSE_BUTTON_XBUTTON1: PromptFont.MOUSE_4, MOUSE_BUTTON_WHEEL_LEFT: PromptFont.MOUSE_4,
MOUSE_BUTTON_XBUTTON2: PromptFont.MOUSE_5, MOUSE_BUTTON_WHEEL_RIGHT: PromptFont.MOUSE_5,
# PromptFont.MOUSE_6, MOUSE_BUTTON_XBUTTON1: PromptFont.MOUSE_6,
# PromptFont.MOUSE_7, MOUSE_BUTTON_XBUTTON2: PromptFont.MOUSE_7,
# PromptFont.MOUSE_8, # PromptFont.MOUSE_8,
MOUSE_BUTTON_WHEEL_UP: PromptFont.MOUSE_SCROLL_UP, MOUSE_BUTTON_WHEEL_UP: PromptFont.MOUSE_SCROLL_UP,
MOUSE_BUTTON_WHEEL_DOWN: PromptFont.MOUSE_SCROLL_DOWN MOUSE_BUTTON_WHEEL_DOWN: PromptFont.MOUSE_SCROLL_DOWN