frame-of-mind/src/addons/input_prompts/action_prompt/action_prompt.gd

157 lines
4.7 KiB
GDScript3
Raw Normal View History

2025-01-16 15:06:46 +00:00
# Copyright (C) 2022-2023 John Pennycook
# SPDX-License-Identifier: MIT
@tool
@icon("res://addons/input_prompts/action_prompt/icon.svg")
class_name ActionPrompt
extends "res://addons/input_prompts/input_prompt.gd"
## Displays a prompt based on an action registered in the [InputMap].
##
## Displays a prompt based on an action registered in the [InputMap].
## The texture used for the prompt is determined automatically, based on the
## contents of the [InputMap] and an icon preference. When the icon preference
## is set to "Automatic", the prompt automatically adjusts to match the most
## recent input device.
## The name of an action registered in the [InputMap].
var action := "ui_accept":
set = _set_action
## The icon preference for this prompt:
## Automatic (0), Xbox (1), Sony (2), Nintendo (3), Keyboard (4).
## When set to "Automatic", the prompt automatically adjusts to match the most
## recent input device.
var icon: int = Icons.AUTOMATIC:
set = _set_icon
func _ready():
ProjectSettings.settings_changed.connect(_update_events)
_update_events()
_update_icon()
func _set_action(new_action: String):
action = new_action
_update_events()
_update_icon()
func _set_icon(new_icon):
icon = new_icon
_update_icon()
func _update_events():
# In the Editor, InputMap reflects Editor settings
# Read the list of actions from ProjectSettings instead
# TODO: Find a cleaner way to cast these values
var tmp: Array = []
if Engine.is_editor_hint():
tmp = ProjectSettings.get_setting("input/" + action)["events"]
else:
tmp = InputMap.action_get_events(action)
events = []
for ev in tmp:
events.append(ev)
update_configuration_warnings()
func _find_event(list: Array, types: Array):
for candidate in list:
for type in types:
if is_instance_of(candidate, type):
return candidate
return null
func _update_icon():
# If icon is set to AUTOMATIC, first determine which icon to display
var display_icon: int = icon
if icon == Icons.AUTOMATIC:
display_icon = PromptManager.icons
# Choose the atlas and region associated with the InputEvent
# If the InputMap contains multiple events, choose the first
if display_icon == Icons.KEYBOARD:
var types = [InputEventKey, InputEventMouseButton]
var ev = _find_event(events, types)
if ev is InputEventKey:
var textures := PromptManager.get_keyboard_textures()
texture = textures.get_texture(ev)
elif ev is InputEventMouseButton:
var textures := PromptManager.get_mouse_textures()
texture = textures.get_texture(ev)
else:
var types = [InputEventJoypadButton, InputEventJoypadMotion]
var ev = _find_event(events, types)
if ev is InputEventJoypadButton:
var textures := PromptManager.get_joypad_button_textures(display_icon)
texture = textures.get_texture(ev)
elif ev is InputEventJoypadMotion:
var textures := PromptManager.get_joypad_motion_textures(display_icon)
texture = textures.get_texture(ev)
queue_redraw()
func _refresh():
_update_events()
_update_icon()
func _input(event: InputEvent):
if not event.is_action_pressed(action):
return
emit_signal("pressed")
func _get_property_list():
var properties = []
properties.append(
{
name = "ActionPrompt",
type = TYPE_NIL,
usage = PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_SCRIPT_VARIABLE
}
)
# In the Editor, InputMap reflects Editor settings
# Read the list of actions from ProjectSettings instead
var actions: String = ""
for property in ProjectSettings.get_property_list():
var name = property["name"]
if name.begins_with("input/"):
if actions != "":
actions += ","
actions += name.trim_prefix("input/")
properties.append(
{name = "action", type = TYPE_STRING, hint = PROPERTY_HINT_ENUM, hint_string = actions}
)
properties.append(
{
name = "icon",
type = TYPE_INT,
hint = PROPERTY_HINT_ENUM,
hint_string = "Automatic,Xbox,Sony,Nintendo,Keyboard"
}
)
return properties
func _get_configuration_warnings() -> PackedStringArray:
var warnings: PackedStringArray = []
# Check that the action is associated with Keyboard/Mouse in the InputMap
if icon == Icons.AUTOMATIC or icon == Icons.KEYBOARD:
var types = [InputEventKey, InputEventMouseButton]
var ev = _find_event(events, types)
if not (ev is InputEventKey or ev is InputEventMouseButton):
warnings.append("No Key/Mouse input for " + action + " in InputMap.")
# Check that the action is associated with Joypad in the InputMap
if icon == Icons.AUTOMATIC or icon != Icons.KEYBOARD:
var types = [InputEventJoypadButton, InputEventJoypadMotion]
var ev = _find_event(events, types)
if not (ev is InputEventJoypadButton or ev is InputEventJoypadMotion):
warnings.append("No Joypad input for " + action + " in InputMap.")
return warnings