187 lines
5.1 KiB
GDScript
187 lines
5.1 KiB
GDScript
class_name CoolerFishSprite
|
|
extends Button
|
|
|
|
@onready var _visual_root: Control = %VisualRoot
|
|
@onready var _fish_shadow: TextureRect = %FishShadow
|
|
@onready var _fish_texture: TextureRect = %FishTexture
|
|
@onready var _favorite_marker: Label = %FavoriteMarker
|
|
|
|
var catch_id: StringName
|
|
var _display_name: String = ""
|
|
var _neutral_position := Vector2.ZERO
|
|
var _target_position := Vector2.ZERO
|
|
var _motion_phase: float = 0.0
|
|
var _depth_scale: float = 1.0
|
|
var _batch_selected: bool = false
|
|
var _focused_catch: bool = false
|
|
var _hovered: bool = false
|
|
var _quality_color := Color.WHITE
|
|
|
|
|
|
func _ready() -> void:
|
|
set_meta(&"controller_focus_inversion_disabled", true)
|
|
resized.connect(_update_visual_pivot)
|
|
focus_entered.connect(_refresh_style)
|
|
focus_exited.connect(_refresh_style)
|
|
mouse_entered.connect(func() -> void:
|
|
_hovered = true
|
|
_refresh_style()
|
|
)
|
|
mouse_exited.connect(func() -> void:
|
|
_hovered = false
|
|
_refresh_style()
|
|
)
|
|
_update_visual_pivot()
|
|
_refresh_style()
|
|
|
|
|
|
func configure(
|
|
identity: StringName,
|
|
display_name: String,
|
|
texture: Texture2D,
|
|
phase: float,
|
|
depth_scale: float,
|
|
quality_color: Color,
|
|
) -> void:
|
|
catch_id = identity
|
|
_display_name = display_name
|
|
_fish_texture.texture = texture
|
|
_fish_shadow.texture = texture
|
|
_motion_phase = phase
|
|
_depth_scale = depth_scale
|
|
_quality_color = quality_color
|
|
_refresh_style()
|
|
tooltip_text = "%s · drag to a hotbar slot" % _display_name
|
|
|
|
|
|
func _get_drag_data(_at_position: Vector2) -> Variant:
|
|
if catch_id.is_empty() or disabled or _fish_texture.texture == null:
|
|
return null
|
|
var preview := VBoxContainer.new()
|
|
preview.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
preview.add_theme_constant_override("separation", 2)
|
|
var texture := TextureRect.new()
|
|
texture.custom_minimum_size = Vector2(72.0, 52.0)
|
|
texture.texture = _fish_texture.texture
|
|
texture.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
|
texture.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
|
texture.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
|
texture.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
preview.add_child(texture)
|
|
var label := Label.new()
|
|
label.text = _display_name
|
|
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
label.add_theme_font_size_override("font_size", 12)
|
|
preview.add_child(label)
|
|
set_drag_preview(preview)
|
|
return {
|
|
"kind": "cooler_fish",
|
|
"catch_id": String(catch_id),
|
|
}
|
|
|
|
|
|
func set_target_position(target: Vector2, immediate: bool = false) -> void:
|
|
_target_position = target
|
|
if immediate:
|
|
_neutral_position = target
|
|
position = _neutral_position
|
|
|
|
|
|
func set_item_state(
|
|
batch_selected: bool,
|
|
focused_catch: bool,
|
|
favorite: bool,
|
|
) -> void:
|
|
_batch_selected = batch_selected
|
|
_focused_catch = focused_catch
|
|
_favorite_marker.visible = favorite
|
|
_refresh_style()
|
|
|
|
|
|
func advance_presentation(delta: float, elapsed: float) -> void:
|
|
var response: float = 1.0 - exp(-9.0 * delta)
|
|
_neutral_position = _neutral_position.lerp(_target_position, response)
|
|
position = _neutral_position
|
|
var bob: float = sin(elapsed * TAU / 7.2 + _motion_phase) * 1.1
|
|
var tilt: float = sin(elapsed * TAU / 9.0 + _motion_phase * 1.31) * 0.018
|
|
var interaction_lift: float = 0.0
|
|
if _batch_selected:
|
|
interaction_lift += 3.0
|
|
if _focused_catch or has_focus():
|
|
interaction_lift += 1.5
|
|
elif _hovered:
|
|
interaction_lift += 0.8
|
|
_visual_root.position = Vector2(0.0, bob - interaction_lift)
|
|
_visual_root.rotation = tilt
|
|
var emphasis: float = 1.0
|
|
if _batch_selected:
|
|
emphasis += 0.085
|
|
if _focused_catch or has_focus():
|
|
emphasis += 0.035
|
|
elif _hovered:
|
|
emphasis += 0.045
|
|
_visual_root.scale = Vector2.ONE * _depth_scale * emphasis
|
|
|
|
|
|
func _has_point(point: Vector2) -> bool:
|
|
var radius: float = minf(size.x, size.y) * 0.48
|
|
if radius <= 0.0:
|
|
return false
|
|
return (point - size * 0.5).length_squared() <= radius * radius
|
|
|
|
|
|
func _update_visual_pivot() -> void:
|
|
_visual_root.pivot_offset = size * 0.5
|
|
|
|
|
|
func _refresh_style() -> void:
|
|
var idle := StyleBoxEmpty.new()
|
|
var normal := _make_quality_style(_quality_color, 2, 0.25)
|
|
var hover := _make_quality_style(
|
|
_quality_color.lightened(0.08), 4, 0.34
|
|
)
|
|
var selected_fill: Color = (
|
|
_quality_color.lightened(0.12)
|
|
if _batch_selected
|
|
else _quality_color
|
|
)
|
|
var selected := _make_quality_style(
|
|
selected_fill,
|
|
6 if _batch_selected else 4,
|
|
0.46 if _batch_selected else 0.34,
|
|
)
|
|
var circle_visible: bool = (
|
|
_batch_selected
|
|
or _hovered
|
|
or has_focus()
|
|
)
|
|
var base_style: StyleBox = idle
|
|
if circle_visible:
|
|
base_style = (
|
|
selected
|
|
if _batch_selected or _focused_catch
|
|
else normal
|
|
)
|
|
add_theme_stylebox_override(
|
|
"normal",
|
|
base_style,
|
|
)
|
|
add_theme_stylebox_override("hover", selected if _batch_selected else hover)
|
|
add_theme_stylebox_override("focus", selected)
|
|
add_theme_stylebox_override("pressed", selected)
|
|
|
|
|
|
func _make_quality_style(
|
|
fill: Color,
|
|
shadow_size: int,
|
|
shadow_alpha: float,
|
|
) -> StyleBoxFlat:
|
|
var style := StyleBoxFlat.new()
|
|
style.bg_color = fill
|
|
style.set_border_width_all(0)
|
|
style.set_corner_radius_all(128)
|
|
style.shadow_color = Color(0.01, 0.045, 0.06, shadow_alpha)
|
|
style.shadow_size = shadow_size
|
|
style.shadow_offset = Vector2(0.0, 2.0)
|
|
return style
|