196 lines
6.2 KiB
C#
Raw Normal View History

2025-09-19 14:56:58 +05:00
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
namespace BulletHellTemplate
{
/// <summary>
/// This script allows rotation of a child object inside a container when dragging or holding,
/// or triggers an animation on click without dragging.
/// Attach this script to an Image or Button (set to transparent).
/// </summary>
public class DragRotateAndHit : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
public static DragRotateAndHit Singleton;
[Header("Container Settings")]
[Tooltip("The container that holds the child object to be rotated.")]
public Transform container;
[Tooltip("Rotation speed of the container.")]
public float rotateSpeed = 4f;
[Tooltip("Audio clip to play when triggering a hit animation.")]
public AudioClip hitClip;
[Tooltip("Audio mixer tag to identify the audio group.")]
public string hitTag = "master";
private Animator childAnimator;
private CharacterModel childCharacterModel;
private bool isDragging = false;
private bool isHolding = false;
private Vector2 startPointerPosition;
private Quaternion initialRotation;
private void Awake()
{
if (Singleton == null)
{
Singleton = this;
}
else
{
Destroy(gameObject);
}
}
private void Start()
{
SetupChild();
}
/// <summary>
/// Sets up the child object inside the container and retrieves its Animator and/or CharacterModel.
/// </summary>
private void SetupChild()
{
if (container == null)
{
Debug.LogError("No container assigned. Please assign a container in the inspector.");
return;
}
if (container.childCount > 0)
{
Transform child = container.GetChild(0);
childAnimator = child.GetComponent<Animator>();
childCharacterModel = child.GetComponent<CharacterModel>();
if (childAnimator == null && childCharacterModel == null)
{
Debug.LogError("No Animator or CharacterModel found in the child of the container.");
}
}
else
{
Debug.LogError("No child found in the container.");
}
initialRotation = container.rotation;
}
/// <summary>
/// Called when the pointer is pressed down on the UI element.
/// </summary>
public void OnPointerDown(PointerEventData eventData)
{
startPointerPosition = eventData.position;
isDragging = false;
isHolding = true;
}
/// <summary>
/// Called when dragging the UI element. Rotates the container based on horizontal drag movement.
/// </summary>
/// <param name="eventData">Pointer event data containing the drag information.</param>
public void OnDrag(PointerEventData eventData)
{
if (container == null || container.childCount == 0)
return;
Vector2 dragDirection = eventData.position - startPointerPosition;
if (dragDirection.x != 0)
{
float rotationAmount = -rotateSpeed * dragDirection.x * Time.deltaTime;
container.Rotate(Vector3.up, rotationAmount);
}
isDragging = true;
}
private void Update()
{
// If holding but not dragging, rotate the container slowly
if (isHolding && !isDragging)
{
container.Rotate(Vector3.up, rotateSpeed * Time.deltaTime);
}
}
/// <summary>
/// Called when the pointer is released. If not dragging, triggers the hit animation.
/// </summary>
/// <param name="eventData">Pointer event data.</param>
public void OnPointerUp(PointerEventData eventData)
{
isHolding = false;
// If it was not dragging, trigger a "Hit" animation
if (!isDragging)
{
// Play audio if available
if (AudioManager.Singleton != null)
{
AudioManager.Singleton.PlayAudio(hitClip, hitTag);
}
// Check if the child has a CharacterModel with Playable animations
if (childCharacterModel != null && childCharacterModel.usePlayableAnimations)
{
childCharacterModel.PlayBaseAnimation("Hit");
}
// Otherwise, fallback to the legacy Animator
else if (childAnimator != null)
{
childAnimator.SetTrigger("hit");
}
else
{
Debug.LogWarning("No Animator or CharacterModel found to trigger the hit animation.");
}
}
}
/// <summary>
/// Resets the container rotation to its original state.
/// </summary>
public void ResetRotation()
{
if (container != null)
{
container.rotation = initialRotation;
}
else
{
Debug.LogError("No container assigned to reset rotation.");
}
}
/// <summary>
/// Updates the character after a new one is loaded into the container.
/// </summary>
public void UpdateCharacter()
{
StartCoroutine(UpdateCharacterAfterFrame());
}
/// <summary>
/// Waits a frame to ensure the new character is instantiated before setup.
/// </summary>
private IEnumerator UpdateCharacterAfterFrame()
{
yield return null;
ResetRotation();
SetupChild();
if (childAnimator == null && childCharacterModel == null)
{
Debug.LogError("No Animator or CharacterModel found after character update. Check the container's child.");
}
}
}
}