Added touchscreen controls!
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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="TouchScreenButtonControl"
|
||||
description="A Control Node version to TouchScreenButton2D"
|
||||
author="Matata.exe"
|
||||
version="1.0"
|
||||
script="TouchScreenButtonControlPlugin.gd"
|
||||
1
src/addons/virtual_joystick/icon.svg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
43
src/addons/virtual_joystick/icon.svg.import
Normal file
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ndaordejurrl"
|
||||
path="res://.godot/imported/icon.svg-3eaf29e1973fdc580c89279657f85e37.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-3eaf29e1973fdc580c89279657f85e37.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
|
||||
8
src/addons/virtual_joystick/plugin.cfg
Normal file
@@ -0,0 +1,8 @@
|
||||
[plugin]
|
||||
|
||||
name="Virtual Joystick"
|
||||
description="Virtual Joystick is a lightweight and fully configurable plugin that adds a virtual joystick to the screen, ideal for mobile games or touch-based interfaces.
|
||||
With it, you can control player movement or any other input action using a simple, responsive, and customizable visual stick."
|
||||
author="Saulo de Souza"
|
||||
version="1.0.7"
|
||||
script="plugin.gd"
|
||||
11
src/addons/virtual_joystick/plugin.gd
Normal file
@@ -0,0 +1,11 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
var icon = preload("res://addons/virtual_joystick/icon.svg")
|
||||
var script_main = preload("res://addons/virtual_joystick/virtual_joystick.gd")
|
||||
|
||||
func _enter_tree():
|
||||
add_custom_type("VirtualJoystick", "Control", script_main, icon)
|
||||
|
||||
func _exit_tree():
|
||||
remove_custom_type("VirtualJoystick")
|
||||
1
src/addons/virtual_joystick/plugin.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://e7m2yqefj838
|
||||
|
After Width: | Height: | Size: 58 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://mfjv5h7sdlhy"
|
||||
path="res://.godot/imported/joystick_texture_1.png-9fe11098e467f8f7500bf2529275c515.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_1.png"
|
||||
dest_files=["res://.godot/imported/joystick_texture_1.png-9fe11098e467f8f7500bf2529275c515.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
|
||||
|
After Width: | Height: | Size: 78 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cppp7p7l040i5"
|
||||
path="res://.godot/imported/joystick_texture_2.png-bd8e129c570c51a41d34619540e549b1.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_2.png"
|
||||
dest_files=["res://.godot/imported/joystick_texture_2.png-bd8e129c570c51a41d34619540e549b1.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
|
||||
|
After Width: | Height: | Size: 7.8 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ct6r0wagtmapd"
|
||||
path="res://.godot/imported/joystick_texture_3.png-d28d8fdffe3dd01bcd800f8da8ffad5c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_3.png"
|
||||
dest_files=["res://.godot/imported/joystick_texture_3.png-d28d8fdffe3dd01bcd800f8da8ffad5c.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
|
||||
|
After Width: | Height: | Size: 62 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://rxah3fc1lih3"
|
||||
path="res://.godot/imported/joystick_texture_4.png-288403f1a78edebf82b0917d63d71545.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_4.png"
|
||||
dest_files=["res://.godot/imported/joystick_texture_4.png-288403f1a78edebf82b0917d63d71545.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
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://01qhightlcso"
|
||||
path="res://.godot/imported/joystick_texture_5.png-b4d7bb661b1dfa9d44580770afad2948.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_5.png"
|
||||
dest_files=["res://.godot/imported/joystick_texture_5.png-b4d7bb661b1dfa9d44580770afad2948.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
|
||||
|
After Width: | Height: | Size: 66 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://don118m3unno4"
|
||||
path="res://.godot/imported/joystick_texture_6.png-2b34481992ebc7f5529547a31713f9e4.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/joystick_texture_6.png"
|
||||
dest_files=["res://.godot/imported/joystick_texture_6.png-2b34481992ebc7f5529547a31713f9e4.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
|
||||
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dv7m8ofd7vjkg"
|
||||
path="res://.godot/imported/stick_texture_1.png-b7322c6c9fa9ceca47042e9525a31e3d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/stick_texture_1.png"
|
||||
dest_files=["res://.godot/imported/stick_texture_1.png-b7322c6c9fa9ceca47042e9525a31e3d.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
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bra3aeybagspi"
|
||||
path="res://.godot/imported/stick_texture_2.png-56a0dc5972515a4c813acb0018d59897.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/stick_texture_2.png"
|
||||
dest_files=["res://.godot/imported/stick_texture_2.png-56a0dc5972515a4c813acb0018d59897.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
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b76m3oio3bpve"
|
||||
path="res://.godot/imported/stick_texture_3.png-ac8c0e09219e9294012c766efb28a6dd.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/stick_texture_3.png"
|
||||
dest_files=["res://.godot/imported/stick_texture_3.png-ac8c0e09219e9294012c766efb28a6dd.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
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dt4ujdvuod0ei"
|
||||
path="res://.godot/imported/stick_texture_4.png-ea228bad22a241c375a4eb387cc66da7.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/stick_texture_4.png"
|
||||
dest_files=["res://.godot/imported/stick_texture_4.png-ea228bad22a241c375a4eb387cc66da7.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
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dywm4x5vqdtsm"
|
||||
path="res://.godot/imported/stick_texture_5.png-f76da9fbec9ae506d29c25a5b2e273b4.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/stick_texture_5.png"
|
||||
dest_files=["res://.godot/imported/stick_texture_5.png-f76da9fbec9ae506d29c25a5b2e273b4.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
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,40 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://fts4nb53arsl"
|
||||
path="res://.godot/imported/stick_texture_6.png-0fdb4087c1eca258d05fa6e2a535cbbe.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/virtual_joystick/resources/textures/stick_texture_6.png"
|
||||
dest_files=["res://.godot/imported/stick_texture_6.png-0fdb4087c1eca258d05fa6e2a535cbbe.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
|
||||
496
src/addons/virtual_joystick/virtual_joystick.gd
Normal file
@@ -0,0 +1,496 @@
|
||||
@tool
|
||||
@icon("res://addons/virtual_joystick/icon.svg")
|
||||
class_name VirtualJoystick
|
||||
extends Control
|
||||
|
||||
#region Signals =================================================
|
||||
## Emitted when the stick is moved.
|
||||
signal analogic_changed(
|
||||
value: Vector2,
|
||||
distance: float,
|
||||
angle: float,
|
||||
angle_clockwise: float,
|
||||
angle_not_clockwise: float
|
||||
)
|
||||
|
||||
## Emitted when the stick enters the dead zone.
|
||||
signal deadzone_enter
|
||||
|
||||
## Emitted when the stick leaves the dead zone.
|
||||
signal deadzone_leave
|
||||
#endregion Signals ===============================================
|
||||
|
||||
|
||||
#region Private Properties ======================================
|
||||
var _joystick: VirtualJoystickCircle
|
||||
var _stick: VirtualJoystickCircle
|
||||
|
||||
var _joystick_radius: float = 100.0
|
||||
var _joystick_border_width: float = 10.0
|
||||
var _joystick_start_position: Vector2 = Vector2(_joystick_radius + _joystick_border_width, _joystick_radius + _joystick_border_width)
|
||||
|
||||
var _stick_radius: float = 45.0
|
||||
var _stick_border_width: float = -1.0
|
||||
var _stick_start_position: Vector2 = _joystick_start_position
|
||||
|
||||
var _drag_started_inside := false
|
||||
var _click_in := false
|
||||
var _delta: Vector2 = Vector2.ZERO
|
||||
var _in_deadzone: bool = false:
|
||||
set(value):
|
||||
if value != _in_deadzone:
|
||||
_in_deadzone = value
|
||||
if not active:
|
||||
return
|
||||
if _in_deadzone:
|
||||
deadzone_enter.emit()
|
||||
else:
|
||||
deadzone_leave.emit()
|
||||
|
||||
var _real_size: Vector2 = size * scale
|
||||
var _warnings: PackedStringArray = []
|
||||
|
||||
var _DEFAULT_JOYSTICK_TEXTURE = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_1.png")
|
||||
var _JOYSTICK_TEXTURE_2 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_2.png")
|
||||
var _JOYSTICK_TEXTURE_3 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_3.png")
|
||||
var _JOYSTICK_TEXTURE_4 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_4.png")
|
||||
var _JOYSTICK_TEXTURE_5 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_5.png")
|
||||
var _JOYSTICK_TEXTURE_6 = preload("res://addons/virtual_joystick/resources/textures/joystick_texture_6.png")
|
||||
|
||||
var _DEFAULT_STICK_TEXTURE = preload("res://addons/virtual_joystick/resources/textures/stick_texture_1.png")
|
||||
var _STICK_TEXTURE_2 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_2.png")
|
||||
var _STICK_TEXTURE_3 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_3.png")
|
||||
var _STICK_TEXTURE_4 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_4.png")
|
||||
var _STICK_TEXTURE_5 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_5.png")
|
||||
var _STICK_TEXTURE_6 = preload("res://addons/virtual_joystick/resources/textures/stick_texture_6.png")
|
||||
|
||||
enum _preset_enum {
|
||||
## Nothing
|
||||
NONE,
|
||||
## Default preset texture
|
||||
PRESET_DEFAULT,
|
||||
## Texture 2
|
||||
PRESET_2,
|
||||
## Texture 3
|
||||
PRESET_3,
|
||||
## Texture 4
|
||||
PRESET_4,
|
||||
## Texture 5
|
||||
PRESET_5,
|
||||
## Texture 6
|
||||
PRESET_6,
|
||||
|
||||
}
|
||||
#endregion Private Properties ====================================
|
||||
|
||||
|
||||
#region Public Properties =======================================
|
||||
## Normalized joystick direction vector (X, Y).
|
||||
var value: Vector2 = Vector2.ZERO
|
||||
|
||||
## Distance of the stick from the joystick center (0.0 to 1.0).
|
||||
var distance: float = 0.0
|
||||
|
||||
## Angle in degrees (universal reference, 0° = right).
|
||||
var angle_degrees: float = 0.0
|
||||
|
||||
## Angle in degrees, measured clockwise.
|
||||
var angle_degrees_clockwise: float = 0.0
|
||||
|
||||
## Angle in degrees, measured counter-clockwise.
|
||||
var angle_degrees_not_clockwise: float = 0.0
|
||||
#endregion Public Properties =====================================
|
||||
|
||||
|
||||
#region Exports ===================================================
|
||||
@export_category("Virtual Joystick")
|
||||
## Enables or disables the joystick input.
|
||||
@export var active: bool = true
|
||||
## Deadzone threshold (0.0 = off, 1.0 = full range).
|
||||
@export_range(0.0, 0.9, 0.001, "suffix:length") var deadzone: float = 0.1
|
||||
## Global scale factor of the joystick.
|
||||
@export_range(0.1, 2.0, 0.001, "suffix:x", "or_greater") var scale_factor: float = 1.0:
|
||||
set(value):
|
||||
scale_factor = value
|
||||
scale = Vector2(value, value)
|
||||
_update_real_size()
|
||||
queue_redraw()
|
||||
## If true, the Joystick will only be displayed on the screen on mobile devices.
|
||||
@export var only_mobile: bool = false:
|
||||
set(value):
|
||||
only_mobile = value
|
||||
if only_mobile == true and OS.get_name().to_lower() not in ["android", "ios"]:
|
||||
visible = false
|
||||
else:
|
||||
visible = true
|
||||
|
||||
@export_category("Joystick")
|
||||
## Enable the use of textures for the joystick.
|
||||
@export var joystick_use_textures: bool = true:
|
||||
set(value):
|
||||
joystick_use_textures = value
|
||||
if value and joystick_texture == null:
|
||||
_set_joystick_preset(joystick_preset_texture)
|
||||
_verify_can_use_border()
|
||||
update_configuration_warnings()
|
||||
queue_redraw()
|
||||
## Select one of the available models. More models will be available soon.
|
||||
@export var joystick_preset_texture: _preset_enum = _preset_enum.PRESET_5: set = _set_joystick_preset
|
||||
## Select a texture for the joystick figure.
|
||||
@export var joystick_texture: Texture2D = _JOYSTICK_TEXTURE_5:
|
||||
set(value):
|
||||
joystick_texture = value
|
||||
update_configuration_warnings()
|
||||
_verify_can_use_border()
|
||||
queue_redraw()
|
||||
## Base color of the joystick background.
|
||||
@export_color_no_alpha() var joystick_color: Color = Color.WHITE:
|
||||
set(value):
|
||||
joystick_color = value
|
||||
if _joystick:
|
||||
_joystick.color = value
|
||||
_joystick.opacity = joystick_opacity
|
||||
queue_redraw()
|
||||
## Opacity of the joystick base.
|
||||
@export_range(0.0, 1.0, 0.001, "suffix:alpha") var joystick_opacity: float = 0.8:
|
||||
set(value):
|
||||
joystick_opacity = value
|
||||
if _joystick:
|
||||
_joystick.opacity = value
|
||||
queue_redraw()
|
||||
## Width of the joystick base border.
|
||||
@export_range(1.0, 20.0, 0.01, "suffix:px", "or_greater") var joystick_border: float = 1.0:
|
||||
set(value):
|
||||
joystick_border = value
|
||||
_joystick.width = value
|
||||
_joystick_border_width = value
|
||||
_joystick_start_position = Vector2(_joystick_radius + _joystick_border_width, _joystick_radius + _joystick_border_width)
|
||||
_joystick.position = _joystick_start_position
|
||||
_stick_start_position = Vector2(_joystick_radius + _joystick_border_width, _joystick_radius + _joystick_border_width)
|
||||
_stick.position = _stick_start_position
|
||||
update_configuration_warnings()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
@export_category("Stick")
|
||||
## Enable the use of textures for the stick.
|
||||
@export var stick_use_textures: bool = true:
|
||||
set(value):
|
||||
stick_use_textures = value
|
||||
if value and stick_texture == null:
|
||||
_set_stick_preset(stick_preset_texture)
|
||||
update_configuration_warnings()
|
||||
queue_redraw()
|
||||
## Select one of the available models. More models will be available soon.
|
||||
@export var stick_preset_texture: _preset_enum = _preset_enum.PRESET_5: set = _set_stick_preset
|
||||
## Select a texture for the stick figure.
|
||||
@export var stick_texture: Texture2D = _STICK_TEXTURE_5:
|
||||
set(value):
|
||||
stick_texture = value
|
||||
update_configuration_warnings()
|
||||
queue_redraw()
|
||||
## Stick (thumb) color.
|
||||
@export_color_no_alpha() var stick_color: Color = Color.WHITE:
|
||||
set(value):
|
||||
stick_color = value
|
||||
if _stick:
|
||||
_stick.color = value
|
||||
_stick.opacity = stick_opacity
|
||||
queue_redraw()
|
||||
## Opacity of the stick.
|
||||
@export_range(0.0, 1.0, 0.001, "suffix:alpha") var stick_opacity: float = 0.8:
|
||||
set(value):
|
||||
stick_opacity = value
|
||||
if _stick:
|
||||
_stick.opacity = value
|
||||
queue_redraw()
|
||||
#endregion Exports =================================================
|
||||
|
||||
|
||||
#region Engine Methods =============================================
|
||||
func _init() -> void:
|
||||
_joystick = VirtualJoystickCircle.new(_joystick_start_position, _joystick_radius, _joystick_border_width, false, joystick_color, joystick_opacity)
|
||||
_stick = VirtualJoystickCircle.new(_stick_start_position, _stick_radius, _stick_border_width, true, stick_color, stick_opacity)
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
set_size(Vector2(_joystick_radius * 2 + _joystick_border_width * 2, _joystick_radius * 2 + _joystick_border_width * 2))
|
||||
_update_real_size()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if joystick_use_textures and joystick_texture:
|
||||
var base_size = joystick_texture.get_size()
|
||||
var base_scale = (_joystick_radius * 2) / base_size.x
|
||||
draw_set_transform(_joystick.position, 0, Vector2(base_scale, base_scale))
|
||||
draw_texture(joystick_texture, -base_size / 2, Color(joystick_color.r, joystick_color.g, joystick_color.b, joystick_opacity))
|
||||
draw_set_transform(Vector2.ZERO, 0, Vector2.ONE)
|
||||
else:
|
||||
_joystick.draw(self, false)
|
||||
|
||||
if stick_use_textures and stick_texture:
|
||||
var stick_size = stick_texture.get_size()
|
||||
var stick_scale = (_stick_radius * 2) / stick_size.x
|
||||
draw_set_transform(_stick.position, 0, Vector2(stick_scale, stick_scale))
|
||||
draw_texture(stick_texture, -stick_size / 2, Color(stick_color.r, stick_color.g, stick_color.b, stick_opacity))
|
||||
draw_set_transform(Vector2.ZERO, 0, Vector2.ONE)
|
||||
else:
|
||||
_stick.draw(self, false)
|
||||
|
||||
scale = Vector2(scale_factor, scale_factor)
|
||||
set_size(Vector2((_joystick_radius * 2) + (_joystick_border_width * 2), (_joystick_radius * 2) + (_joystick_border_width * 2)))
|
||||
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventScreenTouch:
|
||||
if event.pressed:
|
||||
distance = event.position.distance_to(_joystick.position)
|
||||
_drag_started_inside = distance <= _joystick.radius + _joystick.width / 2
|
||||
if _drag_started_inside:
|
||||
_click_in = true
|
||||
_update_stick(event.position)
|
||||
else:
|
||||
_click_in = false
|
||||
else:
|
||||
if _click_in:
|
||||
_reset_values()
|
||||
_update_emit_signals()
|
||||
_click_in = false
|
||||
_drag_started_inside = false
|
||||
_stick.position = _stick_start_position
|
||||
queue_redraw()
|
||||
|
||||
elif event is InputEventScreenDrag:
|
||||
if _drag_started_inside:
|
||||
_update_stick(event.position)
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
_warnings = []
|
||||
if joystick_use_textures and (joystick_texture == null):
|
||||
_warnings.append("The joystick_texture properties must be set when using joystick_use_textures = true.")
|
||||
if stick_use_textures and (stick_texture == null):
|
||||
_warnings.append("The stick_texture properties must be set when using stick_use_textures = true.")
|
||||
if joystick_use_textures and joystick_texture != null and joystick_preset_texture != _preset_enum.NONE and joystick_border > 1.0:
|
||||
_warnings.append("When using a texture preset, the ideal border height would be 1.0.")
|
||||
return _warnings
|
||||
|
||||
#endregion Engine Methods =============================================
|
||||
|
||||
|
||||
#region Private Methods ============================================
|
||||
func _update_stick(_position: Vector2) -> void:
|
||||
_delta = _position - _stick_start_position
|
||||
if _delta.length() > _joystick.radius:
|
||||
_delta = _delta.normalized() * _joystick.radius
|
||||
_stick.position = _stick_start_position + _delta
|
||||
queue_redraw()
|
||||
|
||||
var processed = _apply_deadzone(_delta / _joystick.radius)
|
||||
value = processed.value
|
||||
distance = processed.distance
|
||||
angle_degrees = processed.angle_degrees
|
||||
angle_degrees_clockwise = processed.angle_clockwise
|
||||
angle_degrees_not_clockwise = processed.angle_not_clockwise
|
||||
|
||||
_update_emit_signals()
|
||||
|
||||
|
||||
func _reset_values() -> void:
|
||||
_delta = Vector2.ZERO
|
||||
value = Vector2.ZERO
|
||||
distance = 0.0
|
||||
angle_degrees = 0.0
|
||||
angle_degrees_clockwise = 0.0
|
||||
angle_degrees_not_clockwise = 0.0
|
||||
_stick.position = _stick_start_position
|
||||
|
||||
var length = (_delta / _joystick.radius).length()
|
||||
var dz = clamp(deadzone, 0.0, 0.99)
|
||||
if length <= dz:
|
||||
_in_deadzone = true
|
||||
|
||||
queue_redraw()
|
||||
|
||||
|
||||
## Applies linear deadzone adjustment and calculates resulting angles.
|
||||
func _apply_deadzone(input_value: Vector2) -> Dictionary:
|
||||
var length = input_value.length()
|
||||
var result = Vector2.ZERO
|
||||
var dz = clamp(deadzone, 0.0, 0.99)
|
||||
|
||||
if length <= dz:
|
||||
_in_deadzone = true
|
||||
result = Vector2.ZERO
|
||||
length = 0.0
|
||||
else:
|
||||
_in_deadzone = false
|
||||
# Re-scale linearly between deadzone and full range
|
||||
var adjusted = (length - dz) / (1.0 - dz)
|
||||
result = input_value.normalized() * adjusted
|
||||
length = adjusted
|
||||
|
||||
var angle_cw = _get_angle_delta(result * _joystick.radius, true, true)
|
||||
var angle_ccw = _get_angle_delta(result * _joystick.radius, true, false)
|
||||
var angle = _get_angle_delta(result * _joystick.radius, false, false)
|
||||
|
||||
if active:
|
||||
return {
|
||||
"value": result,
|
||||
"distance": length,
|
||||
"angle_clockwise": angle_cw,
|
||||
"angle_not_clockwise": angle_ccw,
|
||||
"angle_degrees": angle
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"value": Vector2.ZERO,
|
||||
"distance": 0.0,
|
||||
"angle_clockwise": 0.0,
|
||||
"angle_not_clockwise": 0.0,
|
||||
"angle_degrees": 0.0
|
||||
}
|
||||
|
||||
|
||||
func _update_emit_signals() -> void:
|
||||
if not active:
|
||||
return
|
||||
if _in_deadzone:
|
||||
analogic_changed.emit(
|
||||
Vector2.ZERO,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
)
|
||||
else:
|
||||
analogic_changed.emit(
|
||||
value,
|
||||
distance,
|
||||
angle_degrees,
|
||||
angle_degrees_clockwise,
|
||||
angle_degrees_not_clockwise
|
||||
)
|
||||
|
||||
|
||||
func _update_real_size() -> void:
|
||||
_real_size = size * scale
|
||||
pivot_offset = size / 2
|
||||
|
||||
|
||||
## Calculates the angle of a vector in degrees.
|
||||
func _get_angle_delta(delta: Vector2, continuous: bool, clockwise: bool) -> float:
|
||||
var angle_deg = 0.0
|
||||
if continuous and not clockwise:
|
||||
angle_deg = rad_to_deg(atan2(-delta.y, delta.x))
|
||||
else:
|
||||
angle_deg = rad_to_deg(atan2(delta.y, delta.x))
|
||||
if continuous and angle_deg < 0.0:
|
||||
angle_deg += 360.0
|
||||
return angle_deg
|
||||
|
||||
|
||||
func _set_joystick_preset(_value: _preset_enum) -> void:
|
||||
joystick_preset_texture = _value
|
||||
match (_value):
|
||||
_preset_enum.PRESET_DEFAULT:
|
||||
joystick_texture = _DEFAULT_JOYSTICK_TEXTURE
|
||||
_preset_enum.PRESET_2:
|
||||
joystick_texture = _JOYSTICK_TEXTURE_2
|
||||
_preset_enum.PRESET_3:
|
||||
joystick_texture = _JOYSTICK_TEXTURE_3
|
||||
_preset_enum.PRESET_4:
|
||||
joystick_texture = _JOYSTICK_TEXTURE_4
|
||||
_preset_enum.PRESET_5:
|
||||
joystick_texture = _JOYSTICK_TEXTURE_5
|
||||
_preset_enum.PRESET_6:
|
||||
joystick_texture = _JOYSTICK_TEXTURE_6
|
||||
_preset_enum.NONE:
|
||||
if joystick_texture in [_DEFAULT_JOYSTICK_TEXTURE, _JOYSTICK_TEXTURE_2, _JOYSTICK_TEXTURE_3, _JOYSTICK_TEXTURE_4, _JOYSTICK_TEXTURE_5, _JOYSTICK_TEXTURE_6]:
|
||||
joystick_texture = null
|
||||
_verify_can_use_border()
|
||||
update_configuration_warnings()
|
||||
|
||||
func _set_stick_preset(_value: _preset_enum) -> void:
|
||||
stick_preset_texture = _value
|
||||
match (_value):
|
||||
_preset_enum.PRESET_DEFAULT:
|
||||
stick_texture = _DEFAULT_STICK_TEXTURE
|
||||
_preset_enum.PRESET_2:
|
||||
stick_texture = _STICK_TEXTURE_2
|
||||
_preset_enum.PRESET_3:
|
||||
stick_texture = _STICK_TEXTURE_3
|
||||
_preset_enum.PRESET_4:
|
||||
stick_texture = _STICK_TEXTURE_4
|
||||
_preset_enum.PRESET_5:
|
||||
stick_texture = _STICK_TEXTURE_5
|
||||
_preset_enum.PRESET_6:
|
||||
stick_texture = _STICK_TEXTURE_6
|
||||
_preset_enum.NONE:
|
||||
if stick_texture in [_DEFAULT_STICK_TEXTURE, _STICK_TEXTURE_2, _STICK_TEXTURE_3, _STICK_TEXTURE_4, _STICK_TEXTURE_5, _STICK_TEXTURE_6]:
|
||||
stick_texture = null
|
||||
|
||||
|
||||
func _verify_can_use_border() -> bool:
|
||||
if joystick_use_textures and not joystick_texture == null:
|
||||
joystick_border = 1.0
|
||||
return false
|
||||
return true
|
||||
#endregion Private Methods ===========================================
|
||||
|
||||
|
||||
#region Public Methods =============================================
|
||||
## Returns the current joystick vector value.
|
||||
func get_value() -> Vector2:
|
||||
return value
|
||||
|
||||
|
||||
## Returns the joystick distance (0 to 1).
|
||||
func get_distance() -> float:
|
||||
return distance
|
||||
|
||||
|
||||
## Returns the current joystick angle (clockwise).
|
||||
func get_angle_degrees_clockwise() -> float:
|
||||
return angle_degrees_clockwise
|
||||
|
||||
|
||||
## Returns the current joystick angle (counter-clockwise).
|
||||
func get_angle_degrees_not_clockwise() -> float:
|
||||
return angle_degrees_not_clockwise
|
||||
|
||||
|
||||
## Returns a specific angle configuration.
|
||||
func get_angle_degrees(continuous: bool = true, clockwise: bool = false) -> float:
|
||||
return _get_angle_delta(_delta, continuous, clockwise)
|
||||
#endregion Public Methods ============================================
|
||||
|
||||
|
||||
#region Classes ====================================================
|
||||
class VirtualJoystickCircle extends RefCounted:
|
||||
var position: Vector2
|
||||
var radius: float
|
||||
var color: Color
|
||||
var width: float
|
||||
var filled: bool
|
||||
var antialiased: bool
|
||||
var opacity: float:
|
||||
set(value):
|
||||
opacity = value
|
||||
self.color.a = opacity
|
||||
|
||||
func _init(_position: Vector2, _radius: float, _width: float = -1.0, _filled: bool = true, _color: Color = Color.WHITE, _opacity: float = 1.0, _antialiased: bool = true):
|
||||
self.position = _position
|
||||
self.radius = _radius
|
||||
self.color = _color
|
||||
self.width = _width
|
||||
self.filled = _filled
|
||||
self.antialiased = _antialiased
|
||||
self.opacity = _opacity
|
||||
self.color.a = _opacity
|
||||
|
||||
func draw(canvas_item: CanvasItem, offset: bool) -> void:
|
||||
var pos = self.position + (Vector2(self.radius, self.radius) if offset else Vector2.ZERO)
|
||||
canvas_item.draw_circle(pos, self.radius, self.color, self.filled, self.width, self.antialiased)
|
||||
#endregion Classes ===================================================
|
||||
1
src/addons/virtual_joystick/virtual_joystick.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dhn1uax7qtt1v
|
||||