uibutton 임시저장

This commit is contained in:
NTG 2025-08-20 20:15:49 +09:00
parent 4a18a239e8
commit 0dc138ea2f
4 changed files with 529 additions and 0 deletions

View File

@ -0,0 +1,390 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
namespace DDD
{
public enum ButtonState
{
Normal,
Highlighted,
Pressed,
Selected,
Disabled
}
public class UiButton : MonoBehaviour, IInteractableUi, IPointerEnterHandler, IPointerExitHandler,
IPointerDownHandler, IPointerUpHandler, ISelectHandler, IDeselectHandler, ISubmitHandler
{
[Header("Button Components")]
[SerializeField] private Button _button;
[SerializeField] private Selectable _selectable;
[Header("State Synchronization")]
[SerializeField] private bool _synchronizeStates = true;
[SerializeField] private bool _handleKeyboardInput = true;
[SerializeField] private bool _handleGamepadInput = true;
[Header("Visual Feedback")]
[SerializeField] private Animator _animator;
[SerializeField] private Image _targetGraphic;
[Header("Toggle Functionality")]
[SerializeField] private bool _useToggle = false;
// State tracking
private bool _isPressed;
private bool _isHighlighted;
private bool _isSelected;
private bool _wasSelectedByKeyboard;
private bool _isToggled = false;
// Events
public event Action OnClicked;
public event Action OnStateChanged;
// Animation parameter hashes (if using Animator)
private readonly int _normalHash = Animator.StringToHash("Normal");
private readonly int _highlightedHash = Animator.StringToHash("Highlighted");
private readonly int _pressedHash = Animator.StringToHash("Pressed");
private readonly int _selectedHash = Animator.StringToHash("Selected");
private readonly int _disabledHash = Animator.StringToHash("Disabled");
private void Awake()
{
InitializeComponents();
}
private void OnEnable()
{
if (_button != null)
{
_button.onClick.AddListener(HandleButtonClick);
}
UpdateVisualState();
}
private void OnDisable()
{
if (_button != null)
{
_button.onClick.RemoveListener(HandleButtonClick);
}
}
private void Update()
{
HandleInputUpdate();
}
private void InitializeComponents()
{
// Get Button component if not assigned
if (_button == null)
{
_button = GetComponent<Button>();
}
// Get Selectable component (Button inherits from Selectable)
if (_selectable == null)
{
_selectable = _button;
}
// Get target graphic from button if not assigned
if (_targetGraphic == null && _button != null)
{
_targetGraphic = _button.targetGraphic as Image;
}
// Get Animator if not assigned
if (_animator == null)
{
_animator = GetComponent<Animator>();
}
}
private void HandleInputUpdate()
{
if (!_handleKeyboardInput && !_handleGamepadInput) return;
if (_selectable == null || !_selectable.interactable) return;
// Handle keyboard/gamepad input when this button is selected
if (EventSystem.current != null && EventSystem.current.currentSelectedGameObject == gameObject)
{
//HandleSelectedInput();
}
}
private void HandleSelectedInput()
{
var keyboard = Keyboard.current;
var gamepad = Gamepad.current;
// Handle keyboard input
if (_handleKeyboardInput && keyboard != null)
{
if (keyboard.enterKey.wasPressedThisFrame || keyboard.spaceKey.wasPressedThisFrame)
{
HandleButtonClick();
}
}
// Handle gamepad input
if (_handleGamepadInput && gamepad != null)
{
if (gamepad.buttonSouth.wasPressedThisFrame) // A button on Xbox controller
{
HandleButtonClick();
}
}
}
private void HandleButtonClick()
{
if (_selectable != null && !_selectable.interactable) return;
if (_useToggle)
{
_isToggled = !_isToggled;
if (_isToggled)
{
// When toggled on, maintain pressed state and make non-interactable
_isPressed = true;
_selectable.interactable = false;
}
else
{
// When toggled off, restore normal behavior
_isPressed = false;
_selectable.interactable = true;
}
UpdateVisualState();
}
OnClicked?.Invoke();
}
private void UpdateVisualState()
{
if (!_synchronizeStates) return;
var currentState = GetCurrentState();
print(currentState);
ApplyVisualState(currentState);
OnStateChanged?.Invoke();
}
private ButtonState GetCurrentState()
{
if (_selectable == null || (!_selectable.interactable && !_isToggled))
return ButtonState.Disabled;
// Toggle mode: when toggled on, maintain pressed state even if not interactable
if (_useToggle && _isToggled)
return ButtonState.Pressed;
if (_isPressed)
return ButtonState.Pressed;
if (_isSelected)
return ButtonState.Selected;
if (_isHighlighted)
return ButtonState.Highlighted;
return ButtonState.Normal;
}
private void ApplyVisualState(ButtonState state)
{
// Apply animator state if available
if (_animator != null && _animator.runtimeAnimatorController != null)
{
ApplyAnimatorState(state);
}
// Apply color tint if using Button's color block
if (_button != null && _targetGraphic != null)
{
ApplyColorState(state);
}
}
private void ApplyAnimatorState(ButtonState state)
{
switch (state)
{
case ButtonState.Normal:
_animator.SetTrigger(_normalHash);
break;
case ButtonState.Highlighted:
_animator.SetTrigger(_highlightedHash);
break;
case ButtonState.Pressed:
_animator.SetTrigger(_pressedHash);
break;
case ButtonState.Selected:
_animator.SetTrigger(_selectedHash);
break;
case ButtonState.Disabled:
_animator.SetTrigger(_disabledHash);
break;
}
}
private void ApplyColorState(ButtonState state)
{
var colors = _button.colors;
Color targetColor;
switch (state)
{
case ButtonState.Normal:
targetColor = colors.normalColor;
break;
case ButtonState.Highlighted:
targetColor = colors.highlightedColor;
break;
case ButtonState.Pressed:
targetColor = colors.pressedColor;
break;
case ButtonState.Selected:
targetColor = colors.selectedColor;
break;
case ButtonState.Disabled:
targetColor = colors.disabledColor;
break;
default:
targetColor = colors.normalColor;
break;
}
_targetGraphic.color = targetColor;
}
// IInteractableUi implementation
public void OnInteract()
{
if (_selectable != null && _selectable.interactable)
{
// This method is called for programmatic interaction
HandleButtonClick();
}
}
// Pointer event handlers
public void OnPointerEnter(PointerEventData eventData)
{
_isHighlighted = true;
UpdateVisualState();
}
public void OnPointerExit(PointerEventData eventData)
{
_isHighlighted = false;
UpdateVisualState();
}
public void OnPointerDown(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
if (_isSelected)
{
_isPressed = true;
UpdateVisualState();
return;
}
_isSelected = true;
UpdateVisualState();
}
}
public void OnPointerUp(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
// Don't reset pressed state in toggle mode when toggled on
if (_isPressed && !(_useToggle && _isToggled))
{
_isPressed = false;
}
_isSelected = false;
UpdateVisualState();
}
}
// Selection event handlers (for keyboard/gamepad navigation)
public void OnSelect(BaseEventData eventData)
{
_isSelected = true;
UpdateVisualState();
}
public void OnDeselect(BaseEventData eventData)
{
_isSelected = false;
UpdateVisualState();
}
// Submit handler (for keyboard/gamepad activation)
public void OnSubmit(BaseEventData eventData)
{
HandleButtonClick();
}
// Public API
public bool IsInteractable => _selectable != null && _selectable.interactable;
public void SetInteractable(bool interactable)
{
if (_selectable != null)
{
_selectable.interactable = interactable;
UpdateVisualState();
}
}
public void ForceUpdateState()
{
UpdateVisualState();
}
// Toggle functionality API
public bool UseToggle
{
get => _useToggle;
set => _useToggle = value;
}
public bool IsToggled => _isToggled;
public void SetToggleState(bool toggled)
{
if (!_useToggle) return;
_isToggled = toggled;
if (_isToggled)
{
_isPressed = true;
if (_selectable != null)
_selectable.interactable = false;
}
else
{
_isPressed = false;
if (_selectable != null)
_selectable.interactable = true;
}
UpdateVisualState();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fb17a59bc188495b84cb323bb982f64b
timeCreated: 1755681745

View File

@ -0,0 +1,133 @@
using UnityEngine;
using UnityEngine.UI;
namespace DDD
{
/// <summary>
/// Simple test script to verify UiButton functionality.
/// Attach this to a GameObject with UiButton component to test.
/// </summary>
public class UiButtonTest : MonoBehaviour
{
[SerializeField] private UiButton _uiButton;
[SerializeField] private Text _statusText;
private int _clickCount = 0;
private void Start()
{
// Get UiButton if not assigned
if (_uiButton == null)
{
_uiButton = GetComponent<UiButton>();
}
if (_uiButton != null)
{
// Subscribe to events
_uiButton.OnClicked += HandleButtonClicked;
_uiButton.OnStateChanged += HandleStateChanged;
Debug.Log("[DEBUG_LOG] UiButton test initialized");
}
else
{
Debug.LogError("[DEBUG_LOG] UiButton component not found!");
}
UpdateStatusText();
}
private void OnDestroy()
{
if (_uiButton != null)
{
_uiButton.OnClicked -= HandleButtonClicked;
_uiButton.OnStateChanged -= HandleStateChanged;
}
}
private void HandleButtonClicked()
{
_clickCount++;
Debug.Log($"[DEBUG_LOG] UiButton clicked! Count: {_clickCount}");
UpdateStatusText();
}
private void HandleStateChanged()
{
Debug.Log($"[DEBUG_LOG] UiButton state changed. Interactable: {_uiButton.IsInteractable}");
}
private void UpdateStatusText()
{
if (_statusText != null)
{
_statusText.text = $"Clicks: {_clickCount}\nInteractable: {(_uiButton?.IsInteractable ?? false)}";
}
}
// Test methods that can be called from inspector or other scripts
[ContextMenu("Toggle Interactable")]
public void ToggleInteractable()
{
if (_uiButton != null)
{
_uiButton.SetInteractable(!_uiButton.IsInteractable);
Debug.Log($"[DEBUG_LOG] Button interactable set to: {_uiButton.IsInteractable}");
UpdateStatusText();
}
}
[ContextMenu("Force Update State")]
public void ForceUpdateState()
{
if (_uiButton != null)
{
_uiButton.ForceUpdateState();
Debug.Log("[DEBUG_LOG] Button state forcefully updated");
}
}
[ContextMenu("Reset Click Count")]
public void ResetClickCount()
{
_clickCount = 0;
Debug.Log("[DEBUG_LOG] Click count reset");
UpdateStatusText();
}
[ContextMenu("Toggle Use Toggle Mode")]
public void ToggleUseToggleMode()
{
if (_uiButton != null)
{
_uiButton.UseToggle = !_uiButton.UseToggle;
Debug.Log($"[DEBUG_LOG] Toggle mode set to: {_uiButton.UseToggle}");
UpdateStatusText();
}
}
[ContextMenu("Set Toggle State On")]
public void SetToggleStateOn()
{
if (_uiButton != null)
{
_uiButton.SetToggleState(true);
Debug.Log($"[DEBUG_LOG] Toggle state set to ON. Toggled: {_uiButton.IsToggled}");
UpdateStatusText();
}
}
[ContextMenu("Set Toggle State Off")]
public void SetToggleStateOff()
{
if (_uiButton != null)
{
_uiButton.SetToggleState(false);
Debug.Log($"[DEBUG_LOG] Toggle state set to OFF. Toggled: {_uiButton.IsToggled}");
UpdateStatusText();
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cc3aec81f35244d39191739b3bd208d2
timeCreated: 1755681789