Table of Contents

Extending Outputs

In order to extend HyperTween to add new output types, you just need to add a component that extends ITweenTo<TComponent, TValue>. HyperTween will automatically generate a From version of the component and the systems required.

using BreezeBlockGames.HyperTween.UnityShared.ECS.ConflictDetection.Attributes;
using BreezeBlockGames.HyperTween.UnityShared.ECS.Update.Components;
using Unity.Mathematics;
using Unity.Transforms;

namespace BreezeBlockGames.HyperTween.UnityShared.Modules.LocalTransforms.Components
{
    [DetectConflicts(typeof(TransformInstanceId))]
    public struct TweenLocalPosition : ITweenTo<LocalTransform, float3>
    {
        public float3 Value;

        public float3 GetValue()
        {
            return Value;
        }

        public float3 Lerp(float3 from, float3 to, float parameter)
        {
            return math.lerp(from, to, parameter);
        }

        public readonly float3 Read(in LocalTransform component)
        {
            return component.Position;
        }

        public readonly void Write(ref LocalTransform component, float3 value)
        {
            component.Position = value;
        }
    }
}

API Extensions Methods

You could add this component to tweens using the regular ECS methods, but it is recommended to create extension methods for TweenHandle with overloads with parameters with/without a from component.

using System;
using BreezeBlockGames.HyperTween.UnityShared.API;
using BreezeBlockGames.HyperTween.UnityShared.Modules.LocalTransforms.Components;
using BreezeBlockGames.HyperTween.UnityShared.Modules.Transforms.Components;
using BreezeBlockGames.HyperTween.UnityShared.TweenBuilders;

namespace BreezeBlockGames.HyperTween.UnityShared.Modules.Transforms.API
{
    public static class TweenTransformExtensions
    {
        public static TweenHandle<TBuilder> WithTransform<TBuilder>(this TweenHandle<TBuilder> tweenHandle, UnityEngine.Transform transform) 
            where TBuilder : unmanaged, ITweenBuilder
        {
            if (!transform)
            {
                throw new NullReferenceException("Transform must be non-null");
            }

            tweenHandle = tweenHandle.EnsureHasLocalTransform();

            tweenHandle.TweenBuilder.AddComponent(tweenHandle.Entity, TransformInstanceId.Create(transform));
            
            return tweenHandle;
        }
    }
}

Optionally, you can also add extension methods for BatchTweenHandle.

using BreezeBlockGames.HyperTween.UnityShared.API;
using BreezeBlockGames.HyperTween.UnityShared.Modules.LocalTransforms.Components;
using BreezeBlockGames.HyperTween.UnityShared.Modules.Transforms.Components;
using BreezeBlockGames.HyperTween.UnityShared.TweenBuilders;
using Unity.Collections;
using Unity.Profiling;
using Unity.Transforms;

namespace BreezeBlockGames.HyperTween.UnityShared.Modules.Transforms.API
{
    public static class TweenTransformBatchExtensions
    {
        public static BatchTweenHandle<T> WithManagedTransformOutputs<T>(this BatchTweenHandle<T> tweenHandle, NativeArray<TransformInstanceId> transformInstanceIds)
            where T : unmanaged, ITweenBuilder
        {
            tweenHandle.BatchTweenBuilder.AddComponent<LocalTransform>();
            tweenHandle.BatchTweenBuilder.AddComponents(transformInstanceIds);
            return tweenHandle;
        }
        
        public static NativeArray<TransformInstanceId> ToTransformInstanceIds(this UnityEngine.Transform[] transforms, Allocator allocator)
        {
            using var profilerMarker = new ProfilerMarker("ToTransformInstanceIds").Auto();
            
            var transformInstanceIds = new NativeArray<TransformInstanceId>(transforms.Length, allocator);
            
            for (var i = 0; i < transforms.Length; i++)
            {
                transformInstanceIds[i] = TransformInstanceId.Create(transforms[i]);
            }

            return transformInstanceIds;
        }
    }
}

Conflict Detection

Adding the [DetectConflicts] attribute to the output component will also generate the system required to detect conflicts. See Miscellaneous Topics for more information regarding conflicts. By default, this system will detect conflicts by checking if there is an existing tween playing with the same target entity and output component. Alternatively, you can use [DetectConflicts(typeof(UnityObjectInstanceId))] for detecting conflicts based on Unity Object instance ids, [DetectConflicts(typeof(ObjectHashCode))] to use System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj). Note that you must also add these components to the tween entity using UnityObjectInstanceId.Create() and ObjectHashCode.Create() respectively.