uibutton 임시저장
This commit is contained in:
parent
4a18a239e8
commit
0dc138ea2f
390
Assets/_DDD/_Scripts/GameUi/UiButton.cs
Normal file
390
Assets/_DDD/_Scripts/GameUi/UiButton.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/_DDD/_Scripts/GameUi/UiButton.cs.meta
Normal file
3
Assets/_DDD/_Scripts/GameUi/UiButton.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb17a59bc188495b84cb323bb982f64b
|
||||
timeCreated: 1755681745
|
133
Assets/_DDD/_Scripts/GameUi/UiButtonTest.cs
Normal file
133
Assets/_DDD/_Scripts/GameUi/UiButtonTest.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/_DDD/_Scripts/GameUi/UiButtonTest.cs.meta
Normal file
3
Assets/_DDD/_Scripts/GameUi/UiButtonTest.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc3aec81f35244d39191739b3bd208d2
|
||||
timeCreated: 1755681789
|
Loading…
Reference in New Issue
Block a user