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"
|
type="CompressedTexture2D"
|
||||||
uid="uid://crci2on30ctoc"
|
uid="uid://crci2on30ctoc"
|
||||||
path.s3tc="res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex"
|
path.s3tc="res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.s3tc.ctex"
|
||||||
|
path.etc2="res://.godot/imported/grass_lite.png-f89cf6413257cd31582bd4f9f875ae85.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/environment/textures/grass_lite.png"
|
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]
|
[params]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,16 @@ importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://btxhq3rdlum2"
|
uid="uid://btxhq3rdlum2"
|
||||||
path.s3tc="res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"
|
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={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/environment/textures/grass_olive_tile.png"
|
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]
|
[params]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,16 @@ importer="texture"
|
||||||
type="CompressedTexture2D"
|
type="CompressedTexture2D"
|
||||||
uid="uid://bnje415gq85nn"
|
uid="uid://bnje415gq85nn"
|
||||||
path.s3tc="res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex"
|
path.s3tc="res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.s3tc.ctex"
|
||||||
|
path.etc2="res://.godot/imported/sand.png-41fc96c392119deeba43c2d4e49d88a5.etc2.ctex"
|
||||||
metadata={
|
metadata={
|
||||||
"imported_formats": ["s3tc_bptc"],
|
"imported_formats": ["s3tc_bptc", "etc2_astc"],
|
||||||
"vram_texture": true
|
"vram_texture": true
|
||||||
}
|
}
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://art/exported/environment/textures/sand.png"
|
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]
|
[params]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,8 @@ class ShowcaseCameraSnapshot:
|
||||||
@export var maximum_zoom: float = 8.0
|
@export var maximum_zoom: float = 8.0
|
||||||
@export var zoom_step: float = 0.75
|
@export var zoom_step: float = 0.75
|
||||||
@export var zoom_smoothing: float = 12.0
|
@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 _visuals: Node3D = %Visuals
|
||||||
@onready var _character_animation_player: AnimationPlayer = (
|
@onready var _character_animation_player: AnimationPlayer = (
|
||||||
|
|
@ -290,6 +292,16 @@ func _process(delta: float) -> void:
|
||||||
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y)
|
Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y)
|
||||||
)
|
)
|
||||||
if stick.length() > controller_camera_deadzone:
|
if stick.length() > controller_camera_deadzone:
|
||||||
|
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 = (
|
var adjusted_strength: float = (
|
||||||
(stick.length() - controller_camera_deadzone)
|
(stick.length() - controller_camera_deadzone)
|
||||||
/ (1.0 - controller_camera_deadzone)
|
/ (1.0 - controller_camera_deadzone)
|
||||||
|
|
@ -435,6 +447,17 @@ func _set_target_zoom(value: float) -> void:
|
||||||
_target_zoom = clampf(value, minimum_zoom, maximum_zoom)
|
_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:
|
func set_local_control(enabled: bool) -> void:
|
||||||
local_control_enabled = enabled
|
local_control_enabled = enabled
|
||||||
if is_node_ready():
|
if is_node_ready():
|
||||||
|
|
|
||||||
|
|
@ -80,13 +80,13 @@ slow_walk={
|
||||||
interact={
|
interact={
|
||||||
"deadzone": 0.2,
|
"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)
|
"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={
|
fish_primary={
|
||||||
"deadzone": 0.2,
|
"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)
|
"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={
|
camera_drag={
|
||||||
|
|
@ -97,13 +97,11 @@ camera_drag={
|
||||||
camera_zoom_in={
|
camera_zoom_in={
|
||||||
"deadzone": 0.2,
|
"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)
|
"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={
|
camera_zoom_out={
|
||||||
"deadzone": 0.2,
|
"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)
|
"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={
|
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)
|
, 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={
|
open_tacklebox={
|
||||||
"deadzone": 0.2,
|
"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)
|
"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)
|
"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]
|
[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_left", JOY_AXIS_LEFT_X, -1.0))
|
||||||
assert(_has_joypad_motion(&"move_right", 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(&"jump", JOY_BUTTON_A))
|
||||||
assert(_has_joypad_button(&"interact", JOY_BUTTON_X))
|
assert(_has_joypad_button(&"ui_accept", JOY_BUTTON_A))
|
||||||
assert(_has_joypad_motion(&"fish_primary", JOY_AXIS_TRIGGER_RIGHT, 1.0))
|
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(&"sprint", JOY_BUTTON_LEFT_STICK))
|
||||||
assert(_has_joypad_button(&"camera_zoom_out", JOY_BUTTON_LEFT_SHOULDER))
|
assert(not _has_joypad_button(
|
||||||
assert(_has_joypad_button(&"camera_zoom_in", JOY_BUTTON_RIGHT_SHOULDER))
|
&"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_previous", JOY_BUTTON_DPAD_LEFT))
|
||||||
assert(_has_joypad_button(&"hotbar_next", JOY_BUTTON_DPAD_RIGHT))
|
assert(_has_joypad_button(&"hotbar_next", JOY_BUTTON_DPAD_RIGHT))
|
||||||
assert(_has_joypad_button(&"open_backpack", JOY_BUTTON_BACK))
|
assert(_has_joypad_button(&"open_backpack", JOY_BUTTON_BACK))
|
||||||
assert(_has_joypad_button(&"open_system_menu", JOY_BUTTON_START))
|
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_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")
|
print("android readiness validation passed")
|
||||||
quit()
|
quit()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,13 @@ func close_chat() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> 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 is InputEventKey and event.pressed and not event.echo:
|
||||||
if event.keycode in [KEY_ENTER, KEY_KP_ENTER]:
|
if event.keycode in [KEY_ENTER, KEY_KP_ENTER]:
|
||||||
if _opened:
|
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 SIT_SECTOR: int = 0
|
||||||
const RING_RADIUS: float = 172.0
|
const RING_RADIUS: float = 172.0
|
||||||
const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0)
|
const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0)
|
||||||
|
const CONTROLLER_SELECTION_DEADZONE: float = 0.35
|
||||||
|
|
||||||
var _buttons: Array[BubbleButton] = []
|
var _buttons: Array[BubbleButton] = []
|
||||||
var _is_open: bool = false
|
var _is_open: bool = false
|
||||||
var _selected_sector: int = SIT_SECTOR
|
var _selected_sector: int = SIT_SECTOR
|
||||||
|
var _controller_selection_mode: bool = false
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
@ -42,7 +44,7 @@ func handle_input(event: InputEvent, can_open: bool) -> bool:
|
||||||
if event.is_pressed():
|
if event.is_pressed():
|
||||||
if _is_open or not can_open:
|
if _is_open or not can_open:
|
||||||
return _is_open
|
return _is_open
|
||||||
open_menu()
|
open_menu(event is InputEventJoypadButton)
|
||||||
return true
|
return true
|
||||||
if not _is_open:
|
if not _is_open:
|
||||||
return false
|
return false
|
||||||
|
|
@ -53,9 +55,10 @@ func handle_input(event: InputEvent, can_open: bool) -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
func open_menu() -> void:
|
func open_menu(controller_selection: bool = false) -> void:
|
||||||
_is_open = true
|
_is_open = true
|
||||||
_selected_sector = SIT_SECTOR
|
_selected_sector = SIT_SECTOR
|
||||||
|
_controller_selection_mode = controller_selection
|
||||||
visible = true
|
visible = true
|
||||||
_layout_bubbles()
|
_layout_bubbles()
|
||||||
_apply_selection_styles()
|
_apply_selection_styles()
|
||||||
|
|
@ -74,7 +77,7 @@ func _process(_delta: float) -> void:
|
||||||
if not _is_open:
|
if not _is_open:
|
||||||
return
|
return
|
||||||
_layout_bubbles()
|
_layout_bubbles()
|
||||||
_update_mouse_selection()
|
_update_selection()
|
||||||
|
|
||||||
|
|
||||||
func _layout_bubbles() -> void:
|
func _layout_bubbles() -> void:
|
||||||
|
|
@ -88,10 +91,27 @@ func _layout_bubbles() -> void:
|
||||||
bubble.pivot_offset = BUBBLE_SIZE * 0.5
|
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:
|
func _update_mouse_selection() -> void:
|
||||||
var offset: Vector2 = get_local_mouse_position() - size * 0.5
|
var offset: Vector2 = get_local_mouse_position() - size * 0.5
|
||||||
if offset.length() < 24.0:
|
if offset.length() < 24.0:
|
||||||
return
|
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 angle: float = fposmod(offset.angle() + PI * 0.5 + PI / 8.0, TAU)
|
||||||
var sector: int = int(floor(angle / (TAU / float(SECTOR_COUNT))))
|
var sector: int = int(floor(angle / (TAU / float(SECTOR_COUNT))))
|
||||||
if sector == _selected_sector:
|
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 ChatUIType = preload("res://ui/chat_ui.gd")
|
||||||
const EmoteRadialMenuType = preload("res://ui/emote_radial_menu.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(
|
const SurfaceDrawingToolbarType = preload(
|
||||||
"res://ui/surface_drawing_toolbar.gd"
|
"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 player_menu_backdrop_visibility_changed(is_visible: bool)
|
||||||
signal shop_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 _status_label: Label = %StatusLabel
|
||||||
@onready var _gameplay_transient_hud: Control = %GameplayTransientHUD
|
@onready var _gameplay_transient_hud: Control = %GameplayTransientHUD
|
||||||
@onready var _experience_presentation: Control = %ExperiencePresentation
|
@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: PanelContainer = %ExperienceBubble
|
||||||
@onready var _experience_bubble_label: Label = %ExperienceBubbleLabel
|
@onready var _experience_bubble_label: Label = %ExperienceBubbleLabel
|
||||||
@onready var _canonical_stage: Control = %CanonicalStage
|
@onready var _canonical_stage: Control = %CanonicalStage
|
||||||
|
@onready var _ui_root: Control = %UIRoot
|
||||||
@onready var _player_menu: PlayerMenuType = %PlayerMenu
|
@onready var _player_menu: PlayerMenuType = %PlayerMenu
|
||||||
@onready var _screen_fade: ScreenFade = %ScreenFade
|
@onready var _screen_fade: ScreenFade = %ScreenFade
|
||||||
@onready var _title_screen: TitleScreenType = %TitleScreen
|
@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 _effect_status: Label = %EffectStatus
|
||||||
@onready var _chat_ui: ChatUIType = %ChatUI
|
@onready var _chat_ui: ChatUIType = %ChatUI
|
||||||
@onready var _emote_radial_menu: EmoteRadialMenuType = %EmoteRadialMenu
|
@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 = (
|
@onready var _surface_drawing_toolbar: SurfaceDrawingToolbarType = (
|
||||||
%SurfaceDrawingToolbar
|
%SurfaceDrawingToolbar
|
||||||
)
|
)
|
||||||
|
|
@ -115,6 +129,15 @@ var _experience_award_queue: Array[Dictionary] = []
|
||||||
var _experience_animation_active: bool = false
|
var _experience_animation_active: bool = false
|
||||||
var _experience_animation_generation: int = 0
|
var _experience_animation_generation: int = 0
|
||||||
var _experience_panel_rest_y: float = 18.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:
|
func _ready() -> void:
|
||||||
|
|
@ -128,6 +151,7 @@ func _ready() -> void:
|
||||||
presentation_parent.get_child_count() - 1,
|
presentation_parent.get_child_count() - 1,
|
||||||
)
|
)
|
||||||
_emote_radial_menu.emote_selected.connect(_on_emote_selected)
|
_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(
|
_chat_ui.text_entry_ownership_changed.connect(
|
||||||
_on_chat_text_entry_ownership_changed
|
_on_chat_text_entry_ownership_changed
|
||||||
)
|
)
|
||||||
|
|
@ -274,6 +298,17 @@ func setup(
|
||||||
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
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 (
|
if (
|
||||||
_surface_drawing_toolbar != null
|
_surface_drawing_toolbar != null
|
||||||
and _surface_drawing_toolbar.owns_pointer_event(event)
|
and _surface_drawing_toolbar.owns_pointer_event(event)
|
||||||
|
|
@ -295,7 +330,7 @@ func _input(event: InputEvent) -> void:
|
||||||
):
|
):
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
return
|
return
|
||||||
if _emote_radial_menu == null:
|
if _emote_radial_menu == null or _quick_radial_menu == null:
|
||||||
return
|
return
|
||||||
var can_open: bool = (
|
var can_open: bool = (
|
||||||
_gameplay_ui_enabled
|
_gameplay_ui_enabled
|
||||||
|
|
@ -304,8 +339,42 @@ func _input(event: InputEvent) -> void:
|
||||||
and not _shop_open
|
and not _shop_open
|
||||||
and not _chat_input_open
|
and not _chat_input_open
|
||||||
and not _showcase_active
|
and not _showcase_active
|
||||||
|
and not _virtual_mouse_active
|
||||||
|
)
|
||||||
|
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
|
||||||
)
|
)
|
||||||
if _emote_radial_menu.handle_input(event, can_open):
|
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -314,6 +383,212 @@ func _on_emote_selected(emote_id: StringName) -> void:
|
||||||
_player.toggle_sitting()
|
_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:
|
func _toggle_surface_drawing() -> void:
|
||||||
if _surface_drawing == null:
|
if _surface_drawing == null:
|
||||||
return
|
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()
|
_update_experience_bubble_position()
|
||||||
if _item_effects == null or not _gameplay_ui_enabled:
|
if _item_effects == null or not _gameplay_ui_enabled:
|
||||||
_effect_status.hide()
|
_effect_status.hide()
|
||||||
|
|
@ -403,6 +679,19 @@ func set_gameplay_ui_enabled(enabled: bool) -> void:
|
||||||
_experience_presentation.visible = enabled
|
_experience_presentation.visible = enabled
|
||||||
_refresh_chat_availability()
|
_refresh_chat_availability()
|
||||||
if not enabled:
|
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:
|
if _surface_drawing != null:
|
||||||
_surface_drawing.deactivate()
|
_surface_drawing.deactivate()
|
||||||
close_player_menu_for_session_end()
|
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="Script" path="res://ui/game_ui.gd" id="1_ui"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/player_menu.tscn" id="2_menu"]
|
[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="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/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/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"]
|
[sub_resource type="StyleBoxFlat" id="StyleBox_chase_background"]
|
||||||
bg_color = Color(0.032, 0.118, 0.15, 1)
|
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")]
|
[node name="EmoteRadialMenu" parent="UIRoot/CanonicalStage" instance=ExtResource("10_emote")]
|
||||||
unique_name_in_owner = true
|
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"]
|
[node name="ShopPrompt" type="PanelContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
visible = false
|
visible = false
|
||||||
|
|
@ -386,6 +391,12 @@ grow_vertical = 2
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
script = ExtResource("9_chat")
|
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"]
|
[node name="ScreenFade" type="ColorRect" parent="UIRoot"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
visible = false
|
visible = false
|
||||||
|
|
|
||||||
|
|
@ -701,6 +701,25 @@ func open_menu() -> void:
|
||||||
menu_visibility_changed.emit(true)
|
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(
|
func mount_shop_cooler(
|
||||||
host: Control,
|
host: Control,
|
||||||
buyer: FishBuyerProfileType,
|
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