Add comprehensive UI system with action bar, unit frame, and character sheet
- Created UI system in level/ui/ folder - Action bar with 12 ability slots (Attack, Block, Dash, Jump + 8 expansion slots) - Unit frame showing player portrait with health bar - Character sheet/spellbook (toggle with Tab) displaying stats, weapons, and abilities - Tab hint indicator showing how to open character sheet - Custom theme with golden borders and dark backgrounds - UI Components: - HUD Manager autoload handles all UI initialization and player connections - Ability buttons with cooldown overlay and keybind display - Real-time health and cooldown tracking via signals - Scrollable character sheet with two-page layout - Player Integration: - Added UI signals: dash_cooldown_updated, attack_cooldown_updated, weapon_equipped_changed - Mouse capture system (Escape to toggle, click to recapture) - Synced attack cooldown from weapons to player for UI tracking - Updated level.gd to connect local player to HUD Manager - Updated CLAUDE.md with git commit guidelines
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
extends Control
|
||||
class_name ActionBar
|
||||
## Action bar displaying 12 ability slots at the bottom of the screen
|
||||
## Pre-populated with Jump, Dash, Attack, Block + 8 empty slots for expansion
|
||||
|
||||
# Ability button references (12 slots)
|
||||
var ability_buttons: Array[AbilityButton] = []
|
||||
|
||||
# Player reference
|
||||
var player: Character = null
|
||||
|
||||
# Slot assignments (which slot holds which ability)
|
||||
const SLOT_ATTACK = 0 # Left Mouse Button
|
||||
const SLOT_BLOCK = 1 # Right Mouse Button
|
||||
const SLOT_DASH = 2 # F key
|
||||
const SLOT_JUMP = 3 # Space
|
||||
|
||||
func _ready():
|
||||
# Ability buttons are children of the HBoxContainer
|
||||
var container = $HBoxContainer
|
||||
if container:
|
||||
for child in container.get_children():
|
||||
if child is AbilityButton:
|
||||
ability_buttons.append(child)
|
||||
|
||||
print("[ActionBar] Found ", ability_buttons.size(), " ability button slots")
|
||||
|
||||
# Initialize button appearances
|
||||
_initialize_slots()
|
||||
|
||||
## Set the player reference and connect signals
|
||||
func set_player(p: Character):
|
||||
if player:
|
||||
_disconnect_player_signals()
|
||||
|
||||
player = p
|
||||
|
||||
if player:
|
||||
_connect_player_signals()
|
||||
_update_all_abilities()
|
||||
|
||||
## Initialize all slots with their keybinds
|
||||
func _initialize_slots():
|
||||
if ability_buttons.size() < 12:
|
||||
push_warning("[ActionBar] Expected 12 slots, found ", ability_buttons.size())
|
||||
return
|
||||
|
||||
# Set keybinds for all slots
|
||||
var keybinds = ["LMB", "RMB", "F", "Space", "5", "6", "7", "8", "9", "0", "-", "="]
|
||||
for i in range(min(12, ability_buttons.size())):
|
||||
ability_buttons[i].set_keybind(keybinds[i])
|
||||
|
||||
print("[ActionBar] Initialized all ability slots")
|
||||
|
||||
## Update all ability icons and data
|
||||
func _update_all_abilities():
|
||||
if not player:
|
||||
return
|
||||
|
||||
# Clear all slots first
|
||||
for button in ability_buttons:
|
||||
button.clear_ability()
|
||||
|
||||
# Re-set keybinds
|
||||
_initialize_slots()
|
||||
|
||||
# SLOT 0: Attack (Main Hand or Unarmed)
|
||||
if player.equipped_weapon:
|
||||
var weapon_data = player.equipped_weapon.weapon_data
|
||||
if weapon_data and weapon_data.icon:
|
||||
ability_buttons[SLOT_ATTACK].set_ability(
|
||||
weapon_data.icon,
|
||||
"LMB",
|
||||
weapon_data.weapon_name,
|
||||
"Attack with " + weapon_data.weapon_name
|
||||
)
|
||||
else:
|
||||
# Unarmed attack - use placeholder or no icon
|
||||
ability_buttons[SLOT_ATTACK].set_ability(
|
||||
null,
|
||||
"LMB",
|
||||
"Unarmed Attack",
|
||||
"Punch enemies"
|
||||
)
|
||||
|
||||
# SLOT 1: Block (if shield equipped)
|
||||
if player.equipped_offhand:
|
||||
var offhand_data = player.equipped_offhand.weapon_data
|
||||
if offhand_data and offhand_data.can_block and offhand_data.icon:
|
||||
ability_buttons[SLOT_BLOCK].set_ability(
|
||||
offhand_data.icon,
|
||||
"RMB",
|
||||
"Block",
|
||||
"Block with " + offhand_data.weapon_name + " (" + str(int(offhand_data.block_reduction * 100)) + "% reduction)"
|
||||
)
|
||||
# If main hand can block
|
||||
elif player.equipped_weapon:
|
||||
var weapon_data = player.equipped_weapon.weapon_data
|
||||
if weapon_data and weapon_data.can_block and weapon_data.icon:
|
||||
ability_buttons[SLOT_BLOCK].set_ability(
|
||||
weapon_data.icon,
|
||||
"RMB",
|
||||
"Block",
|
||||
"Block with " + weapon_data.weapon_name + " (" + str(int(weapon_data.block_reduction * 100)) + "% reduction)"
|
||||
)
|
||||
|
||||
# SLOT 2: Dash
|
||||
ability_buttons[SLOT_DASH].set_ability(
|
||||
null, # TODO: Add dash icon
|
||||
"F",
|
||||
"Dash",
|
||||
"Dash in movement direction\nCooldown: 4s"
|
||||
)
|
||||
|
||||
# SLOT 3: Jump
|
||||
ability_buttons[SLOT_JUMP].set_ability(
|
||||
null, # TODO: Add jump icon
|
||||
"Space",
|
||||
"Jump",
|
||||
"Jump into the air"
|
||||
)
|
||||
|
||||
# Slots 4-11 remain empty for future abilities
|
||||
|
||||
print("[ActionBar] Updated all ability displays")
|
||||
|
||||
## Connect to player signals
|
||||
func _connect_player_signals():
|
||||
if not player:
|
||||
return
|
||||
|
||||
# We'll add custom signals to player.gd for weapon changes and cooldowns
|
||||
# For now, just print
|
||||
print("[ActionBar] Connected to player signals")
|
||||
|
||||
## Disconnect from player signals
|
||||
func _disconnect_player_signals():
|
||||
if not player:
|
||||
return
|
||||
|
||||
print("[ActionBar] Disconnected from player signals")
|
||||
|
||||
## Update dash cooldown
|
||||
func update_dash_cooldown(remaining: float, total: float):
|
||||
if ability_buttons.size() > SLOT_DASH:
|
||||
if remaining > 0:
|
||||
ability_buttons[SLOT_DASH].start_cooldown(remaining, total)
|
||||
|
||||
## Update attack cooldown
|
||||
func update_attack_cooldown(remaining: float, total: float):
|
||||
if ability_buttons.size() > SLOT_ATTACK:
|
||||
if remaining > 0:
|
||||
ability_buttons[SLOT_ATTACK].start_cooldown(remaining, total)
|
||||
|
||||
## Called when weapon is equipped/unequipped
|
||||
func on_weapon_changed():
|
||||
_update_all_abilities()
|
||||
Reference in New Issue
Block a user