You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.8 KiB
114 lines
3.8 KiB
class_name RadialMenu |
|
extends Node2D |
|
|
|
const TIME_FADE := 0.6 |
|
const TIME_VISIBLE := 0.4 |
|
|
|
@export var cursor : Cursor |
|
@export var player : Player |
|
|
|
@export var min_segments := 8 |
|
@export var inner_radius := 32.0 |
|
@export var outer_radius := 64.0 |
|
@export var separation := 2.0 |
|
|
|
@onready var label := $Label as Label |
|
@onready var start_angle := (TAU / 4) - (TAU / min_segments / 2) |
|
|
|
var visibility_timer: float |
|
|
|
var hovered: Item: |
|
get: return hovered |
|
set(value): hovered = value; label.text = str(value.name) if value else "" |
|
|
|
func _unhandled_input(event: InputEvent) -> void: |
|
if not player or not player.health.is_alive: return |
|
|
|
if event.is_action_pressed("interact_select"): |
|
position = cursor.hud_position.round() |
|
visible = true |
|
modulate = Color.WHITE |
|
|
|
hovered = player.inventory.equipped |
|
player.inventory.equipped = null |
|
|
|
visibility_timer = INF |
|
|
|
var select_dec := event.is_action_pressed("interact_select_dec") |
|
var select_inc := event.is_action_pressed("interact_select_inc") |
|
if select_dec != select_inc: # xor would be more fitting here |
|
if visible and visibility_timer == INF: |
|
var cursor_offset := to_local(cursor.hud_position) |
|
if cursor_offset.length() > inner_radius: return |
|
else: |
|
position = player.get_global_transform_with_canvas().origin |
|
hovered = player.inventory.equipped |
|
|
|
visible = true |
|
modulate = Color.WHITE |
|
visibility_timer = TIME_FADE + TIME_VISIBLE |
|
|
|
var items := player.inventory.get_items() |
|
if items.is_empty(): return |
|
|
|
var new_index := 0 |
|
if hovered: |
|
var index := hovered.get_index() |
|
var diff := 1 if select_inc else -1 |
|
new_index = posmod(index + diff, items.size()) |
|
hovered = items[new_index] |
|
player.inventory.equipped = hovered |
|
queue_redraw() |
|
|
|
func _process(delta: float) -> void: |
|
if not player or not player.health.is_alive: visible = false |
|
if not visible: return |
|
|
|
visibility_timer -= delta |
|
if visibility_timer <= 0.0: visible = false |
|
if visibility_timer < TIME_FADE: modulate = Color(Color.WHITE, visibility_timer / TIME_FADE) |
|
if visibility_timer < INF: return |
|
|
|
var cursor_offset := to_local(cursor.hud_position) |
|
var angle := cursor_offset.angle() - start_angle |
|
var index := floori(fmod((angle / TAU + 1), 1) * min_segments) |
|
|
|
var items := player.inventory.get_items() |
|
if cursor_offset.length() > inner_radius and index < items.size() and items[index] != hovered: |
|
hovered = items[index] |
|
|
|
if not Input.is_action_pressed("interact_select"): |
|
player.inventory.equipped = hovered |
|
visibility_timer = TIME_FADE |
|
|
|
queue_redraw() |
|
|
|
func _draw() -> void: |
|
var items := player.inventory.get_items() |
|
var segments := maxi(min_segments, items.size()) |
|
for i in segments: |
|
var angle_1 := start_angle + TAU * ( i / float(segments)) |
|
var angle_3 := start_angle + TAU * ((i + 1) / float(segments)) |
|
var angle_2 := (angle_1 + angle_3) / 2 |
|
|
|
var sep_1 := separation * Vector2.from_angle(angle_1 + TAU / 4) |
|
var sep_2 := separation * Vector2.from_angle(angle_3 - TAU / 4) |
|
|
|
var is_hovered := i < items.size() and items[i] == hovered |
|
var inner_radius_2 := inner_radius + (5.0 if is_hovered else 0.0) |
|
var outer_radius_2 := outer_radius + (5.0 if is_hovered else 0.0) |
|
|
|
var color := Color(0.1, 0.1, 0.1, 0.7 if is_hovered else 0.4) |
|
draw_colored_polygon([ |
|
inner_radius_2 * Vector2.from_angle(angle_1) + sep_1, |
|
outer_radius_2 * Vector2.from_angle(angle_1) + sep_1, |
|
(outer_radius_2 + separation) * Vector2.from_angle(angle_2) , |
|
outer_radius_2 * Vector2.from_angle(angle_3) + sep_2, |
|
inner_radius_2 * Vector2.from_angle(angle_3) + sep_2, |
|
], color) |
|
|
|
if i < items.size(): |
|
var sprite := items[i] |
|
var pos := (inner_radius_2 + outer_radius_2) / 2 * Vector2.from_angle(angle_2) |
|
if sprite.centered: pos -= sprite.texture.get_size() / 2 |
|
draw_texture(sprite.texture, pos, sprite.modulate)
|
|
|