Added touchscreen controls!
This commit is contained in:
135
src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd
Normal file
135
src/addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd
Normal file
@@ -0,0 +1,135 @@
|
||||
@tool
|
||||
@icon("TouchScreenButtonControl.svg")
|
||||
class_name TouchScreenButtonControl
|
||||
extends TextureButton
|
||||
|
||||
const DefaultValues := {
|
||||
"expand": true,
|
||||
"ignore_texture_size": true,
|
||||
"stretch_mode": TextureButton.STRETCH_KEEP_ASPECT_CENTERED,
|
||||
"action_mode": TextureButton.ACTION_MODE_BUTTON_PRESS,
|
||||
"focus_mode": TextureButton.FOCUS_NONE,
|
||||
}
|
||||
|
||||
@export var use_default_values := true
|
||||
@export var touchscreen_only := false
|
||||
|
||||
# The actual variable that holds the data
|
||||
var input_action: String = ""
|
||||
|
||||
# 2. MATCHED the property name here...
|
||||
func _get_property_list() -> Array:
|
||||
var properties: Array = []
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
InputMap.load_from_project_settings()
|
||||
|
||||
# Get actions and format them for the dropdown
|
||||
var actions = InputMap.get_actions()
|
||||
var action_list = ",".join(actions)
|
||||
|
||||
properties.append({
|
||||
"name": "input_action",
|
||||
"type": TYPE_STRING,
|
||||
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
|
||||
"hint_string": ",".join(actions),
|
||||
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR
|
||||
})
|
||||
|
||||
return properties
|
||||
|
||||
func _set(property: StringName, value: Variant) -> bool:
|
||||
if property == "input_action":
|
||||
input_action = value
|
||||
return true
|
||||
return false
|
||||
|
||||
func _get(property: StringName) -> Variant:
|
||||
if property == "input_action":
|
||||
return input_action
|
||||
return null
|
||||
|
||||
# Track multiple simultaneous touches for multitouch support
|
||||
var active_touches := {} # Dictionary: touch_index -> bool (true if pressed)
|
||||
var initial_press_touches := {} # Dictionary: touch_index -> bool (true if this button was pressed on initial touch)
|
||||
|
||||
func _init():
|
||||
if use_default_values:
|
||||
for k in DefaultValues.keys():
|
||||
self.set(k, DefaultValues.get(k))
|
||||
|
||||
# Set mouse_filter to IGNORE so the button doesn't consume touch events
|
||||
# This allows multiple buttons to detect the same touch simultaneously
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
if touchscreen_only and not DisplayServer.is_touchscreen_available():
|
||||
hide()
|
||||
|
||||
func press():
|
||||
var input_event: InputEvent = InputMap.action_get_events(input_action)[0]
|
||||
input_event.pressed = true
|
||||
Input.parse_input_event(input_event)
|
||||
|
||||
func release():
|
||||
var input_event: InputEvent = InputMap.action_get_events(input_action)[0]
|
||||
input_event.pressed = false
|
||||
Input.parse_input_event(input_event)
|
||||
|
||||
func is_in(pos: Vector2) -> bool:
|
||||
# Get the global rect of this Control node in screen coordinates
|
||||
var global_rect = get_global_rect()
|
||||
# Check if the touch position is within the button's global rect
|
||||
if pos.x >= global_rect.position.x and pos.x <= global_rect.position.x + global_rect.size.x:
|
||||
if pos.y >= global_rect.position.y and pos.y <= global_rect.position.y + global_rect.size.y:
|
||||
return true
|
||||
return false
|
||||
|
||||
func _input(event):
|
||||
# Use _input to receive all touch events
|
||||
# IMPORTANT: _input is called on ALL nodes in the scene tree, so multiple buttons
|
||||
# can receive the same event. We don't consume the event so others can too.
|
||||
if event is InputEventScreenTouch:
|
||||
if event.pressed:
|
||||
# Check if this touch is within this button's bounds
|
||||
if is_in(event.position):
|
||||
# Start tracking this touch for this button
|
||||
if event.index not in active_touches:
|
||||
active_touches[event.index] = true
|
||||
initial_press_touches[event.index] = true # Mark as initial press
|
||||
press()
|
||||
else:
|
||||
# Touch released - check if we were tracking it
|
||||
if event.index in active_touches:
|
||||
# This touch was being tracked by this button, release it
|
||||
active_touches.erase(event.index)
|
||||
initial_press_touches.erase(event.index)
|
||||
# Only release the action if no other touches are active for this button
|
||||
if active_touches.is_empty():
|
||||
release()
|
||||
elif event is InputEventScreenDrag:
|
||||
# Handle touch drag with smart re-activation logic
|
||||
if event.index in active_touches:
|
||||
# We're tracking this touch
|
||||
if initial_press_touches.has(event.index):
|
||||
# This was an initial press - keep it active even if touch moves outside
|
||||
# Don't release until touch ends
|
||||
pass
|
||||
else:
|
||||
# This was a re-activation (touch moved back into bounds)
|
||||
# Check if touch moved back out of bounds
|
||||
if not is_in(event.position):
|
||||
# Touch moved out of bounds, release this re-activated button
|
||||
active_touches.erase(event.index)
|
||||
if active_touches.is_empty():
|
||||
release()
|
||||
else:
|
||||
# We're not tracking this touch - check if it moved into our bounds
|
||||
# This allows "tapping" behavior - touch can re-enter and activate button
|
||||
if is_in(event.position):
|
||||
# Touch moved into bounds, start tracking (but not as initial press)
|
||||
active_touches[event.index] = true
|
||||
press()
|
||||
|
||||
# CRITICAL: Never call get_viewport().set_input_as_handled() here
|
||||
# This would prevent other buttons from receiving the same touch event
|
||||
# mouse_filter is set to IGNORE so the TextureButton doesn't consume mouse/touch events
|
||||
@@ -0,0 +1 @@
|
||||
uid://bh5a3ydiu51eo
|
||||
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><defs/><g><path d="M3,1 C2.7249,1 2.4771,1.1087 2.2929,1.2929 C2.1087,1.4771 2,1.7249 2,2 L2,4 C2,4.2751 2.1087,4.5229 2.2929,4.7071 C2.4771,4.8913 2.7249,5 3,5 L5,5 L5,4 L3,4 L3,2 L11,2 L11,4 L9,4 L9,5 L11,5 C11.2751,5 11.5229,4.8913 11.7071,4.7071 C11.8913,4.5229 12,4.2751 12,4 L12,2 C12,1.7249 11.8913,1.4771 11.7071,1.2929 C11.5229,1.1087 11.2751,1 11,1 L3,1 Z M8,8 L8,4 C8,3.4015 7.5531,3 7,3 C6.4469,3 6,3.4015 6,4 L6,11.05 L3.5,9.25 C2.9376,8.8026 2.2507,8.8435 1.8125,9.3125 C1.3692,9.787 1.3561,10.4968 1.875,11 L6,15 L12,15 C12.5502,15 13.0459,14.7826 13.4142,14.4142 C13.7826,14.0459 14,13.5502 14,13 L14,10 C14,9.4498 13.7826,8.9541 13.4142,8.5858 C13.0459,8.2174 12.5502,8 12,8 L8,8 Z" fill="rgb(142,239,151)" opacity="1"/></g></svg>
|
||||
|
After Width: | Height: | Size: 807 B |
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ckvwnehwdvwyq"
|
||||
path="res://.godot/imported/TouchScreenButtonControl.svg-ec8e7f48e271699010d76650daf1583d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg"
|
||||
dest_files=["res://.godot/imported/TouchScreenButtonControl.svg-ec8e7f48e271699010d76650daf1583d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dsj828xm2e28w"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd" id="1_5k641"]
|
||||
|
||||
[node name="TouchScreenButtonControl" type="TextureButton"]
|
||||
script = ExtResource("1_5k641")
|
||||
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
var MyCustomNode = preload("res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.gd")
|
||||
|
||||
func _enter_tree():
|
||||
add_custom_type(
|
||||
"TouchScreenButtonControl",
|
||||
"Control",
|
||||
TouchScreenButtonControl,
|
||||
preload("res://addons/touchscreenbuttoncontrol/TouchScreenButtonControl.svg")
|
||||
)
|
||||
|
||||
func _exit_tree():
|
||||
remove_custom_type("TouchScreenButtonControl")
|
||||
@@ -0,0 +1 @@
|
||||
uid://cq0bml8epsqa
|
||||
13
src/addons/touchscreenbuttoncontrol/button_style.tres
Normal file
13
src/addons/touchscreenbuttoncontrol/button_style.tres
Normal file
@@ -0,0 +1,13 @@
|
||||
[gd_resource type="StyleBoxFlat" format=3 uid="uid://cv5o175a2677e"]
|
||||
|
||||
[resource]
|
||||
bg_color = Color(0.3, 0.3, 0.3, 0.7)
|
||||
border_width_left = 2
|
||||
border_width_top = 2
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color(0.8, 0.8, 0.8, 0.9)
|
||||
corner_radius_top_left = 40
|
||||
corner_radius_top_right = 40
|
||||
corner_radius_bottom_right = 40
|
||||
corner_radius_bottom_left = 40
|
||||
1
src/addons/touchscreenbuttoncontrol/icon.svg
Normal file
1
src/addons/touchscreenbuttoncontrol/icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><defs/><g><path d="M3,1 C2.7249,1 2.4771,1.1087 2.2929,1.2929 C2.1087,1.4771 2,1.7249 2,2 L2,4 C2,4.2751 2.1087,4.5229 2.2929,4.7071 C2.4771,4.8913 2.7249,5 3,5 L5,5 L5,4 L3,4 L3,2 L11,2 L11,4 L9,4 L9,5 L11,5 C11.2751,5 11.5229,4.8913 11.7071,4.7071 C11.8913,4.5229 12,4.2751 12,4 L12,2 C12,1.7249 11.8913,1.4771 11.7071,1.2929 C11.5229,1.1087 11.2751,1 11,1 L3,1 Z M8,8 L8,4 C8,3.4015 7.5531,3 7,3 C6.4469,3 6,3.4015 6,4 L6,11.05 L3.5,9.25 C2.9376,8.8026 2.2507,8.8435 1.8125,9.3125 C1.3692,9.787 1.3561,10.4968 1.875,11 L6,15 L12,15 C12.5502,15 13.0459,14.7826 13.4142,14.4142 C13.7826,14.0459 14,13.5502 14,13 L14,10 C14,9.4498 13.7826,8.9541 13.4142,8.5858 C13.0459,8.2174 12.5502,8 12,8 L8,8 Z" fill="rgb(142,239,151)" opacity="1"/></g></svg>
|
||||
|
After Width: | Height: | Size: 807 B |
43
src/addons/touchscreenbuttoncontrol/icon.svg.import
Normal file
43
src/addons/touchscreenbuttoncontrol/icon.svg.import
Normal file
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://x5ggo5vlsqwn"
|
||||
path="res://.godot/imported/icon.svg-e7770945a21c9fca528355bbf6b1708f.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/touchscreenbuttoncontrol/icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-e7770945a21c9fca528355bbf6b1708f.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
7
src/addons/touchscreenbuttoncontrol/plugin.cfg
Normal file
7
src/addons/touchscreenbuttoncontrol/plugin.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="TouchScreenButtonControl"
|
||||
description="A Control Node version to TouchScreenButton2D"
|
||||
author="Matata.exe"
|
||||
version="1.0"
|
||||
script="TouchScreenButtonControlPlugin.gd"
|
||||
Reference in New Issue
Block a user