generated from krampus/template-godot4
	Compare commits
	
		
			3 Commits
		
	
	
		
			01df07eb11
			...
			f75af2196d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f75af2196d | |||
| dff8065f95 | |||
| b780bb5a2c | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -3,7 +3,6 @@ | ||||
| 
 | ||||
| # Godot-specific ignores | ||||
| .import/ | ||||
| override.cfg | ||||
| export.cfg | ||||
| export_presets.cfg | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,6 @@ | ||||
| keys,en | ||||
| UI_UNSET,unset | ||||
| UI_LISTEN,listening... | ||||
| ACTION_camera_forward,"Forward (free camera)" | ||||
| ACTION_camera_back,"Backward (free camera)" | ||||
| ACTION_camera_left,"Left (free camera)" | ||||
|  | ||||
| 
 | 
| @ -13,6 +13,7 @@ config_version=5 | ||||
| config/name="GFOLF 2" | ||||
| config/description="GFOLF: Combat Golf Action" | ||||
| run/main_scene="res://src/game/game.tscn" | ||||
| config/project_settings_override="user://settings.godot" | ||||
| config/features=PackedStringArray("4.3", "Forward Plus") | ||||
| run/max_fps=60 | ||||
| 
 | ||||
| @ -20,6 +21,7 @@ run/max_fps=60 | ||||
| 
 | ||||
| ClubCatalog="*res://src/equipment/clubs/club_catalog.tscn" | ||||
| GameSettings="*res://src/game/game_settings.gd" | ||||
| BindingLoader="*res://src/game/binding_loader.gd" | ||||
| 
 | ||||
| [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) | ||||
| ] | ||||
| } | ||||
| 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={ | ||||
| "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) | ||||
| @ -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) | ||||
| ] | ||||
| } | ||||
| pause={ | ||||
| debug_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) | ||||
| ] | ||||
| } | ||||
| 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) | ||||
| ] | ||||
| "events": [] | ||||
| } | ||||
| 
 | ||||
| [internationalization] | ||||
|  | ||||
							
								
								
									
										35
									
								
								src/game/binding_loader.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/game/binding_loader.gd
									
									
									
									
									
										Normal 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) | ||||
| @ -1,6 +1,8 @@ | ||||
| class_name GameSettingsType extends Node | ||||
| ## Container for project settings, for quick runtime access. | ||||
| 
 | ||||
| var settings_file: String | ||||
| 
 | ||||
| var free_camera_speed: float | ||||
| var x_sensitivity: float | ||||
| var y_sensitivity: float | ||||
| @ -16,6 +18,8 @@ func _init() -> 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") | ||||
| 	x_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/x_axis_sensitivity") | ||||
| 	y_sensitivity = ProjectSettings.get_setting("game/config/controls/camera/y_axis_sensitivity") | ||||
|  | ||||
| @ -80,6 +80,11 @@ HeaderMedium/font_sizes/font_size = 24 | ||||
| HeaderSmall/font_sizes/font_size = 20 | ||||
| HeaderXLarge/base_type = &"Label" | ||||
| 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/colors/font_color = Color(1, 1, 0.870588, 1) | ||||
| InputPrompt/constants/outline_size = 8 | ||||
|  | ||||
| @ -2,12 +2,21 @@ class_name ControlBinding extends CheckerContainer | ||||
| ## Input for rebinding an action. | ||||
| 
 | ||||
| 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 MOTION_THRESHOLD := 0.5 | ||||
| 
 | ||||
| @export var key: StringName | ||||
| 
 | ||||
| var listening: bool = false: | ||||
| 	set(value): | ||||
| 		if button: | ||||
| 			button.disabled = value | ||||
| 		listening = value | ||||
| 
 | ||||
| @onready var action: Label = %Action | ||||
| @onready var binding: Label = %Binding | ||||
| @onready var button: Button = %Button | ||||
| 
 | ||||
| 
 | ||||
| func _ready() -> void: | ||||
| @ -21,10 +30,73 @@ func _ready() -> void: | ||||
| 	action.text = loc_action if loc_action else key | ||||
| 
 | ||||
| 	# Set the binding label | ||||
| 	_set_label_from_binding() | ||||
| 
 | ||||
| 
 | ||||
| func _set_label_from_binding() -> void: | ||||
| 	var actions := InputMap.action_get_events(key) | ||||
| 	if actions: | ||||
| 		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: | ||||
|  | ||||
| @ -28,21 +28,7 @@ text = "Action" | ||||
| unique_name_in_owner = true | ||||
| custom_minimum_size = Vector2(300, 42) | ||||
| layout_mode = 2 | ||||
| theme_type_variation = &"InputBindButton" | ||||
| text = "UI_UNSET" | ||||
| 
 | ||||
| [node name="Binding" type="Label" parent="MarginContainer/HBoxContainer/Button"] | ||||
| 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 | ||||
| [connection signal="pressed" from="MarginContainer/HBoxContainer/Button" to="." method="start_listening"] | ||||
|  | ||||
| @ -2,7 +2,6 @@ extends MarginContainer | ||||
| ## Menu allowing the user to adjust game configuration. | ||||
| 
 | ||||
| const SETTINGS_GROUP := "Settings" | ||||
| const SETTINGS_FILE := "override.cfg" | ||||
| 
 | ||||
| @onready var control_binding_list: VBoxContainer = %ControlBindingList | ||||
| 
 | ||||
| @ -18,7 +17,6 @@ func _get_settings_elements() -> Array[Setting]: | ||||
| 
 | ||||
| 
 | ||||
| func populate_control_bindings() -> void: | ||||
| 	InputMap.get | ||||
| 	for action: StringName in InputMap.get_actions(): | ||||
| 		if not action.begins_with("ui_"): | ||||
| 			control_binding_list.add_child(ControlBinding.create(action)) | ||||
| @ -37,7 +35,9 @@ func apply() -> void: | ||||
| 
 | ||||
| ## Write all applied settings to disk. | ||||
| 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. | ||||
|  | ||||
							
								
								
									
										4
									
								
								src/util/binding_map.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/util/binding_map.gd
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| class_name BindingMap extends Resource | ||||
| ## Serializable action input map. Used by `BindingLoader`. | ||||
| 
 | ||||
| @export var bindings: Dictionary | ||||
| @ -96,10 +96,10 @@ const MOUSE := { | ||||
| 	MOUSE_BUTTON_LEFT: PromptFont.MOUSE_1, | ||||
| 	MOUSE_BUTTON_RIGHT: PromptFont.MOUSE_2, | ||||
| 	MOUSE_BUTTON_MIDDLE: PromptFont.MOUSE_3, | ||||
| 	MOUSE_BUTTON_XBUTTON1: PromptFont.MOUSE_4, | ||||
| 	MOUSE_BUTTON_XBUTTON2: PromptFont.MOUSE_5, | ||||
| 	# PromptFont.MOUSE_6, | ||||
| 	# PromptFont.MOUSE_7, | ||||
| 	MOUSE_BUTTON_WHEEL_LEFT: PromptFont.MOUSE_4, | ||||
| 	MOUSE_BUTTON_WHEEL_RIGHT: PromptFont.MOUSE_5, | ||||
| 	MOUSE_BUTTON_XBUTTON1: PromptFont.MOUSE_6, | ||||
| 	MOUSE_BUTTON_XBUTTON2: PromptFont.MOUSE_7, | ||||
| 	# PromptFont.MOUSE_8, | ||||
| 	MOUSE_BUTTON_WHEEL_UP: PromptFont.MOUSE_SCROLL_UP, | ||||
| 	MOUSE_BUTTON_WHEEL_DOWN: PromptFont.MOUSE_SCROLL_DOWN | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user