action_prompt.gd 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. # Copyright (C) 2022-2023 John Pennycook
  2. # SPDX-License-Identifier: MIT
  3. @tool
  4. @icon("res://addons/input_prompts/action_prompt/icon.svg")
  5. class_name ActionPrompt
  6. extends "res://addons/input_prompts/input_prompt.gd"
  7. ## Displays a prompt based on an action registered in the [InputMap].
  8. ##
  9. ## Displays a prompt based on an action registered in the [InputMap].
  10. ## The texture used for the prompt is determined automatically, based on the
  11. ## contents of the [InputMap] and an icon preference. When the icon preference
  12. ## is set to "Automatic", the prompt automatically adjusts to match the most
  13. ## recent input device.
  14. ## The name of an action registered in the [InputMap].
  15. var action := "ui_accept":
  16. set = _set_action
  17. ## The icon preference for this prompt:
  18. ## Automatic (0), Xbox (1), Sony (2), Nintendo (3), Keyboard (4).
  19. ## When set to "Automatic", the prompt automatically adjusts to match the most
  20. ## recent input device.
  21. var icon: int = Icons.AUTOMATIC:
  22. set = _set_icon
  23. func _ready():
  24. ProjectSettings.settings_changed.connect(_update_events)
  25. _update_events()
  26. _update_icon()
  27. func _set_action(new_action: String):
  28. action = new_action
  29. _update_events()
  30. _update_icon()
  31. func _set_icon(new_icon):
  32. icon = new_icon
  33. _update_icon()
  34. func _update_events():
  35. # In the Editor, InputMap reflects Editor settings
  36. # Read the list of actions from ProjectSettings instead
  37. # TODO: Find a cleaner way to cast these values
  38. var tmp: Array = []
  39. if Engine.is_editor_hint():
  40. tmp = ProjectSettings.get_setting("input/" + action)["events"]
  41. else:
  42. tmp = InputMap.action_get_events(action)
  43. events = []
  44. for ev in tmp:
  45. events.append(ev)
  46. update_configuration_warnings()
  47. func _find_event(list: Array, types: Array):
  48. for candidate in list:
  49. for type in types:
  50. if is_instance_of(candidate, type):
  51. return candidate
  52. return null
  53. func _update_icon():
  54. # If icon is set to AUTOMATIC, first determine which icon to display
  55. var display_icon: int = icon
  56. if icon == Icons.AUTOMATIC:
  57. display_icon = PromptManager.icons
  58. # Choose the atlas and region associated with the InputEvent
  59. # If the InputMap contains multiple events, choose the first
  60. if display_icon == Icons.KEYBOARD:
  61. var types = [InputEventKey, InputEventMouseButton]
  62. var ev = _find_event(events, types)
  63. if ev is InputEventKey:
  64. var textures := PromptManager.get_keyboard_textures()
  65. texture = textures.get_texture(ev)
  66. elif ev is InputEventMouseButton:
  67. var textures := PromptManager.get_mouse_textures()
  68. texture = textures.get_texture(ev)
  69. else:
  70. var types = [InputEventJoypadButton, InputEventJoypadMotion]
  71. var ev = _find_event(events, types)
  72. if ev is InputEventJoypadButton:
  73. var textures := PromptManager.get_joypad_button_textures(display_icon)
  74. texture = textures.get_texture(ev)
  75. elif ev is InputEventJoypadMotion:
  76. var textures := PromptManager.get_joypad_motion_textures(display_icon)
  77. texture = textures.get_texture(ev)
  78. queue_redraw()
  79. func _refresh():
  80. _update_events()
  81. _update_icon()
  82. func _input(event: InputEvent):
  83. if not event.is_action_pressed(action):
  84. return
  85. emit_signal("pressed")
  86. func _get_property_list():
  87. var properties = []
  88. properties.append(
  89. {
  90. name = "ActionPrompt",
  91. type = TYPE_NIL,
  92. usage = PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_SCRIPT_VARIABLE
  93. }
  94. )
  95. # In the Editor, InputMap reflects Editor settings
  96. # Read the list of actions from ProjectSettings instead
  97. var actions: String = ""
  98. for property in ProjectSettings.get_property_list():
  99. var name = property["name"]
  100. if name.begins_with("input/"):
  101. if actions != "":
  102. actions += ","
  103. actions += name.trim_prefix("input/")
  104. properties.append(
  105. {name = "action", type = TYPE_STRING, hint = PROPERTY_HINT_ENUM, hint_string = actions}
  106. )
  107. properties.append(
  108. {
  109. name = "icon",
  110. type = TYPE_INT,
  111. hint = PROPERTY_HINT_ENUM,
  112. hint_string = "Automatic,Xbox,Sony,Nintendo,Keyboard"
  113. }
  114. )
  115. return properties
  116. func _get_configuration_warnings() -> PackedStringArray:
  117. var warnings: PackedStringArray = []
  118. # Check that the action is associated with Keyboard/Mouse in the InputMap
  119. if icon == Icons.AUTOMATIC or icon == Icons.KEYBOARD:
  120. var types = [InputEventKey, InputEventMouseButton]
  121. var ev = _find_event(events, types)
  122. if not (ev is InputEventKey or ev is InputEventMouseButton):
  123. warnings.append("No Key/Mouse input for " + action + " in InputMap.")
  124. # Check that the action is associated with Joypad in the InputMap
  125. if icon == Icons.AUTOMATIC or icon != Icons.KEYBOARD:
  126. var types = [InputEventJoypadButton, InputEventJoypadMotion]
  127. var ev = _find_event(events, types)
  128. if not (ev is InputEventJoypadButton or ev is InputEventJoypadMotion):
  129. warnings.append("No Joypad input for " + action + " in InputMap.")
  130. return warnings