feat: implement InventoryBackpack FSM and InventoryOverlay
- InventoryBackpack: Control-based FSM with IDLE/OPEN/SELECTED/ACQUIRE/REMOVE states, Tween-based animations, guard condition checks, signal connections to InventoryManager for item_acquired/item_removed reactions - InventoryOverlay: Full-screen overlay with fade-in/out, item grid via GridContainer, drag-and-drop item selection, combination via drag-to-slot, hover labels, right-click inspect - InventorySlot: Individual slot with colored box placeholder, hover highlight, click/right-click/hover signals
This commit is contained in:
233
inventory/inventory_backpack/InventoryBackpack.gd
Normal file
233
inventory/inventory_backpack/InventoryBackpack.gd
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
extends Control
|
||||||
|
class_name InventoryBackpack
|
||||||
|
|
||||||
|
signal overlay_show_requested
|
||||||
|
signal overlay_hide_requested
|
||||||
|
signal item_selected(item_id: String)
|
||||||
|
signal returning_to_idle
|
||||||
|
signal skip_action_requested
|
||||||
|
|
||||||
|
enum State { IDLE, OPEN, SELECTED, ACQUIRE, REMOVE }
|
||||||
|
|
||||||
|
var _state: State = State.IDLE
|
||||||
|
var _animating: bool = false
|
||||||
|
var _active_tween: Tween = null
|
||||||
|
var _floating_item_color: Color = Color(1, 1, 1, 0)
|
||||||
|
|
||||||
|
@onready var backpack_icon: ColorRect = $BackpackIcon
|
||||||
|
@onready var floating_item: ColorRect = $FloatingItem
|
||||||
|
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
floating_item.modulate = Color(1, 1, 1, 0)
|
||||||
|
floating_item.visible = false
|
||||||
|
InventoryManager.item_acquired.connect(_on_item_acquired)
|
||||||
|
InventoryManager.item_removed.connect(_on_item_removed)
|
||||||
|
InventoryManager.inventory_changed.connect(_on_inventory_changed)
|
||||||
|
_update_floating_item()
|
||||||
|
|
||||||
|
func get_state() -> State:
|
||||||
|
return _state
|
||||||
|
|
||||||
|
func is_busy() -> bool:
|
||||||
|
return _animating
|
||||||
|
|
||||||
|
func _update_floating_item() -> void:
|
||||||
|
if InventoryManager.selected_item:
|
||||||
|
var def = InventoryManager.get_item_definition(InventoryManager.selected_item)
|
||||||
|
if def:
|
||||||
|
floating_item.visible = true
|
||||||
|
floating_item.modulate = Color(1, 0.6, 0.2, 1)
|
||||||
|
else:
|
||||||
|
floating_item.visible = true
|
||||||
|
floating_item.modulate = Color(0.8, 0.8, 0.8, 1)
|
||||||
|
else:
|
||||||
|
floating_item.visible = false
|
||||||
|
|
||||||
|
func transition_to(new_state: State) -> void:
|
||||||
|
if _animating and new_state != _state:
|
||||||
|
_kill_tween()
|
||||||
|
match new_state:
|
||||||
|
State.IDLE:
|
||||||
|
_transition_to_idle()
|
||||||
|
State.OPEN:
|
||||||
|
_transition_to_open()
|
||||||
|
State.SELECTED:
|
||||||
|
_transition_to_selected()
|
||||||
|
State.ACQUIRE:
|
||||||
|
_transition_to_acquire()
|
||||||
|
State.REMOVE:
|
||||||
|
_transition_to_remove()
|
||||||
|
|
||||||
|
func _transition_to_idle() -> void:
|
||||||
|
if _state == State.IDLE:
|
||||||
|
return
|
||||||
|
_set_state(State.IDLE)
|
||||||
|
overlay_hide_requested.emit()
|
||||||
|
backpack_icon.modulate = Color(1, 1, 1, 1)
|
||||||
|
floating_item.visible = false
|
||||||
|
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_active_tween = tween
|
||||||
|
_animating = true
|
||||||
|
tween.tween_property(backpack_icon, "rotation", 0.0, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_property(backpack_icon, "position", backpack_icon.position, 0.35).set_trans(Tween.TRANS_SINE_IN)
|
||||||
|
tween.tween_callback(_on_transition_complete).bind(State.IDLE)
|
||||||
|
|
||||||
|
func _transition_to_open() -> void:
|
||||||
|
var can_open = _check_guards()
|
||||||
|
if not can_open:
|
||||||
|
if _state == State.IDLE:
|
||||||
|
skip_action_requested.emit()
|
||||||
|
return
|
||||||
|
|
||||||
|
_set_state(State.OPEN)
|
||||||
|
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_active_tween = tween
|
||||||
|
_animating = true
|
||||||
|
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_property(backpack_icon, "position", Vector2(backpack_icon.position.x + 20, backpack_icon.position.y + 20), 0.35).set_trans(Tween.TRANS_SINE_IN)
|
||||||
|
tween.tween_callback(_on_transition_complete).bind(State.OPEN)
|
||||||
|
tween.tween_callback(overlay_show_requested.emit)
|
||||||
|
|
||||||
|
func _transition_to_selected() -> void:
|
||||||
|
if _state == State.SELECTED:
|
||||||
|
return
|
||||||
|
|
||||||
|
_set_state(State.SELECTED)
|
||||||
|
_update_floating_item()
|
||||||
|
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_active_tween = tween
|
||||||
|
_animating = true
|
||||||
|
|
||||||
|
floating_item.visible = true
|
||||||
|
floating_item.modulate = Color(1, 1, 1, 0)
|
||||||
|
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_callback(_on_transition_complete).bind(State.SELECTED)
|
||||||
|
|
||||||
|
func _transition_to_acquire() -> void:
|
||||||
|
if _state == State.ACQUIRE or _state == State.REMOVE:
|
||||||
|
_kill_tween()
|
||||||
|
|
||||||
|
_set_state(State.ACQUIRE)
|
||||||
|
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_active_tween = tween
|
||||||
|
_animating = true
|
||||||
|
|
||||||
|
backpack_icon.modulate = Color(1, 1, 1, 1)
|
||||||
|
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_callback(_start_acquire_item_anim)
|
||||||
|
|
||||||
|
func _start_acquire_item_anim() -> void:
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_active_tween = tween
|
||||||
|
|
||||||
|
floating_item.visible = true
|
||||||
|
floating_item.modulate = Color(1, 1, 1, 0)
|
||||||
|
floating_item.position = Vector2(backpack_icon.position.x - 20, backpack_icon.position.y - 40)
|
||||||
|
|
||||||
|
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_property(floating_item, "position", backpack_icon.position, 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_callback(_on_acquire_complete)
|
||||||
|
|
||||||
|
func _on_acquire_complete() -> void:
|
||||||
|
floating_item.visible = false
|
||||||
|
transition_to(State.IDLE)
|
||||||
|
|
||||||
|
func _transition_to_remove() -> void:
|
||||||
|
if _state == State.ACQUIRE or _state == State.REMOVE:
|
||||||
|
_kill_tween()
|
||||||
|
|
||||||
|
_set_state(State.REMOVE)
|
||||||
|
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_active_tween = tween
|
||||||
|
_animating = true
|
||||||
|
|
||||||
|
backpack_icon.modulate = Color(1, 1, 1, 1)
|
||||||
|
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_callback(_start_remove_item_anim)
|
||||||
|
|
||||||
|
func _start_remove_item_anim() -> void:
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_active_tween = tween
|
||||||
|
|
||||||
|
floating_item.visible = true
|
||||||
|
floating_item.modulate = Color(1, 1, 1, 1)
|
||||||
|
floating_item.position = backpack_icon.position
|
||||||
|
|
||||||
|
tween.tween_property(floating_item, "position", Vector2(backpack_icon.position.x - 20, backpack_icon.position.y - 80), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.parallel().tween_property(floating_item, "modulate", Color(1, 1, 1, 0), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
tween.tween_callback(_on_remove_complete)
|
||||||
|
|
||||||
|
func _on_remove_complete() -> void:
|
||||||
|
floating_item.visible = false
|
||||||
|
var was_selected = InventoryManager.selected_item != ""
|
||||||
|
transition_to(State.IDLE)
|
||||||
|
if was_selected:
|
||||||
|
InventoryManager.clear_selection()
|
||||||
|
|
||||||
|
func _set_state(new_state: State) -> void:
|
||||||
|
_state = new_state
|
||||||
|
|
||||||
|
func _check_guards() -> bool:
|
||||||
|
var main_game = get_node_or_null("/root/Node2D")
|
||||||
|
if not main_game:
|
||||||
|
return true
|
||||||
|
|
||||||
|
if main_game.is_script_running:
|
||||||
|
return false
|
||||||
|
|
||||||
|
var fade = get_node_or_null("/root/Node2D/SceneDisplay/Fade")
|
||||||
|
if fade and fade.modulate.a > 0.5:
|
||||||
|
return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
func _kill_tween() -> void:
|
||||||
|
if _active_tween:
|
||||||
|
_active_tween.kill()
|
||||||
|
_active_tween = null
|
||||||
|
_animating = false
|
||||||
|
|
||||||
|
func _on_transition_complete(completed_state: State) -> void:
|
||||||
|
_animating = false
|
||||||
|
_active_tween = null
|
||||||
|
if completed_state == State.OPEN:
|
||||||
|
pass
|
||||||
|
elif completed_state == State.IDLE:
|
||||||
|
returning_to_idle.emit()
|
||||||
|
|
||||||
|
func _on_item_acquired(item_id: String) -> void:
|
||||||
|
if _state == State.IDLE:
|
||||||
|
transition_to(State.ACQUIRE)
|
||||||
|
|
||||||
|
func _on_item_removed(item_id: String) -> void:
|
||||||
|
if _state == State.IDLE:
|
||||||
|
if InventoryManager.selected_item == item_id:
|
||||||
|
InventoryManager.clear_selection()
|
||||||
|
_update_floating_item()
|
||||||
|
transition_to(State.REMOVE)
|
||||||
|
else:
|
||||||
|
transition_to(State.REMOVE)
|
||||||
|
elif _state == State.SELECTED and InventoryManager.selected_item == item_id:
|
||||||
|
InventoryManager.clear_selection()
|
||||||
|
_update_floating_item()
|
||||||
|
transition_to(State.REMOVE)
|
||||||
|
|
||||||
|
func _on_inventory_changed() -> void:
|
||||||
|
_update_floating_item()
|
||||||
|
|
||||||
|
func _gui_input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
|
||||||
|
if _state == State.IDLE:
|
||||||
|
transition_to(State.OPEN)
|
||||||
|
elif _state == State.OPEN:
|
||||||
|
transition_to(State.IDLE)
|
||||||
|
|
||||||
|
func _notification(what: int) -> void:
|
||||||
|
if what == NOTIFICATION_PREDELETE:
|
||||||
|
_kill_tween()
|
||||||
1
inventory/inventory_backpack/InventoryBackpack.gd.uid
Normal file
1
inventory/inventory_backpack/InventoryBackpack.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://2x3g0ethsdcgo
|
||||||
31
inventory/inventory_backpack/InventoryBackpack.tscn
Normal file
31
inventory/inventory_backpack/InventoryBackpack.tscn
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
[gd_scene format=3 uid="uid://1406xmcnkygw0"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://2x3g0ethsdcgo" path="res://inventory/inventory_backpack/InventoryBackpack.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="InventoryBackpack" type="Control" unique_id=1000000001]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 2
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_top = 10.0
|
||||||
|
offset_right = -10.0
|
||||||
|
offset_bottom = 70.0
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
[node name="BackpackIcon" type="ColorRect" parent="." unique_id=1000000002]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 0.0
|
||||||
|
offset_top = 0.0
|
||||||
|
offset_right = 60.0
|
||||||
|
offset_bottom = 60.0
|
||||||
|
color = Color(0.4, 0.6, 0.9, 1)
|
||||||
|
|
||||||
|
[node name="FloatingItem" type="ColorRect" parent="." unique_id=1000000003]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 20.0
|
||||||
|
offset_top = -30.0
|
||||||
|
offset_right = 50.0
|
||||||
|
offset_bottom = 0.0
|
||||||
|
color = Color(1, 0.6, 0.2, 1)
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1000000004]
|
||||||
1
inventory/inventory_backpack/InventoryBackpack.tscn.uid
Normal file
1
inventory/inventory_backpack/InventoryBackpack.tscn.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://1406xmcnkygw0
|
||||||
215
inventory/inventory_overlay/InventoryOverlay.gd
Normal file
215
inventory/inventory_overlay/InventoryOverlay.gd
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
extends Control
|
||||||
|
class_name InventoryOverlay
|
||||||
|
|
||||||
|
signal close_requested
|
||||||
|
signal item_confirmed(item_id: String)
|
||||||
|
signal combine_requested(item_a_id: String, item_b_id: String)
|
||||||
|
signal inspect_requested(item_id: String)
|
||||||
|
|
||||||
|
var input_active: bool = false
|
||||||
|
var _is_visible: bool = false
|
||||||
|
var _selected_slot: InventorySlot = null
|
||||||
|
var _drag_start_time: float = 0.0
|
||||||
|
var _is_dragging: bool = false
|
||||||
|
var _dragged_item: Control = null
|
||||||
|
var _hovered_slot: InventorySlot = null
|
||||||
|
var _fade_tween: Tween = null
|
||||||
|
|
||||||
|
const FADE_DURATION: float = 0.2
|
||||||
|
const LONG_PRESS_THRESHOLD: float = 0.5
|
||||||
|
const SLOTS_PER_ROW: int = 8
|
||||||
|
const SLOT_SIZE: Vector2i = Vector2i(64, 64)
|
||||||
|
|
||||||
|
@onready var background: ColorRect = $Background
|
||||||
|
@onready var panel: Control = $InventoryPanel
|
||||||
|
@onready var frame: ColorRect = $InventoryPanel/Frame
|
||||||
|
@onready var grid: GridContainer = $InventoryPanel/ItemGrid
|
||||||
|
@onready var hover_label: Label = $InventoryPanel/HoverLabel
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
hide()
|
||||||
|
background.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||||
|
InventoryManager.inventory_changed.connect(_refresh_grid)
|
||||||
|
InventoryManager.combination_attempted.connect(_on_combination_attempted)
|
||||||
|
|
||||||
|
func show_overlay() -> void:
|
||||||
|
if _fade_tween:
|
||||||
|
_fade_tween.kill()
|
||||||
|
_fade_tween = null
|
||||||
|
|
||||||
|
_is_visible = true
|
||||||
|
show()
|
||||||
|
modulate = Color(1, 1, 1, 0)
|
||||||
|
input_active = false
|
||||||
|
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_fade_tween = tween
|
||||||
|
tween.tween_property(self, "modulate", Color(1, 1, 1, 1), FADE_DURATION)
|
||||||
|
tween.tween_callback(_on_fade_in_complete)
|
||||||
|
|
||||||
|
func hide_overlay() -> void:
|
||||||
|
if _fade_tween:
|
||||||
|
_fade_tween.kill()
|
||||||
|
_fade_tween = null
|
||||||
|
|
||||||
|
input_active = false
|
||||||
|
_clear_selection()
|
||||||
|
|
||||||
|
var tween = create_tween().bind_node(self)
|
||||||
|
_fade_tween = tween
|
||||||
|
tween.tween_property(self, "modulate", Color(1, 1, 1, 0), FADE_DURATION)
|
||||||
|
tween.tween_callback(_on_fade_out_complete)
|
||||||
|
|
||||||
|
func _on_fade_in_complete() -> void:
|
||||||
|
input_active = true
|
||||||
|
|
||||||
|
func _on_fade_out_complete() -> void:
|
||||||
|
_is_visible = false
|
||||||
|
hide()
|
||||||
|
input_active = false
|
||||||
|
|
||||||
|
func is_active() -> bool:
|
||||||
|
return _is_visible and input_active
|
||||||
|
|
||||||
|
func _refresh_grid() -> void:
|
||||||
|
for child in grid.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
for item_id in InventoryManager.inventory:
|
||||||
|
var def = InventoryManager.get_item_definition(item_id)
|
||||||
|
if not def:
|
||||||
|
def = ItemDefinition.new()
|
||||||
|
def.id = item_id
|
||||||
|
def.name = item_id
|
||||||
|
|
||||||
|
var slot_scene = load("res://inventory/inventory_overlay/InventorySlot.tscn")
|
||||||
|
var slot: InventorySlot = slot_scene.instantiate()
|
||||||
|
slot.set_item(def)
|
||||||
|
slot.clicked.connect(_on_slot_clicked)
|
||||||
|
slot.right_clicked.connect(_on_slot_right_clicked)
|
||||||
|
slot.hovered.connect(_on_slot_hovered)
|
||||||
|
slot.unhovered.connect(_on_slot_unhovered)
|
||||||
|
grid.add_child(slot)
|
||||||
|
|
||||||
|
grid.columns = SLOTS_PER_ROW
|
||||||
|
|
||||||
|
func _on_slot_clicked(item_id: String) -> void:
|
||||||
|
if not input_active:
|
||||||
|
return
|
||||||
|
|
||||||
|
for child in grid.get_children():
|
||||||
|
if child is InventorySlot and child.item_id == item_id:
|
||||||
|
if _selected_slot == null:
|
||||||
|
_selected_slot = child
|
||||||
|
_drag_start_time = Time.get_ticks_msec() / 1000.0
|
||||||
|
_is_dragging = true
|
||||||
|
_create_drag_preview(child)
|
||||||
|
elif _selected_slot.item_id == item_id:
|
||||||
|
_handle_release_same_item()
|
||||||
|
else:
|
||||||
|
combine_requested.emit(_selected_slot.item_id, item_id)
|
||||||
|
_clear_selection()
|
||||||
|
break
|
||||||
|
|
||||||
|
func _on_slot_right_clicked(item_id: String) -> void:
|
||||||
|
if not input_active:
|
||||||
|
return
|
||||||
|
inspect_requested.emit(item_id)
|
||||||
|
hide_overlay()
|
||||||
|
|
||||||
|
func _on_slot_hovered(item_id: String) -> void:
|
||||||
|
if not input_active:
|
||||||
|
return
|
||||||
|
_hovered_slot = null
|
||||||
|
for child in grid.get_children():
|
||||||
|
if child is InventorySlot and child.item_id == item_id:
|
||||||
|
_hovered_slot = child
|
||||||
|
break
|
||||||
|
_update_hover_label()
|
||||||
|
|
||||||
|
func _on_slot_unhovered(item_id: String) -> void:
|
||||||
|
if _hovered_slot and _hovered_slot.item_id == item_id:
|
||||||
|
_hovered_slot = null
|
||||||
|
_update_hover_label()
|
||||||
|
|
||||||
|
func _create_drag_preview(slot: InventorySlot) -> void:
|
||||||
|
var preview = ColorRect.new()
|
||||||
|
preview.color = Color(1, 0.6, 0.2, 0.7)
|
||||||
|
preview.size = Vector2(48, 48)
|
||||||
|
preview.position = slot.global_position - global_position
|
||||||
|
panel.add_child(preview)
|
||||||
|
_dragged_item = preview
|
||||||
|
|
||||||
|
func _handle_release_same_item() -> void:
|
||||||
|
var elapsed = Time.get_ticks_msec() / 1000.0 - _drag_start_time
|
||||||
|
if elapsed <= LONG_PRESS_THRESHOLD:
|
||||||
|
item_confirmed.emit(_selected_slot.item_id)
|
||||||
|
hide_overlay()
|
||||||
|
else:
|
||||||
|
_clear_selection()
|
||||||
|
|
||||||
|
func _clear_selection() -> void:
|
||||||
|
_selected_slot = null
|
||||||
|
_is_dragging = false
|
||||||
|
if _dragged_item:
|
||||||
|
_dragged_item.queue_free()
|
||||||
|
_dragged_item = null
|
||||||
|
_update_hover_label()
|
||||||
|
|
||||||
|
func _update_hover_label() -> void:
|
||||||
|
if _selected_slot and _hovered_slot and _selected_slot.item_id != _hovered_slot.item_id:
|
||||||
|
var def_a = InventoryManager.get_item_definition(_selected_slot.item_id)
|
||||||
|
var def_b = InventoryManager.get_item_definition(_hovered_slot.item_id)
|
||||||
|
var name_a = _selected_slot.item_id
|
||||||
|
var name_b = _hovered_slot.item_id
|
||||||
|
if def_a:
|
||||||
|
name_a = def_a.name
|
||||||
|
if def_b:
|
||||||
|
name_b = def_b.name
|
||||||
|
hover_label.text = "Use %s with %s" % [name_a, name_b]
|
||||||
|
elif _hovered_slot:
|
||||||
|
var def = InventoryManager.get_item_definition(_hovered_slot.item_id)
|
||||||
|
if def:
|
||||||
|
hover_label.text = def.name
|
||||||
|
else:
|
||||||
|
hover_label.text = _hovered_slot.item_id
|
||||||
|
else:
|
||||||
|
hover_label.text = ""
|
||||||
|
|
||||||
|
func _gui_input(event: InputEvent) -> void:
|
||||||
|
if not _is_visible:
|
||||||
|
return
|
||||||
|
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
if event.button_index == 1 and event.pressed:
|
||||||
|
if not _is_dragging:
|
||||||
|
pass
|
||||||
|
elif event.button_index == 1 and not event.pressed:
|
||||||
|
if _is_dragging:
|
||||||
|
if _hovered_slot == null:
|
||||||
|
_clear_selection()
|
||||||
|
hide_overlay()
|
||||||
|
close_requested.emit()
|
||||||
|
elif _hovered_slot == _selected_slot:
|
||||||
|
_handle_release_same_item()
|
||||||
|
else:
|
||||||
|
combine_requested.emit(_selected_slot.item_id, _hovered_slot.item_id)
|
||||||
|
_clear_selection()
|
||||||
|
return
|
||||||
|
|
||||||
|
if event is InputEventMouseMotion and _is_dragging and _dragged_item:
|
||||||
|
_dragged_item.position = get_local_mouse_position() - Vector2(24, 24)
|
||||||
|
var panel_rect = panel.get_global_rect()
|
||||||
|
if not panel_rect.has_point(get_global_mouse_position()):
|
||||||
|
_clear_selection()
|
||||||
|
hide_overlay()
|
||||||
|
close_requested.emit()
|
||||||
|
|
||||||
|
func _on_combination_attempted(item_a_id: String, item_b_id: String) -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func _notification(what: int) -> void:
|
||||||
|
if what == NOTIFICATION_PREDELETE:
|
||||||
|
if _fade_tween:
|
||||||
|
_fade_tween.kill()
|
||||||
|
_fade_tween = null
|
||||||
1
inventory/inventory_overlay/InventoryOverlay.gd.uid
Normal file
1
inventory/inventory_overlay/InventoryOverlay.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://3mkdj9s1oe1jz
|
||||||
63
inventory/inventory_overlay/InventoryOverlay.tscn
Normal file
63
inventory/inventory_overlay/InventoryOverlay.tscn
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
[gd_scene format=3 uid="uid://1p46uzngsih9o"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://3mkdj9s1oe1jz" path="res://inventory/inventory_overlay/InventoryOverlay.gd" id="1"]
|
||||||
|
|
||||||
|
[sub_resource type="LabelSettings" id="LabelSettings_inv"]
|
||||||
|
font_size = 20
|
||||||
|
outline_size = 3
|
||||||
|
outline_color = Color(0, 0, 0, 1)
|
||||||
|
|
||||||
|
[node name="InventoryOverlay" type="Control" unique_id=3000000001]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
[node name="Background" type="ColorRect" parent="." unique_id=3000000002]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
color = Color(0, 0, 0, 0.7)
|
||||||
|
|
||||||
|
[node name="InventoryPanel" type="Control" parent="." unique_id=3000000003]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 7
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -350.0
|
||||||
|
offset_top = -150.0
|
||||||
|
offset_right = 350.0
|
||||||
|
offset_bottom = 150.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="Frame" type="ColorRect" parent="InventoryPanel" unique_id=3000000004]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
color = Color(0.15, 0.15, 0.2, 1)
|
||||||
|
|
||||||
|
[node name="ItemGrid" type="GridContainer" parent="InventoryPanel" unique_id=3000000005]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 0
|
||||||
|
offset_left = 10.0
|
||||||
|
offset_top = 10.0
|
||||||
|
offset_right = -10.0
|
||||||
|
offset_bottom = -50.0
|
||||||
|
|
||||||
|
[node name="HoverLabel" type="Label" parent="InventoryPanel" unique_id=3000000006]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_bottom = -10.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
horizontal_alignment = 1
|
||||||
|
label_settings = SubResource("LabelSettings_inv")
|
||||||
1
inventory/inventory_overlay/InventoryOverlay.tscn.uid
Normal file
1
inventory/inventory_overlay/InventoryOverlay.tscn.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://1p46uzngsih9o
|
||||||
55
inventory/inventory_overlay/InventorySlot.gd
Normal file
55
inventory/inventory_overlay/InventorySlot.gd
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
extends Control
|
||||||
|
class_name InventorySlot
|
||||||
|
|
||||||
|
signal clicked(item_id: String)
|
||||||
|
signal right_clicked(item_id: String)
|
||||||
|
signal hovered(item_id: String)
|
||||||
|
signal unhovered(item_id: String)
|
||||||
|
|
||||||
|
var item_id: String = ""
|
||||||
|
var is_hovered: bool = false
|
||||||
|
|
||||||
|
@onready var item_box: ColorRect = $ItemBox
|
||||||
|
@onready var hover_highlight: ColorRect = $HoverHighlight
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
hover_highlight.visible = false
|
||||||
|
|
||||||
|
func set_item(item_def: ItemDefinition) -> void:
|
||||||
|
item_id = item_def.id
|
||||||
|
item_box.color = Color(1, 0.6, 0.2, 1)
|
||||||
|
|
||||||
|
func set_item_color(color: Color) -> void:
|
||||||
|
item_box.color = color
|
||||||
|
|
||||||
|
func set_hover(hovered: bool) -> void:
|
||||||
|
is_hovered = hovered
|
||||||
|
hover_highlight.visible = hovered
|
||||||
|
if hovered:
|
||||||
|
item_box.color = item_box.color.lightened(0.2)
|
||||||
|
else:
|
||||||
|
var def = InventoryManager.get_item_definition(item_id)
|
||||||
|
if def:
|
||||||
|
item_box.color = Color(1, 0.6, 0.2, 1)
|
||||||
|
else:
|
||||||
|
item_box.color = Color(0.8, 0.8, 0.8, 1)
|
||||||
|
|
||||||
|
func _gui_input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventMouseButton:
|
||||||
|
if event.button_index == 1 and event.pressed:
|
||||||
|
clicked.emit(item_id)
|
||||||
|
elif event.button_index == 2:
|
||||||
|
right_clicked.emit(item_id)
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
var rect = get_global_rect()
|
||||||
|
var mouse_pos = get_global_mouse_position()
|
||||||
|
var was_hovered = is_hovered
|
||||||
|
is_hovered = rect.has_point(mouse_pos)
|
||||||
|
if is_hovered != was_hovered:
|
||||||
|
set_hover(is_hovered)
|
||||||
|
if is_hovered:
|
||||||
|
hovered.emit(item_id)
|
||||||
|
else:
|
||||||
|
unhovered.emit(item_id)
|
||||||
1
inventory/inventory_overlay/InventorySlot.gd.uid
Normal file
1
inventory/inventory_overlay/InventorySlot.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://oegm753jbl9m
|
||||||
26
inventory/inventory_overlay/InventorySlot.tscn
Normal file
26
inventory/inventory_overlay/InventorySlot.tscn
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
[gd_scene format=3 uid="uid://1esl88fgtd2p6"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://oegm753jbl9m" path="res://inventory/inventory_overlay/InventorySlot.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="InventorySlot" type="Control" unique_id=2000000001]
|
||||||
|
custom_minimum_size = Vector2i(64, 64)
|
||||||
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
[node name="ItemBox" type="ColorRect" parent="." unique_id=2000000002]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.062
|
||||||
|
anchor_top = 0.062
|
||||||
|
anchor_right = 0.938
|
||||||
|
anchor_bottom = 0.938
|
||||||
|
color = Color(1, 0.6, 0.2, 1)
|
||||||
|
|
||||||
|
[node name="HoverHighlight" type="ColorRect" parent="." unique_id=2000000003]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
color = Color(1, 1, 1, 0.3)
|
||||||
|
visible = false
|
||||||
1
inventory/inventory_overlay/InventorySlot.tscn.uid
Normal file
1
inventory/inventory_overlay/InventorySlot.tscn.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://1esl88fgtd2p6
|
||||||
Reference in New Issue
Block a user