157 lines
4.7 KiB
GDScript3
157 lines
4.7 KiB
GDScript3
|
|
# 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
|