Improve Android controller support
This commit is contained in:
parent
b47f131797
commit
9c89116713
16 changed files with 647 additions and 31 deletions
|
|
@ -4,15 +4,16 @@ importer="texture"
|
|||
type="CompressedTexture2D"
|
||||
uid="uid://crci2on30ctoc"
|
||||
path.s3tc="res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/exported/environment/textures/grass_lite.png"
|
||||
dest_files=["res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex"]
|
||||
dest_files=["res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex", "res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@ importer="texture"
|
|||
type="CompressedTexture2D"
|
||||
uid="uid://btxhq3rdlum2"
|
||||
path.s3tc="res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/exported/environment/textures/grass_olive_tile.png"
|
||||
dest_files=["res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"]
|
||||
dest_files=["res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex", "res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@ importer="texture"
|
|||
type="CompressedTexture2D"
|
||||
uid="uid://bnje415gq85nn"
|
||||
path.s3tc="res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex"
|
||||
path.etc2="res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.etc2.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/exported/environment/textures/sand.png"
|
||||
dest_files=["res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex"]
|
||||
dest_files=["res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex", "res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.etc2.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ class ShowcaseCameraSnapshot:
|
|||
@export var maximum_zoom: float = 8.0
|
||||
@export var zoom_step: float = 0.75
|
||||
@export var zoom_smoothing: float = 12.0
|
||||
@export_range(0.1, 12.0, 0.1) var controller_zoom_speed: float = 4.0
|
||||
@export_range(0.0, 1.0, 0.01) var controller_trigger_threshold: float = 0.55
|
||||
|
||||
@onready var _visuals: Node3D = %Visuals
|
||||
@onready var _character_animation_player: AnimationPlayer = (
|
||||
|
|
@ -290,16 +292,26 @@ func _process(delta: float) -> void:
|
|||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y)
|
||||
)
|
||||
if stick.length() > controller_camera_deadzone:
|
||||
var adjusted_strength: float = (
|
||||
(stick.length() - controller_camera_deadzone)
|
||||
/ (1.0 - controller_camera_deadzone)
|
||||
)
|
||||
_rotate_camera(
|
||||
stick.normalized()
|
||||
* adjusted_strength
|
||||
* controller_camera_speed
|
||||
* delta
|
||||
)
|
||||
if (
|
||||
Input.get_joy_axis(0, JOY_AXIS_TRIGGER_RIGHT)
|
||||
>= controller_trigger_threshold
|
||||
):
|
||||
var vertical_zoom_input: float = _apply_axis_deadzone(stick.y)
|
||||
_set_target_zoom(
|
||||
_target_zoom
|
||||
+ vertical_zoom_input * controller_zoom_speed * delta
|
||||
)
|
||||
else:
|
||||
var adjusted_strength: float = (
|
||||
(stick.length() - controller_camera_deadzone)
|
||||
/ (1.0 - controller_camera_deadzone)
|
||||
)
|
||||
_rotate_camera(
|
||||
stick.normalized()
|
||||
* adjusted_strength
|
||||
* controller_camera_speed
|
||||
* delta
|
||||
)
|
||||
|
||||
var zoom_weight: float = 1.0 - exp(-zoom_smoothing * delta)
|
||||
_spring_arm.spring_length = lerpf(
|
||||
|
|
@ -435,6 +447,17 @@ func _set_target_zoom(value: float) -> void:
|
|||
_target_zoom = clampf(value, minimum_zoom, maximum_zoom)
|
||||
|
||||
|
||||
func _apply_axis_deadzone(value: float) -> float:
|
||||
var magnitude: float = absf(value)
|
||||
if magnitude <= controller_camera_deadzone:
|
||||
return 0.0
|
||||
return (
|
||||
signf(value)
|
||||
* (magnitude - controller_camera_deadzone)
|
||||
/ (1.0 - controller_camera_deadzone)
|
||||
)
|
||||
|
||||
|
||||
func set_local_control(enabled: bool) -> void:
|
||||
local_control_enabled = enabled
|
||||
if is_node_ready():
|
||||
|
|
|
|||
|
|
@ -80,13 +80,13 @@ slow_walk={
|
|||
interact={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":2,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":3,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
fish_primary={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":5,"axis_value":1.0,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":10,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
camera_drag={
|
||||
|
|
@ -97,13 +97,11 @@ camera_drag={
|
|||
camera_zoom_in={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":10,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
camera_zoom_out={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":32,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":9,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
hotbar_1={
|
||||
|
|
@ -178,6 +176,16 @@ open_emotes={
|
|||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
open_quick_actions={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
open_chat={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":9,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
open_tacklebox={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":66,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
|
|
@ -213,6 +221,20 @@ alternate_fishing={
|
|||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":92,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
ui_accept={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194310,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
ui_cancel={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[physics]
|
||||
|
||||
|
|
|
|||
|
|
@ -15,16 +15,30 @@ func _init() -> void:
|
|||
assert(_has_joypad_motion(&"move_left", JOY_AXIS_LEFT_X, -1.0))
|
||||
assert(_has_joypad_motion(&"move_right", JOY_AXIS_LEFT_X, 1.0))
|
||||
assert(_has_joypad_button(&"jump", JOY_BUTTON_A))
|
||||
assert(_has_joypad_button(&"interact", JOY_BUTTON_X))
|
||||
assert(_has_joypad_motion(&"fish_primary", JOY_AXIS_TRIGGER_RIGHT, 1.0))
|
||||
assert(_has_joypad_button(&"ui_accept", JOY_BUTTON_A))
|
||||
assert(_has_joypad_button(&"ui_cancel", JOY_BUTTON_B))
|
||||
assert(_has_joypad_button(&"interact", JOY_BUTTON_Y))
|
||||
assert(_has_joypad_button(&"fish_primary", JOY_BUTTON_RIGHT_SHOULDER))
|
||||
assert(not _has_joypad_motion(
|
||||
&"fish_primary", JOY_AXIS_TRIGGER_LEFT, 1.0
|
||||
))
|
||||
assert(not _has_joypad_motion(
|
||||
&"fish_primary", JOY_AXIS_TRIGGER_RIGHT, 1.0
|
||||
))
|
||||
assert(_has_joypad_button(&"sprint", JOY_BUTTON_LEFT_STICK))
|
||||
assert(_has_joypad_button(&"camera_zoom_out", JOY_BUTTON_LEFT_SHOULDER))
|
||||
assert(_has_joypad_button(&"camera_zoom_in", JOY_BUTTON_RIGHT_SHOULDER))
|
||||
assert(not _has_joypad_button(
|
||||
&"camera_zoom_out", JOY_BUTTON_LEFT_SHOULDER
|
||||
))
|
||||
assert(not _has_joypad_button(
|
||||
&"camera_zoom_in", JOY_BUTTON_RIGHT_SHOULDER
|
||||
))
|
||||
assert(_has_joypad_button(&"hotbar_previous", JOY_BUTTON_DPAD_LEFT))
|
||||
assert(_has_joypad_button(&"hotbar_next", JOY_BUTTON_DPAD_RIGHT))
|
||||
assert(_has_joypad_button(&"open_backpack", JOY_BUTTON_BACK))
|
||||
assert(_has_joypad_button(&"open_system_menu", JOY_BUTTON_START))
|
||||
assert(_has_joypad_button(&"open_emotes", JOY_BUTTON_DPAD_UP))
|
||||
assert(_has_joypad_button(&"open_quick_actions", JOY_BUTTON_DPAD_DOWN))
|
||||
assert(_has_joypad_button(&"open_chat", JOY_BUTTON_LEFT_SHOULDER))
|
||||
print("android readiness validation passed")
|
||||
quit()
|
||||
|
||||
|
|
|
|||
|
|
@ -194,6 +194,13 @@ func close_chat() -> void:
|
|||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("open_chat"):
|
||||
if _opened:
|
||||
close_chat()
|
||||
elif _available:
|
||||
open_chat()
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if event is InputEventKey and event.pressed and not event.echo:
|
||||
if event.keycode in [KEY_ENTER, KEY_KP_ENTER]:
|
||||
if _opened:
|
||||
|
|
|
|||
40
ui/controller_virtual_cursor.gd
Normal file
40
ui/controller_virtual_cursor.gd
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
class_name ControllerVirtualCursor
|
||||
extends Control
|
||||
|
||||
const CURSOR_SIZE: Vector2 = Vector2(28.0, 28.0)
|
||||
const OUTER_COLOR: Color = Color(0.02, 0.10, 0.14, 0.96)
|
||||
const INNER_COLOR: Color = Color(0.34, 0.86, 0.91, 1.0)
|
||||
const CENTER_COLOR: Color = Color(0.96, 1.0, 1.0, 1.0)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
size = CURSOR_SIZE
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
focus_mode = Control.FOCUS_NONE
|
||||
visible = false
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func set_pointer_position(pointer_position: Vector2) -> void:
|
||||
position = pointer_position - CURSOR_SIZE * 0.5
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
var center: Vector2 = CURSOR_SIZE * 0.5
|
||||
draw_circle(center, 8.0, OUTER_COLOR)
|
||||
draw_circle(center, 5.0, INNER_COLOR)
|
||||
draw_circle(center, 1.75, CENTER_COLOR)
|
||||
draw_line(Vector2(center.x, 0.0), Vector2(center.x, 6.0), CENTER_COLOR, 2.0)
|
||||
draw_line(
|
||||
Vector2(center.x, CURSOR_SIZE.y - 6.0),
|
||||
Vector2(center.x, CURSOR_SIZE.y),
|
||||
CENTER_COLOR,
|
||||
2.0,
|
||||
)
|
||||
draw_line(Vector2(0.0, center.y), Vector2(6.0, center.y), CENTER_COLOR, 2.0)
|
||||
draw_line(
|
||||
Vector2(CURSOR_SIZE.x - 6.0, center.y),
|
||||
Vector2(CURSOR_SIZE.x, center.y),
|
||||
CENTER_COLOR,
|
||||
2.0,
|
||||
)
|
||||
1
ui/controller_virtual_cursor.gd.uid
Normal file
1
ui/controller_virtual_cursor.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dehegl7ccn057
|
||||
|
|
@ -13,10 +13,12 @@ const SECTOR_COUNT: int = 8
|
|||
const SIT_SECTOR: int = 0
|
||||
const RING_RADIUS: float = 172.0
|
||||
const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0)
|
||||
const CONTROLLER_SELECTION_DEADZONE: float = 0.35
|
||||
|
||||
var _buttons: Array[BubbleButton] = []
|
||||
var _is_open: bool = false
|
||||
var _selected_sector: int = SIT_SECTOR
|
||||
var _controller_selection_mode: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -42,7 +44,7 @@ func handle_input(event: InputEvent, can_open: bool) -> bool:
|
|||
if event.is_pressed():
|
||||
if _is_open or not can_open:
|
||||
return _is_open
|
||||
open_menu()
|
||||
open_menu(event is InputEventJoypadButton)
|
||||
return true
|
||||
if not _is_open:
|
||||
return false
|
||||
|
|
@ -53,9 +55,10 @@ func handle_input(event: InputEvent, can_open: bool) -> bool:
|
|||
return true
|
||||
|
||||
|
||||
func open_menu() -> void:
|
||||
func open_menu(controller_selection: bool = false) -> void:
|
||||
_is_open = true
|
||||
_selected_sector = SIT_SECTOR
|
||||
_controller_selection_mode = controller_selection
|
||||
visible = true
|
||||
_layout_bubbles()
|
||||
_apply_selection_styles()
|
||||
|
|
@ -74,7 +77,7 @@ func _process(_delta: float) -> void:
|
|||
if not _is_open:
|
||||
return
|
||||
_layout_bubbles()
|
||||
_update_mouse_selection()
|
||||
_update_selection()
|
||||
|
||||
|
||||
func _layout_bubbles() -> void:
|
||||
|
|
@ -88,10 +91,27 @@ func _layout_bubbles() -> void:
|
|||
bubble.pivot_offset = BUBBLE_SIZE * 0.5
|
||||
|
||||
|
||||
func _update_selection() -> void:
|
||||
var stick: Vector2 = Vector2(
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_X),
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y),
|
||||
)
|
||||
if stick.length() >= CONTROLLER_SELECTION_DEADZONE:
|
||||
_select_sector_from_offset(stick)
|
||||
return
|
||||
if _controller_selection_mode:
|
||||
return
|
||||
_update_mouse_selection()
|
||||
|
||||
|
||||
func _update_mouse_selection() -> void:
|
||||
var offset: Vector2 = get_local_mouse_position() - size * 0.5
|
||||
if offset.length() < 24.0:
|
||||
return
|
||||
_select_sector_from_offset(offset)
|
||||
|
||||
|
||||
func _select_sector_from_offset(offset: Vector2) -> void:
|
||||
var angle: float = fposmod(offset.angle() + PI * 0.5 + PI / 8.0, TAU)
|
||||
var sector: int = int(floor(angle / (TAU / float(SECTOR_COUNT))))
|
||||
if sector == _selected_sector:
|
||||
|
|
|
|||
295
ui/game_ui.gd
295
ui/game_ui.gd
|
|
@ -34,6 +34,10 @@ const PlayerCoolerCapacityType = preload(
|
|||
)
|
||||
const ChatUIType = preload("res://ui/chat_ui.gd")
|
||||
const EmoteRadialMenuType = preload("res://ui/emote_radial_menu.gd")
|
||||
const QuickRadialMenuType = preload("res://ui/quick_radial_menu.gd")
|
||||
const ControllerVirtualCursorType = preload(
|
||||
"res://ui/controller_virtual_cursor.gd"
|
||||
)
|
||||
const SurfaceDrawingToolbarType = preload(
|
||||
"res://ui/surface_drawing_toolbar.gd"
|
||||
)
|
||||
|
|
@ -58,6 +62,11 @@ signal passive_pointer_ui_changed(is_enabled: bool)
|
|||
signal player_menu_backdrop_visibility_changed(is_visible: bool)
|
||||
signal shop_backdrop_visibility_changed(is_visible: bool)
|
||||
|
||||
const VIRTUAL_MOUSE_INPUT_OWNER: StringName = &"controller_virtual_mouse"
|
||||
const VIRTUAL_MOUSE_TRIGGER_THRESHOLD: float = 0.55
|
||||
const VIRTUAL_MOUSE_STICK_DEADZONE: float = 0.18
|
||||
const VIRTUAL_MOUSE_SPEED: float = 720.0
|
||||
|
||||
@onready var _status_label: Label = %StatusLabel
|
||||
@onready var _gameplay_transient_hud: Control = %GameplayTransientHUD
|
||||
@onready var _experience_presentation: Control = %ExperiencePresentation
|
||||
|
|
@ -77,6 +86,7 @@ signal shop_backdrop_visibility_changed(is_visible: bool)
|
|||
@onready var _experience_bubble: PanelContainer = %ExperienceBubble
|
||||
@onready var _experience_bubble_label: Label = %ExperienceBubbleLabel
|
||||
@onready var _canonical_stage: Control = %CanonicalStage
|
||||
@onready var _ui_root: Control = %UIRoot
|
||||
@onready var _player_menu: PlayerMenuType = %PlayerMenu
|
||||
@onready var _screen_fade: ScreenFade = %ScreenFade
|
||||
@onready var _title_screen: TitleScreenType = %TitleScreen
|
||||
|
|
@ -87,6 +97,10 @@ signal shop_backdrop_visibility_changed(is_visible: bool)
|
|||
@onready var _effect_status: Label = %EffectStatus
|
||||
@onready var _chat_ui: ChatUIType = %ChatUI
|
||||
@onready var _emote_radial_menu: EmoteRadialMenuType = %EmoteRadialMenu
|
||||
@onready var _quick_radial_menu: QuickRadialMenuType = %QuickRadialMenu
|
||||
@onready var _controller_virtual_cursor: ControllerVirtualCursorType = (
|
||||
%ControllerVirtualCursor
|
||||
)
|
||||
@onready var _surface_drawing_toolbar: SurfaceDrawingToolbarType = (
|
||||
%SurfaceDrawingToolbar
|
||||
)
|
||||
|
|
@ -115,6 +129,15 @@ var _experience_award_queue: Array[Dictionary] = []
|
|||
var _experience_animation_active: bool = false
|
||||
var _experience_animation_generation: int = 0
|
||||
var _experience_panel_rest_y: float = 18.0
|
||||
var _emote_prior_camera_input_enabled: bool = true
|
||||
var _quick_prior_camera_input_enabled: bool = true
|
||||
var _virtual_mouse_active: bool = false
|
||||
var _virtual_mouse_prior_camera_input_enabled: bool = true
|
||||
var _virtual_mouse_prior_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_VISIBLE
|
||||
var _virtual_mouse_window_position: Vector2 = Vector2.ZERO
|
||||
var _virtual_mouse_button_mask: int = 0
|
||||
var _virtual_mouse_right_pressed: bool = false
|
||||
var _injecting_virtual_mouse_event: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -128,6 +151,7 @@ func _ready() -> void:
|
|||
presentation_parent.get_child_count() - 1,
|
||||
)
|
||||
_emote_radial_menu.emote_selected.connect(_on_emote_selected)
|
||||
_quick_radial_menu.action_selected.connect(_on_quick_action_selected)
|
||||
_chat_ui.text_entry_ownership_changed.connect(
|
||||
_on_chat_text_entry_ownership_changed
|
||||
)
|
||||
|
|
@ -274,6 +298,17 @@ func setup(
|
|||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if (
|
||||
_virtual_mouse_active
|
||||
and _injecting_virtual_mouse_event
|
||||
and event is InputEventMouseMotion
|
||||
):
|
||||
_update_virtual_cursor_position(
|
||||
(event as InputEventMouseMotion).position
|
||||
)
|
||||
if _handle_virtual_mouse_input(event):
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if (
|
||||
_surface_drawing_toolbar != null
|
||||
and _surface_drawing_toolbar.owns_pointer_event(event)
|
||||
|
|
@ -295,7 +330,7 @@ func _input(event: InputEvent) -> void:
|
|||
):
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if _emote_radial_menu == null:
|
||||
if _emote_radial_menu == null or _quick_radial_menu == null:
|
||||
return
|
||||
var can_open: bool = (
|
||||
_gameplay_ui_enabled
|
||||
|
|
@ -304,8 +339,42 @@ func _input(event: InputEvent) -> void:
|
|||
and not _shop_open
|
||||
and not _chat_input_open
|
||||
and not _showcase_active
|
||||
and not _virtual_mouse_active
|
||||
)
|
||||
if _emote_radial_menu.handle_input(event, can_open):
|
||||
var emote_was_open: bool = _emote_radial_menu.is_open()
|
||||
if _emote_radial_menu.handle_input(
|
||||
event,
|
||||
can_open and not _quick_radial_menu.is_open(),
|
||||
):
|
||||
var emote_is_open: bool = _emote_radial_menu.is_open()
|
||||
if emote_is_open != emote_was_open and _player != null:
|
||||
if emote_is_open:
|
||||
_emote_prior_camera_input_enabled = (
|
||||
_player.is_camera_input_enabled()
|
||||
)
|
||||
_player.set_camera_input_enabled(false)
|
||||
else:
|
||||
_player.set_camera_input_enabled(
|
||||
_emote_prior_camera_input_enabled
|
||||
)
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
var quick_was_open: bool = _quick_radial_menu.is_open()
|
||||
if _quick_radial_menu.handle_input(
|
||||
event,
|
||||
can_open and not _emote_radial_menu.is_open(),
|
||||
):
|
||||
var quick_is_open: bool = _quick_radial_menu.is_open()
|
||||
if quick_is_open != quick_was_open and _player != null:
|
||||
if quick_is_open:
|
||||
_quick_prior_camera_input_enabled = (
|
||||
_player.is_camera_input_enabled()
|
||||
)
|
||||
_player.set_camera_input_enabled(false)
|
||||
else:
|
||||
_player.set_camera_input_enabled(
|
||||
_quick_prior_camera_input_enabled
|
||||
)
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
|
|
@ -314,6 +383,212 @@ func _on_emote_selected(emote_id: StringName) -> void:
|
|||
_player.toggle_sitting()
|
||||
|
||||
|
||||
func _on_quick_action_selected(action_id: StringName) -> void:
|
||||
match action_id:
|
||||
&"stuff":
|
||||
_player_menu.open_section(PlayerMenuType.Section.COOLER)
|
||||
&"logbook":
|
||||
_player_menu.open_section(PlayerMenuType.Section.LOGBOOK)
|
||||
&"fishnet":
|
||||
_player_menu.open_section(PlayerMenuType.Section.NET)
|
||||
&"mail":
|
||||
_player_menu.open_section(PlayerMenuType.Section.MAIL)
|
||||
&"profile":
|
||||
_player_menu.open_section(PlayerMenuType.Section.PROFILE)
|
||||
&"online":
|
||||
_player_menu.open_section(PlayerMenuType.Section.PLAYERS)
|
||||
&"paint":
|
||||
_toggle_surface_drawing()
|
||||
&"chat":
|
||||
_chat_ui.open_chat()
|
||||
|
||||
|
||||
func _handle_virtual_mouse_input(event: InputEvent) -> bool:
|
||||
var motion_event: InputEventJoypadMotion = event as InputEventJoypadMotion
|
||||
if motion_event != null:
|
||||
if motion_event.axis == JOY_AXIS_TRIGGER_LEFT:
|
||||
var was_active: bool = _virtual_mouse_active
|
||||
if motion_event.axis_value >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD:
|
||||
if not _virtual_mouse_active and _can_start_virtual_mouse():
|
||||
_begin_virtual_mouse()
|
||||
elif _virtual_mouse_active:
|
||||
_end_virtual_mouse()
|
||||
return was_active or _virtual_mouse_active
|
||||
if (
|
||||
_virtual_mouse_active
|
||||
and motion_event.axis == JOY_AXIS_TRIGGER_RIGHT
|
||||
):
|
||||
_set_virtual_mouse_button(
|
||||
MOUSE_BUTTON_RIGHT,
|
||||
motion_event.axis_value >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD,
|
||||
)
|
||||
return true
|
||||
var button_event: InputEventJoypadButton = event as InputEventJoypadButton
|
||||
if (
|
||||
button_event != null
|
||||
and button_event.button_index == JOY_BUTTON_RIGHT_SHOULDER
|
||||
and (
|
||||
_virtual_mouse_active
|
||||
or Input.get_joy_axis(0, JOY_AXIS_TRIGGER_LEFT)
|
||||
>= VIRTUAL_MOUSE_TRIGGER_THRESHOLD
|
||||
)
|
||||
):
|
||||
if not _virtual_mouse_active and _can_start_virtual_mouse():
|
||||
_begin_virtual_mouse()
|
||||
if _virtual_mouse_active:
|
||||
_set_virtual_mouse_button(MOUSE_BUTTON_LEFT, button_event.pressed)
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _can_start_virtual_mouse() -> bool:
|
||||
return (
|
||||
_gameplay_ui_enabled
|
||||
and not _showcase_active
|
||||
and _player != null
|
||||
and _fishing_spot != null
|
||||
and _fishing_spot.can_use_surface_drawing()
|
||||
and not _emote_radial_menu.is_open()
|
||||
and not _quick_radial_menu.is_open()
|
||||
)
|
||||
|
||||
|
||||
func _begin_virtual_mouse() -> void:
|
||||
if _virtual_mouse_active:
|
||||
return
|
||||
_virtual_mouse_active = true
|
||||
_virtual_mouse_prior_camera_input_enabled = (
|
||||
_player.is_camera_input_enabled()
|
||||
)
|
||||
_player.set_camera_input_enabled(false)
|
||||
if _fishing_spot != null:
|
||||
_fishing_spot.set_local_menu_input_suppressed(
|
||||
VIRTUAL_MOUSE_INPUT_OWNER,
|
||||
true,
|
||||
)
|
||||
_virtual_mouse_prior_mouse_mode = Input.mouse_mode
|
||||
Input.mouse_mode = Input.MOUSE_MODE_HIDDEN
|
||||
_virtual_mouse_button_mask = 0
|
||||
_virtual_mouse_right_pressed = false
|
||||
_virtual_mouse_window_position = Vector2(get_window().size) * 0.5
|
||||
_controller_virtual_cursor.visible = true
|
||||
_emit_virtual_mouse_motion(Vector2.ZERO)
|
||||
|
||||
|
||||
func _end_virtual_mouse() -> void:
|
||||
if not _virtual_mouse_active:
|
||||
return
|
||||
if (_virtual_mouse_button_mask & MOUSE_BUTTON_MASK_LEFT) != 0:
|
||||
_set_virtual_mouse_button(MOUSE_BUTTON_LEFT, false)
|
||||
if _virtual_mouse_right_pressed:
|
||||
_set_virtual_mouse_button(MOUSE_BUTTON_RIGHT, false)
|
||||
_virtual_mouse_active = false
|
||||
_controller_virtual_cursor.visible = false
|
||||
if _fishing_spot != null:
|
||||
_fishing_spot.set_local_menu_input_suppressed(
|
||||
VIRTUAL_MOUSE_INPUT_OWNER,
|
||||
false,
|
||||
)
|
||||
if _player != null and is_instance_valid(_player):
|
||||
_player.set_camera_input_enabled(
|
||||
_virtual_mouse_prior_camera_input_enabled
|
||||
)
|
||||
Input.mouse_mode = _virtual_mouse_prior_mouse_mode
|
||||
|
||||
|
||||
func _update_virtual_mouse(delta: float) -> void:
|
||||
if not _virtual_mouse_active:
|
||||
return
|
||||
if (
|
||||
Input.get_joy_axis(0, JOY_AXIS_TRIGGER_LEFT)
|
||||
< VIRTUAL_MOUSE_TRIGGER_THRESHOLD
|
||||
):
|
||||
_end_virtual_mouse()
|
||||
return
|
||||
var stick: Vector2 = Vector2(
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_X),
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y),
|
||||
)
|
||||
var stick_length: float = stick.length()
|
||||
if stick_length <= VIRTUAL_MOUSE_STICK_DEADZONE:
|
||||
return
|
||||
var adjusted_strength: float = (
|
||||
(stick_length - VIRTUAL_MOUSE_STICK_DEADZONE)
|
||||
/ (1.0 - VIRTUAL_MOUSE_STICK_DEADZONE)
|
||||
)
|
||||
var display_scale: float = UIReferencePresentationType.get_scale(
|
||||
Vector2(get_window().size)
|
||||
)
|
||||
var relative_motion: Vector2 = (
|
||||
stick.normalized()
|
||||
* adjusted_strength
|
||||
* VIRTUAL_MOUSE_SPEED
|
||||
* display_scale
|
||||
* delta
|
||||
)
|
||||
var window_size: Vector2 = Vector2(get_window().size)
|
||||
_virtual_mouse_window_position = Vector2(
|
||||
clampf(
|
||||
_virtual_mouse_window_position.x + relative_motion.x,
|
||||
0.0,
|
||||
window_size.x,
|
||||
),
|
||||
clampf(
|
||||
_virtual_mouse_window_position.y + relative_motion.y,
|
||||
0.0,
|
||||
window_size.y,
|
||||
),
|
||||
)
|
||||
_emit_virtual_mouse_motion(relative_motion)
|
||||
|
||||
|
||||
func _set_virtual_mouse_button(button: MouseButton, pressed: bool) -> void:
|
||||
var mask: int = (
|
||||
MOUSE_BUTTON_MASK_LEFT
|
||||
if button == MOUSE_BUTTON_LEFT
|
||||
else MOUSE_BUTTON_MASK_RIGHT
|
||||
)
|
||||
var already_pressed: bool = bool(_virtual_mouse_button_mask & mask)
|
||||
if already_pressed == pressed:
|
||||
return
|
||||
if pressed:
|
||||
_virtual_mouse_button_mask |= mask
|
||||
else:
|
||||
_virtual_mouse_button_mask &= ~mask
|
||||
if button == MOUSE_BUTTON_RIGHT:
|
||||
_virtual_mouse_right_pressed = pressed
|
||||
var mouse_event := InputEventMouseButton.new()
|
||||
mouse_event.position = _virtual_mouse_window_position
|
||||
mouse_event.global_position = _virtual_mouse_window_position
|
||||
mouse_event.button_index = button
|
||||
mouse_event.button_mask = _virtual_mouse_button_mask
|
||||
mouse_event.pressed = pressed
|
||||
mouse_event.factor = 1.0
|
||||
_parse_virtual_mouse_event(mouse_event)
|
||||
|
||||
|
||||
func _emit_virtual_mouse_motion(relative_motion: Vector2) -> void:
|
||||
var motion_event := InputEventMouseMotion.new()
|
||||
motion_event.position = _virtual_mouse_window_position
|
||||
motion_event.global_position = _virtual_mouse_window_position
|
||||
motion_event.relative = relative_motion
|
||||
motion_event.button_mask = _virtual_mouse_button_mask
|
||||
_parse_virtual_mouse_event(motion_event)
|
||||
|
||||
|
||||
func _parse_virtual_mouse_event(event: InputEventMouse) -> void:
|
||||
_injecting_virtual_mouse_event = true
|
||||
Input.parse_input_event(event)
|
||||
_injecting_virtual_mouse_event = false
|
||||
|
||||
|
||||
func _update_virtual_cursor_position(viewport_position: Vector2) -> void:
|
||||
var root_transform: Transform2D = _ui_root.get_global_transform_with_canvas()
|
||||
_controller_virtual_cursor.set_pointer_position(
|
||||
root_transform.affine_inverse() * viewport_position
|
||||
)
|
||||
|
||||
|
||||
func _toggle_surface_drawing() -> void:
|
||||
if _surface_drawing == null:
|
||||
return
|
||||
|
|
@ -344,7 +619,8 @@ func setup_data_and_identity(
|
|||
)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
func _process(delta: float) -> void:
|
||||
_update_virtual_mouse(delta)
|
||||
_update_experience_bubble_position()
|
||||
if _item_effects == null or not _gameplay_ui_enabled:
|
||||
_effect_status.hide()
|
||||
|
|
@ -403,6 +679,19 @@ func set_gameplay_ui_enabled(enabled: bool) -> void:
|
|||
_experience_presentation.visible = enabled
|
||||
_refresh_chat_availability()
|
||||
if not enabled:
|
||||
_end_virtual_mouse()
|
||||
if _emote_radial_menu != null and _emote_radial_menu.is_open():
|
||||
_emote_radial_menu.close_menu()
|
||||
if _player != null:
|
||||
_player.set_camera_input_enabled(
|
||||
_emote_prior_camera_input_enabled
|
||||
)
|
||||
if _quick_radial_menu != null and _quick_radial_menu.is_open():
|
||||
_quick_radial_menu.close_menu()
|
||||
if _player != null:
|
||||
_player.set_camera_input_enabled(
|
||||
_quick_prior_camera_input_enabled
|
||||
)
|
||||
if _surface_drawing != null:
|
||||
_surface_drawing.deactivate()
|
||||
close_player_menu_for_session_end()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=19 format=3]
|
||||
[gd_scene load_steps=21 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/game_ui.gd" id="1_ui"]
|
||||
[ext_resource type="PackedScene" path="res://ui/player_menu.tscn" id="2_menu"]
|
||||
|
|
@ -11,6 +11,8 @@
|
|||
[ext_resource type="Script" path="res://ui/chat_ui.gd" id="9_chat"]
|
||||
[ext_resource type="PackedScene" path="res://ui/emote_radial_menu.tscn" id="10_emote"]
|
||||
[ext_resource type="PackedScene" path="res://ui/surface_drawing_toolbar.tscn" id="11_drawing_toolbar"]
|
||||
[ext_resource type="PackedScene" path="res://ui/quick_radial_menu.tscn" id="12_quick"]
|
||||
[ext_resource type="Script" path="res://ui/controller_virtual_cursor.gd" id="13_cursor"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBox_chase_background"]
|
||||
bg_color = Color(0.032, 0.118, 0.15, 1)
|
||||
|
|
@ -328,6 +330,9 @@ unique_name_in_owner = true
|
|||
[node name="EmoteRadialMenu" parent="UIRoot/CanonicalStage" instance=ExtResource("10_emote")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="QuickRadialMenu" parent="UIRoot/CanonicalStage" instance=ExtResource("12_quick")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="ShopPrompt" type="PanelContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
|
@ -386,6 +391,12 @@ grow_vertical = 2
|
|||
mouse_filter = 2
|
||||
script = ExtResource("9_chat")
|
||||
|
||||
[node name="ControllerVirtualCursor" type="Control" parent="UIRoot"]
|
||||
unique_name_in_owner = true
|
||||
z_index = 500
|
||||
mouse_filter = 2
|
||||
script = ExtResource("13_cursor")
|
||||
|
||||
[node name="ScreenFade" type="ColorRect" parent="UIRoot"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
|
|
|||
|
|
@ -701,6 +701,25 @@ func open_menu() -> void:
|
|||
menu_visibility_changed.emit(true)
|
||||
|
||||
|
||||
func open_section(section: Section) -> bool:
|
||||
if (
|
||||
_shop_cooler_context_active
|
||||
or _player == null
|
||||
or _fishing_spot == null
|
||||
or not _fishing_spot.can_open_player_menu()
|
||||
):
|
||||
return false
|
||||
if visible:
|
||||
if _transitioning or _page_transitioning or _sale_confirmation.visible:
|
||||
return false
|
||||
if section != _current_section:
|
||||
_show_section(section)
|
||||
return true
|
||||
_current_section = section
|
||||
open_menu()
|
||||
return visible
|
||||
|
||||
|
||||
func mount_shop_cooler(
|
||||
host: Control,
|
||||
buyer: FishBuyerProfileType,
|
||||
|
|
|
|||
152
ui/quick_radial_menu.gd
Normal file
152
ui/quick_radial_menu.gd
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
class_name QuickRadialMenu
|
||||
extends Control
|
||||
|
||||
signal action_selected(action_id: StringName)
|
||||
|
||||
const BubbleButtonScene: PackedScene = preload(
|
||||
"res://ui/components/bubble_menu/bubble_button.tscn"
|
||||
)
|
||||
const BubbleProfile: BubbleMenuProfile = preload(
|
||||
"res://ui/components/bubble_menu/bubble_menu_profile.tres"
|
||||
)
|
||||
const SECTOR_COUNT: int = 8
|
||||
const RING_RADIUS: float = 172.0
|
||||
const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0)
|
||||
const CONTROLLER_SELECTION_DEADZONE: float = 0.35
|
||||
const ACTIONS: Array[StringName] = [
|
||||
&"stuff",
|
||||
&"logbook",
|
||||
&"fishnet",
|
||||
&"mail",
|
||||
&"profile",
|
||||
&"online",
|
||||
&"paint",
|
||||
&"chat",
|
||||
]
|
||||
const LABELS: Array[String] = [
|
||||
"stuff",
|
||||
"logbook",
|
||||
"fishnet",
|
||||
"mail",
|
||||
"profile",
|
||||
"online",
|
||||
"paint",
|
||||
"chat",
|
||||
]
|
||||
|
||||
var _buttons: Array[BubbleButton] = []
|
||||
var _is_open: bool = false
|
||||
var _selected_sector: int = 0
|
||||
var _controller_selection_mode: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
visible = false
|
||||
mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
for sector: int in SECTOR_COUNT:
|
||||
var bubble: BubbleButton = BubbleButtonScene.instantiate() as BubbleButton
|
||||
bubble.profile = BubbleProfile
|
||||
bubble.focus_mode = Control.FOCUS_NONE
|
||||
bubble.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
bubble.text = LABELS[sector]
|
||||
add_child(bubble)
|
||||
_buttons.append(bubble)
|
||||
_apply_selection_styles()
|
||||
|
||||
|
||||
func handle_input(event: InputEvent, can_open: bool) -> bool:
|
||||
if not event.is_action("open_quick_actions"):
|
||||
return false
|
||||
var key_event: InputEventKey = event as InputEventKey
|
||||
if key_event != null and key_event.echo:
|
||||
return false
|
||||
if event.is_pressed():
|
||||
if _is_open or not can_open:
|
||||
return _is_open
|
||||
open_menu(event is InputEventJoypadButton)
|
||||
return true
|
||||
if not _is_open:
|
||||
return false
|
||||
var selected: int = _selected_sector
|
||||
close_menu()
|
||||
call_deferred("_emit_selected_action", ACTIONS[selected])
|
||||
return true
|
||||
|
||||
|
||||
func open_menu(controller_selection: bool = false) -> void:
|
||||
_is_open = true
|
||||
_selected_sector = 0
|
||||
_controller_selection_mode = controller_selection
|
||||
visible = true
|
||||
_layout_bubbles()
|
||||
_apply_selection_styles()
|
||||
|
||||
|
||||
func close_menu() -> void:
|
||||
_is_open = false
|
||||
visible = false
|
||||
|
||||
|
||||
func is_open() -> bool:
|
||||
return _is_open
|
||||
|
||||
|
||||
func _emit_selected_action(action_id: StringName) -> void:
|
||||
action_selected.emit(action_id)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if not _is_open:
|
||||
return
|
||||
_layout_bubbles()
|
||||
_update_selection()
|
||||
|
||||
|
||||
func _layout_bubbles() -> void:
|
||||
var center: Vector2 = size * 0.5
|
||||
for sector: int in SECTOR_COUNT:
|
||||
var angle: float = -PI * 0.5 + TAU * float(sector) / float(SECTOR_COUNT)
|
||||
var bubble_center: Vector2 = center + Vector2.from_angle(angle) * RING_RADIUS
|
||||
var bubble: BubbleButton = _buttons[sector]
|
||||
bubble.position = bubble_center - BUBBLE_SIZE * 0.5
|
||||
bubble.size = BUBBLE_SIZE
|
||||
bubble.pivot_offset = BUBBLE_SIZE * 0.5
|
||||
|
||||
|
||||
func _update_selection() -> void:
|
||||
var stick: Vector2 = Vector2(
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_X),
|
||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y),
|
||||
)
|
||||
if stick.length() >= CONTROLLER_SELECTION_DEADZONE:
|
||||
_select_sector_from_offset(stick)
|
||||
return
|
||||
if _controller_selection_mode:
|
||||
return
|
||||
_update_mouse_selection()
|
||||
|
||||
|
||||
func _update_mouse_selection() -> void:
|
||||
var offset: Vector2 = get_local_mouse_position() - size * 0.5
|
||||
if offset.length() < 24.0:
|
||||
return
|
||||
_select_sector_from_offset(offset)
|
||||
|
||||
|
||||
func _select_sector_from_offset(offset: Vector2) -> void:
|
||||
var angle: float = fposmod(offset.angle() + PI * 0.5 + PI / 8.0, TAU)
|
||||
var sector: int = int(floor(angle / (TAU / float(SECTOR_COUNT))))
|
||||
if sector == _selected_sector:
|
||||
return
|
||||
_selected_sector = sector
|
||||
_apply_selection_styles()
|
||||
|
||||
|
||||
func _apply_selection_styles() -> void:
|
||||
for sector: int in _buttons.size():
|
||||
var bubble: BubbleButton = _buttons[sector]
|
||||
bubble.apply_profile()
|
||||
if sector == _selected_sector:
|
||||
bubble.add_theme_stylebox_override(
|
||||
"normal", BubbleProfile.make_hover_style()
|
||||
)
|
||||
1
ui/quick_radial_menu.gd.uid
Normal file
1
ui/quick_radial_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://5nr1c8x881sw
|
||||
14
ui/quick_radial_menu.tscn
Normal file
14
ui/quick_radial_menu.tscn
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/quick_radial_menu.gd" id="1_quick"]
|
||||
|
||||
[node name="QuickRadialMenu" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
z_index = 90
|
||||
script = ExtResource("1_quick")
|
||||
Loading…
Add table
Add a link
Reference in a new issue