AlicizaX/Client/Assets/Plugins/OM/TimelineCreator/Runtime/OM_ClipBase.cs

178 lines
7.9 KiB
C#
Raw Normal View History

2025-11-17 16:56:03 +08:00
using UnityEngine;
namespace OM.TimelineCreator.Runtime
{
/// <summary>
/// Base class for all clip data stored within the timeline system.
/// Contains common properties like name, description, timing, activation state,
/// display color, and error status. Intended to be inherited by specific clip types (e.g., AnimoraClip).
/// </summary>
[System.Serializable]
public abstract class OM_ClipBase // Changed to abstract as it likely isn't instantiated directly
{
// --- Serialized Fields ---
// Using OM_StartGroup for editor organization (requires a custom drawer or editor script)
[OM_StartGroup("Clip Info", "Info")] // Group Title, Group ID/Key
[SerializeField] private string clipName = "New Clip"; // Default name for the clip
[SerializeField, TextArea] // Use TextArea for multi-line editing in the inspector
private string clipDescription = ""; // Optional description for the clip
[SerializeField] private Color highlightColor = Color.white; // Color used for visual representation in the timeline editor
[OM_StartGroup("Settings", "Settings")] // Start a new group for timing properties
[SerializeField, OM_HideInInspector] // Hide by default, likely controlled by editor logic (e.g., track UI)
private bool isActive = true; // Whether the clip is currently active and should be evaluated
[SerializeField, Min(0)] // Ensure start time is not negative
private float startTime = 0; // The time (in seconds) on the timeline where this clip begins
[SerializeField, Min(0)] // Ensure duration is not negative
private float duration = 1; // The length (in seconds) of this clip
[SerializeField, OM_HideInInspector] // Hide by default, managed internally or by editor
private int orderIndex = 0; // The vertical order/layer index of this clip on the timeline
// --- Public Properties (Accessors for Serialized Fields) ---
/// <summary>
/// Gets or sets the name of the clip, displayed in the timeline editor.
/// </summary>
public string ClipName { get => clipName; set => clipName = value; }
/// <summary>
/// Gets or sets the description for the clip, potentially shown as a tooltip or in an inspector.
/// </summary>
public string ClipDescription { get => clipDescription; set => clipDescription = value; }
/// <summary>
/// Gets or sets the color used to highlight this clip in the timeline editor UI.
/// </summary>
public Color HighlightColor { get => highlightColor; set => highlightColor = value; }
/// <summary>
/// Gets or sets a value indicating whether this clip is active. Inactive clips are typically ignored during playback.
/// </summary>
public bool IsActive { get => isActive; set => isActive = value; }
/// <summary>
/// Gets or sets the start time of the clip on the timeline (in seconds).
/// Setting this might require updating the editor UI representation.
/// </summary>
public float StartTime { get => startTime; set => startTime = Mathf.Max(0, value); } // Added validation
/// <summary>
/// Gets or sets the duration of the clip (in seconds).
/// Setting this might require updating the editor UI representation.
/// </summary>
public float Duration { get => duration; set => duration = Mathf.Max(0, value); } // Added validation
/// <summary>
/// Gets or sets the order index (vertical layer) of the clip.
/// This is primarily used for sorting tracks visually and resolving potential overlaps if needed.
/// Modifying this usually requires re-sorting or updating the timeline structure.
/// </summary>
public int OrderIndex { get => orderIndex; set => orderIndex = value; }
// --- Virtual Methods for Timing ---
/// <summary>
/// Gets the effective start time of the clip. Can be overridden if start time calculation is complex.
/// </summary>
/// <returns>The start time in seconds.</returns>
public virtual float GetStartTime()
{
return startTime;
}
/// <summary>
/// Gets the effective duration of the clip. Can be overridden if duration calculation is complex.
/// </summary>
/// <returns>The duration in seconds.</returns>
public virtual float GetDuration()
{
return duration;
}
/// <summary>
/// Sets the effective duration of the clip. Can be overridden for custom logic.
/// </summary>
/// <param name="newDuration">The new duration in seconds.</param>
public virtual void SetDuration(float newDuration)
{
// Basic implementation with validation
duration = Mathf.Max(0, newDuration);
// Derived classes might need to trigger UI updates or other logic here
}
/// <summary>
/// Sets the effective start time of the clip. Can be overridden for custom logic.
/// </summary>
/// <param name="newStartTime">The new start time in seconds.</param>
public virtual void SetStartTime(float newStartTime)
{
// Basic implementation with validation
startTime = Mathf.Max(0, newStartTime);
// Derived classes might need to trigger UI updates or other logic here
}
/// <summary>
/// Calculates and gets the effective end time of the clip (StartTime + Duration).
/// </summary>
/// <returns>The end time in seconds.</returns>
public virtual float GetEndTime()
{
// Standard calculation, ensures virtual methods for start/duration are used
return GetStartTime() + GetDuration();
}
// --- Virtual Methods for Playback Eligibility and State ---
/// <summary>
/// Determines if the clip is currently in a state where it can be played.
/// Base implementation checks IsActive and HasError. Derived classes (like AnimoraClip)
/// can add further conditions (e.g., play chance).
/// </summary>
/// <returns>True if the clip can potentially be played, false otherwise.</returns>
public virtual bool CanBePlayed()
{
// Default condition: must be active and have no errors.
return IsActive && HasError(out _) == false;
}
/// <summary>
/// Checks if the clip has any configuration errors that would prevent playback.
/// Base implementation always returns false (no errors). Derived classes should override this
/// to perform specific validation (e.g., check if targets are assigned).
/// </summary>
/// <param name="error">Output parameter containing the error message if an error is found.</param>
/// <returns>True if an error exists, false otherwise.</returns>
public virtual bool HasError(out string error)
{
error = string.Empty; // Default: no error
return false;
}
/// <summary>
/// Resets the clip's internal state. Called when resetting the timeline or potentially on clip creation/modification.
/// Base implementation does nothing. Derived classes can override to reset specific state variables.
/// </summary>
public virtual void Reset()
{
// No base state to reset here. Derived classes handle their own state.
}
/// <summary>
/// A simple override for ToString() to provide a meaningful representation, often the clip name.
/// Useful for debugging and logging.
/// </summary>
/// <returns>The clip's name or a default string representation.</returns>
public override string ToString()
{
return string.IsNullOrEmpty(clipName) ? base.ToString() : clipName;
}
}
}