/* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (C) 2025 Sergej Görzen * This file is part of OmiLAXR. */ using System.ComponentModel; using OmiLAXR.Components; using OmiLAXR.Schedules; using UnityEngine; namespace OmiLAXR.TrackingBehaviours { /// /// Monitors transform changes (position, rotation, scale) in GameObjects with TransformWatcher components. /// Supports both interval-based polling and real-time change detection modes. /// Can selectively ignore specific transform properties based on configuration. /// [AddComponentMenu("OmiLAXR / 3) Tracking Behaviours / Transform Tracking Behaviour")] [Description("Tracks position, rotation and scale changes in a game object holding component.")] public class TransformTrackingBehaviour : TrackingBehaviour { /// /// Enable real-time change detection by binding to TransformWatcher events. /// When false, only interval-based checking is performed. /// public bool detectOnChange = true; /// /// Configuration for interval-based transform checking. /// Defines timing settings for periodic transform state evaluation. /// public IntervalTicker.Settings intervalSettings; /// /// Flags to ignore specific transform components during tracking. /// Allows selective monitoring of only position, rotation, or scale changes. /// public TransformWatcher.TransformIgnore ignore; /// /// Event triggered when a tracked object's position changes. /// Provides both the TransformWatcher and detailed change information. /// [Gesture("Movement"), Action("Translation")] public readonly TrackingBehaviourEvent OnChangedPosition = new TrackingBehaviourEvent(); /// /// Event triggered when a tracked object's rotation changes. /// Includes old and new rotation values in the change data. /// [Gesture("Movement"), Action("Rotation")] public readonly TrackingBehaviourEvent OnChangedRotation = new TrackingBehaviourEvent(); /// /// Event triggered when a tracked object's scale changes. /// Captures scale modifications with before/after values. /// [Gesture("Movement"), Action("Scale")] public readonly TrackingBehaviourEvent OnChangedScale = new TrackingBehaviourEvent(); /// /// Initializes interval-based transform monitoring when the pipeline starts. /// Creates a scheduled task that polls all tracked transforms at regular intervals. /// /// The pipeline that owns this tracking behavior protected override void OnStartedPipeline(Pipeline pipeline) { // Set up interval-based polling of transform states SetInterval(() => { // Check each tracked transform watcher foreach (var tw in AllFilteredObjects) { // Monitor position changes if not ignored if (!ignore.position) { var posState = new TransformWatcher.TransformChange() { OldValue = tw.PreviousPosition, NewValue = tw.CurrentPosition, }; OnChangedPosition.Invoke(this, tw, posState); } // Monitor rotation changes if not ignored if (!ignore.rotation) { var rotState = new TransformWatcher.TransformChange() { OldValue = tw.PreviousRotation, NewValue = tw.CurrentRotation, }; OnChangedRotation.Invoke(this, tw, rotState); } // Monitor scale changes if not ignored if (!ignore.scale) { var scaleState = new TransformWatcher.TransformChange() { OldValue = tw.PreviousScale, NewValue = tw.CurrentScale, }; OnChangedScale.Invoke(this, tw, scaleState); } } }, intervalSettings); } /// /// Sets up real-time event bindings for detected TransformWatcher components. /// Binds to each watcher's change events for immediate notification of transform modifications. /// /// Array of TransformWatcher components to monitor protected override void AfterFilteredObjects(TransformWatcher[] transformWatchers) { // Skip real-time binding if change detection is disabled if (!detectOnChange) return; // Bind to each transform watcher's events foreach (var tw in transformWatchers) { // Bind to position change events OnChangedPosition.Bind(tw.onChangedPosition, tc => { if (!ignore.position) OnChangedPosition.Invoke(this, tw, tc); }); // Bind to rotation change events OnChangedRotation.Bind(tw.onChangedRotation, tc => { if (!ignore.rotation) OnChangedRotation.Invoke(this, tw, tc); }); // Bind to scale change events OnChangedScale.Bind(tw.onChangedScale, tc => { if (!ignore.scale) OnChangedScale.Invoke(this, tw, tc); }); } } } }