196 lines
6.2 KiB
C#
196 lines
6.2 KiB
C#
|
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.");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|