2D multiplayer platformer using Godot Engine
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

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)