initial game submission
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("UnityGLTF.Interactivity.Tests.Editor")]
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef10b076887dc480d92b11adb8fe92c1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89de0c477eeb585418a50ee6bca64241
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class AbstractMaterialInterpolate<TValueType> : Unit, IGraphElementWithData, IGraphEventListener
|
||||
{
|
||||
public sealed class Data : IGraphElementData
|
||||
{
|
||||
public bool isListening = false;
|
||||
public bool running = false;
|
||||
|
||||
public float time;
|
||||
|
||||
public TValueType lastSetValue;
|
||||
public TValueType startValue;
|
||||
|
||||
public TValueType endValue;
|
||||
|
||||
public float duration;
|
||||
|
||||
public string valueName;
|
||||
|
||||
public Material material;
|
||||
public Vector2 pointA;
|
||||
public Vector2 pointB;
|
||||
|
||||
public Delegate update;
|
||||
}
|
||||
|
||||
protected virtual TValueType defaultValue { get; }
|
||||
protected virtual string defaultValueName { get; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ValueInput target { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ValueInput valueName { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput assign { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Target Value")]
|
||||
public ValueInput targetValue { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Point A")]
|
||||
public ValueInput pointA { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Point B")]
|
||||
public ValueInput pointB { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Duration")]
|
||||
public ValueInput duration { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ControlOutput assigned { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ControlOutput done { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
target = ValueInput(typeof(Material), nameof(target));
|
||||
target.SetDefaultValue(typeof(Material).PseudoDefault());
|
||||
|
||||
assign = ControlInput(nameof(assign), Assign);
|
||||
Requirement(target, assign);
|
||||
|
||||
assigned = ControlOutput(nameof(assigned));
|
||||
done = ControlOutput(nameof(done));
|
||||
Succession(assign, assigned);
|
||||
Succession(assign, done);
|
||||
|
||||
valueName = ValueInput(typeof(string), nameof(valueName));
|
||||
valueName.SetDefaultValue(defaultValueName);
|
||||
Requirement(valueName, assign);
|
||||
|
||||
targetValue = ValueInput(typeof(TValueType), nameof(targetValue));
|
||||
targetValue.SetDefaultValue(defaultValue);
|
||||
Requirement(targetValue, assign);
|
||||
|
||||
duration = ValueInput(typeof(float), nameof(duration));
|
||||
duration.SetDefaultValue(1f);
|
||||
Requirement(duration, assign);
|
||||
|
||||
pointA = ValueInput(typeof(Vector2), nameof(pointA));
|
||||
pointA.SetDefaultValue(new Vector2(1f,1f));
|
||||
Requirement(pointA, assign);
|
||||
|
||||
pointB = ValueInput(typeof(Vector2), nameof(pointB));
|
||||
pointB.SetDefaultValue(new Vector2(1f,1f));
|
||||
Requirement(pointB, assign);
|
||||
}
|
||||
|
||||
private ControlOutput Assign(Flow flow)
|
||||
{
|
||||
StartNewInterpolation(flow);
|
||||
return assigned;
|
||||
}
|
||||
|
||||
public IGraphElementData CreateData()
|
||||
{
|
||||
return new Data();
|
||||
}
|
||||
|
||||
public void StartListening(GraphStack stack)
|
||||
{
|
||||
var data = stack.GetElementData<Data>(this);
|
||||
|
||||
if (data.isListening)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var reference = stack.ToReference();
|
||||
var hook = new EventHook(EventHooks.Update, stack.machine);
|
||||
Action<EmptyEventArgs> update = args => TriggerUpdate(reference);
|
||||
EventBus.Register(hook, update);
|
||||
data.update = update;
|
||||
data.isListening = true;
|
||||
}
|
||||
|
||||
public void StopListening(GraphStack stack)
|
||||
{
|
||||
var data = stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.isListening)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var hook = new EventHook(EventHooks.Update, stack.machine);
|
||||
EventBus.Unregister(hook, data.update);
|
||||
|
||||
stack.ClearReference();
|
||||
|
||||
data.update = null;
|
||||
data.isListening = false;
|
||||
}
|
||||
|
||||
public bool IsListening(GraphPointer pointer)
|
||||
{
|
||||
return pointer.GetElementData<Data>(this).isListening;
|
||||
}
|
||||
|
||||
private void TriggerUpdate(GraphReference reference)
|
||||
{
|
||||
using (var flow = Flow.New(reference))
|
||||
{
|
||||
Update(flow);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void StartNewInterpolation(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
data.running = true;
|
||||
|
||||
data.duration = flow.GetValue<float>(this.duration);
|
||||
data.material = flow.GetValue<Material>(target);
|
||||
data.valueName = flow.GetValue<string>(valueName);
|
||||
data.pointA = flow.GetValue<Vector2>(pointA);
|
||||
data.pointB = flow.GetValue<Vector2>(pointB);
|
||||
data.time = 0f;
|
||||
}
|
||||
|
||||
protected abstract bool SetValue(Flow flow, Data data, TValueType newValue);
|
||||
|
||||
public void Update(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
data.time += Time.deltaTime;
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
var t = data.time / data.duration;
|
||||
var currentValue = InterpolateHelper.BezierInterpolate(data.pointA, data.pointB, data.startValue, data.endValue, t);
|
||||
if (!SetValue(flow, data, (TValueType)currentValue))
|
||||
{
|
||||
// Stop the interpolation if the value was changed externally
|
||||
data.running = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.lastSetValue = (TValueType)currentValue;
|
||||
}
|
||||
|
||||
if (!data.running || data.time >= data.duration)
|
||||
{
|
||||
bool callDone = data.running;
|
||||
|
||||
if (data.running)
|
||||
SetValue(flow, data, data.endValue);
|
||||
|
||||
data.running = false;
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
|
||||
if (callDone)
|
||||
flow.Invoke(done);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c99b5b31dcc4a78b8f802f9e2b98bef
|
||||
timeCreated: 1739350159
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[UnitCategory("Debug")]
|
||||
[UnitTitle("Debug Log glTF (Message, Args)")]
|
||||
[TypeIcon(typeof(Debug))]
|
||||
public class DebugLogGltf : Unit
|
||||
{
|
||||
public enum LogVerbosity
|
||||
{
|
||||
Log = 0,
|
||||
Warning = 1,
|
||||
Error = 2
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
[Inspectable, UnitHeaderInspectable("Verbosity")]
|
||||
public LogVerbosity logVerbosity
|
||||
{
|
||||
get => _logVerbosity;
|
||||
set => _logVerbosity = value;
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
[Inspectable, UnitHeaderInspectable("Message")]
|
||||
public string message
|
||||
{
|
||||
get => _message;
|
||||
set => _message = value;
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
[Inspectable, UnitHeaderInspectable("Arguments")]
|
||||
public int argumentCount
|
||||
{
|
||||
get => _argumentCount;
|
||||
set => _argumentCount = Mathf.Clamp(value, 0, 20);
|
||||
}
|
||||
|
||||
[SerializeAs(nameof(LogVerbosity))]
|
||||
private LogVerbosity _logVerbosity = LogVerbosity.Log;
|
||||
|
||||
[SerializeAs(nameof(argumentCount))]
|
||||
private int _argumentCount = 1;
|
||||
|
||||
[SerializeAs(nameof(message))]
|
||||
private string _message = "Output: {0}";
|
||||
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput enter { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public List<ValueInput> argumentPorts { get; } = new List<ValueInput>();
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlOutput exit { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
enter = ControlInput("enter", (flow) =>
|
||||
{
|
||||
AssignArguments(flow, out var args);
|
||||
|
||||
switch (logVerbosity)
|
||||
{
|
||||
case LogVerbosity.Log:
|
||||
Debug.LogFormat(message, args);
|
||||
break;
|
||||
case LogVerbosity.Warning:
|
||||
Debug.LogWarningFormat(message, args);
|
||||
break;
|
||||
case LogVerbosity.Error:
|
||||
Debug.LogErrorFormat(message, args);
|
||||
break;
|
||||
}
|
||||
return exit;
|
||||
});
|
||||
|
||||
exit = ControlOutput("exit");
|
||||
Succession(enter, exit);
|
||||
|
||||
argumentPorts.Clear();
|
||||
|
||||
for (var i = 0; i < argumentCount; i++)
|
||||
{
|
||||
var port = ValueInput<object>($"Arg. - {i}");
|
||||
argumentPorts.Add(port);
|
||||
Requirement(port, enter);
|
||||
}
|
||||
}
|
||||
|
||||
protected void AssignArguments(Flow flow, out object[] args)
|
||||
{
|
||||
args = new object[argumentCount];
|
||||
for (var i = 0; i < argumentCount; i++)
|
||||
{
|
||||
args[i] = flow.GetValue(argumentPorts[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e21c551bcee461e874573c4707d26e8
|
||||
timeCreated: 1742287958
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class InterpolateHelper
|
||||
{
|
||||
public static bool AreValuesEqual(object valueA, object valueB)
|
||||
{
|
||||
switch (valueA)
|
||||
{
|
||||
case float f:
|
||||
if (Mathf.Abs((float)valueB - f) > 0.0001f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
case Vector2 v2:
|
||||
var diff2 = v2 - (Vector2)valueB;
|
||||
if (diff2.magnitude > 0.0001f)
|
||||
return false;
|
||||
break;
|
||||
case Vector3 v3:
|
||||
var diff3 = v3 - (Vector3)valueB;
|
||||
if (diff3.magnitude > 0.0001f)
|
||||
return false;
|
||||
break;
|
||||
case Vector4 v4:
|
||||
var diff4 = v4 - (Vector4)valueB;
|
||||
if (diff4.magnitude > 0.0001f)
|
||||
return false;
|
||||
break;
|
||||
case Quaternion q:
|
||||
var diffQ = q.eulerAngles - ((Quaternion)valueB).eulerAngles;
|
||||
if (diffQ.magnitude > 0.0001f)
|
||||
return false;
|
||||
break;
|
||||
case Color c:
|
||||
var diff = c - (Color)valueB;
|
||||
float d = Mathf.Abs(diff.r) + Mathf.Abs(diff.g) + Mathf.Abs(diff.b) + Mathf.Abs(diff.a);
|
||||
if (d > 0.0001f)
|
||||
return false;
|
||||
break;
|
||||
case Matrix4x4 m:
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var diffM = m.GetColumn(0) - ((Matrix4x4)valueB).GetColumn(0);
|
||||
if (diffM.magnitude > 0.0001f)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Vector2 CubicBezier(float t, Vector2 p0, Vector2 p1)
|
||||
{
|
||||
return CubicBezier(t,
|
||||
new Vector2(0f, 0f),
|
||||
new Vector2(p0.x, p0.y),
|
||||
new Vector2(p1.x, p1.y),
|
||||
new Vector2(1f, 1f));
|
||||
}
|
||||
|
||||
private static Vector2 CubicBezier (float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
|
||||
{
|
||||
float u = 1 - t;
|
||||
float tt = t * t;
|
||||
float uu = u * u;
|
||||
float uuu = uu * u;
|
||||
float ttt = tt * t;
|
||||
|
||||
Vector2 p = new Vector2(0, 0);
|
||||
p.x = uuu * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + ttt * p3.x;
|
||||
p.y = uuu * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + ttt * p3.y;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static object BezierInterpolate(Vector2 pointAValue, Vector2 pointBValue, object currentValue, object targetValue, float f)
|
||||
{
|
||||
var bezier = CubicBezier(f, pointAValue, pointBValue);
|
||||
f = bezier.y;
|
||||
if (currentValue is Vector2 currentVector2)
|
||||
{
|
||||
return Vector2.Lerp(currentVector2, (Vector2)targetValue , f);
|
||||
}
|
||||
else if (currentValue is Vector3 currentVector3)
|
||||
{
|
||||
return Vector3.Lerp(currentVector3, (Vector3)targetValue , f);
|
||||
}
|
||||
else if (currentValue is Vector4 currentVector4)
|
||||
{
|
||||
return Vector4.Lerp(currentVector4, (Vector4)targetValue , f);
|
||||
}
|
||||
else if (currentValue is Quaternion currentQuaternion)
|
||||
{
|
||||
return Quaternion.Slerp(currentQuaternion, (Quaternion)targetValue , f);
|
||||
}
|
||||
else if (currentValue is Color currentColor)
|
||||
{
|
||||
return Color.Lerp(currentColor, (Color)targetValue , f);
|
||||
}
|
||||
else if (currentValue is int currentInt)
|
||||
{
|
||||
return Mathf.RoundToInt(Mathf.Lerp(currentInt, (int)targetValue , f));
|
||||
}
|
||||
else if (currentValue is float currentFloat)
|
||||
{
|
||||
return Mathf.Lerp(currentFloat, (float)targetValue , f);
|
||||
}
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bce57772b9340ff9c2417a4ec752bc2
|
||||
timeCreated: 1739281757
|
||||
@@ -0,0 +1,268 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
//namespace UnityGLTF.Interactivity.Units
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Interpolates the value of a field or property over time via reflection.
|
||||
/// </summary>
|
||||
[SpecialUnit]
|
||||
public sealed class InterpolateMember : MemberUnit, IGraphElementWithData, IGraphEventListener
|
||||
{
|
||||
public sealed class Data : IGraphElementData
|
||||
{
|
||||
public bool isListening = false;
|
||||
public bool running = false;
|
||||
|
||||
public float time;
|
||||
|
||||
public object lastSetValue;
|
||||
public object startValue;
|
||||
|
||||
public object endValue;
|
||||
|
||||
public float duration;
|
||||
|
||||
public Vector2 pointA;
|
||||
public Vector2 pointB;
|
||||
|
||||
public Delegate update;
|
||||
}
|
||||
|
||||
public InterpolateMember() : base() { }
|
||||
|
||||
public InterpolateMember(Member member) : base(member) { }
|
||||
|
||||
|
||||
[DoNotSerialize]
|
||||
[Unity.VisualScripting.MemberFilter(Fields = true, Properties = true, ReadOnly = false)]
|
||||
public Member setter
|
||||
{
|
||||
get => member;
|
||||
set => member = value;
|
||||
}
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput assign { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Target Value")]
|
||||
public ValueInput input { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Point A")]
|
||||
public ValueInput pointA { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Point B")]
|
||||
public ValueInput pointB { get; private set; }
|
||||
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Duration")]
|
||||
public ValueInput duration { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The target object used when setting the value.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Target")]
|
||||
[PortLabelHidden]
|
||||
public ValueOutput targetOutput { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ControlOutput assigned { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ControlOutput done { get; private set; }
|
||||
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
base.Definition();
|
||||
assign = ControlInput(nameof(assign), Assign);
|
||||
|
||||
assigned = ControlOutput(nameof(assigned));
|
||||
done = ControlOutput(nameof(done));
|
||||
Succession(assign, assigned);
|
||||
Succession(assign, done);
|
||||
|
||||
if (member.requiresTarget)
|
||||
{
|
||||
Requirement(target, assign);
|
||||
}
|
||||
|
||||
input = ValueInput(member.type, nameof(input));
|
||||
Requirement(input, assign);
|
||||
|
||||
if (member.allowsNull)
|
||||
{
|
||||
input.AllowsNull();
|
||||
}
|
||||
input.SetDefaultValue(member.type.PseudoDefault());
|
||||
|
||||
duration = ValueInput(typeof(float), nameof(duration));
|
||||
duration.SetDefaultValue(1f);
|
||||
Requirement(duration, assign);
|
||||
|
||||
pointA = ValueInput(typeof(Vector2), nameof(pointA));
|
||||
pointA.SetDefaultValue(new Vector2(1f,1f));
|
||||
Requirement(pointA, assign);
|
||||
|
||||
pointB = ValueInput(typeof(Vector2), nameof(pointB));
|
||||
pointB.SetDefaultValue(new Vector2(1f,1f));
|
||||
Requirement(pointB, assign);
|
||||
}
|
||||
|
||||
protected override bool IsMemberValid(Member member)
|
||||
{
|
||||
return member.isAccessor && member.isSettable;
|
||||
}
|
||||
|
||||
private ControlOutput Assign(Flow flow)
|
||||
{
|
||||
StartNewInterpolation(flow);
|
||||
return assigned;
|
||||
}
|
||||
|
||||
public IGraphElementData CreateData()
|
||||
{
|
||||
return new Data();
|
||||
}
|
||||
|
||||
public void StartListening(GraphStack stack)
|
||||
{
|
||||
var data = stack.GetElementData<Data>(this);
|
||||
|
||||
if (data.isListening)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var reference = stack.ToReference();
|
||||
var hook = new EventHook(EventHooks.Update, stack.machine);
|
||||
Action<EmptyEventArgs> update = args => TriggerUpdate(reference);
|
||||
EventBus.Register(hook, update);
|
||||
data.update = update;
|
||||
data.isListening = true;
|
||||
}
|
||||
|
||||
public void StopListening(GraphStack stack)
|
||||
{
|
||||
var data = stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.isListening)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var hook = new EventHook(EventHooks.Update, stack.machine);
|
||||
EventBus.Unregister(hook, data.update);
|
||||
|
||||
stack.ClearReference();
|
||||
|
||||
data.update = null;
|
||||
data.isListening = false;
|
||||
}
|
||||
|
||||
public bool IsListening(GraphPointer pointer)
|
||||
{
|
||||
return pointer.GetElementData<Data>(this).isListening;
|
||||
}
|
||||
|
||||
private void TriggerUpdate(GraphReference reference)
|
||||
{
|
||||
using (var flow = Flow.New(reference))
|
||||
{
|
||||
Update(flow);
|
||||
}
|
||||
}
|
||||
|
||||
protected void StartNewInterpolation(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
data.running = true;
|
||||
|
||||
data.duration = flow.GetValue<float>(this.duration);
|
||||
data.pointA = flow.GetValue<Vector2>(pointA);
|
||||
data.pointB = flow.GetValue<Vector2>(pointB);
|
||||
data.time = 0f;
|
||||
|
||||
data.endValue = flow.GetConvertedValue(input);
|
||||
data.startValue = member.Get(flow.GetValue(this.target, member.targetType));
|
||||
data.lastSetValue = data.startValue;
|
||||
}
|
||||
|
||||
protected bool SetValue(Flow flow, Data data, object newValue)
|
||||
{
|
||||
var target = flow.GetValue(this.target, member.targetType);
|
||||
|
||||
var currentSetValue = member.Get(target);
|
||||
if (!InterpolateHelper.AreValuesEqual(data.lastSetValue, currentSetValue))
|
||||
return false;
|
||||
|
||||
member.Set(target, newValue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Update(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
data.time += Time.deltaTime;
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
var t = data.time / data.duration;
|
||||
var currentValue = InterpolateHelper.BezierInterpolate(data.pointA, data.pointB, data.startValue, data.endValue, t);
|
||||
if (!SetValue(flow, data, currentValue))
|
||||
{
|
||||
// Stop the interpolation if the value was changed externally
|
||||
data.running = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.lastSetValue = currentValue;
|
||||
}
|
||||
|
||||
if (!data.running || data.time >= data.duration)
|
||||
{
|
||||
bool callDone = data.running;
|
||||
if (data.running)
|
||||
SetValue(flow, data, data.endValue);
|
||||
|
||||
data.running = false;
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
|
||||
if (callDone)
|
||||
flow.Invoke(done);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
}
|
||||
|
||||
#region Analytics
|
||||
|
||||
public override AnalyticsIdentifier GetAnalyticsIdentifier()
|
||||
{
|
||||
var aid = new AnalyticsIdentifier
|
||||
{
|
||||
Identifier = $"{member.targetType.FullName}.{member.name}(Interpolate)",
|
||||
Namespace = member.targetType.Namespace,
|
||||
};
|
||||
aid.Hashcode = aid.Identifier.GetHashCode();
|
||||
return aid;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4e365d7ab8a2428aaef1c87d96c203a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[UnitCategory("Material")]
|
||||
[UnitTitle("Material Color Interpolate")]
|
||||
public class MaterialColorInterpolate : AbstractMaterialInterpolate<Color>
|
||||
{
|
||||
protected override Color defaultValue { get => Color.white; }
|
||||
protected override string defaultValueName { get => "_Color"; }
|
||||
|
||||
public MaterialColorInterpolate() : base() { }
|
||||
|
||||
protected override bool SetValue(Flow flow, Data data, Color newValue)
|
||||
{
|
||||
// Check if the material color was changed externally
|
||||
var diff = data.material.GetColor(data.valueName) - data.lastSetValue;
|
||||
float d = Mathf.Abs(diff.r) + Mathf.Abs(diff.g) + Mathf.Abs(diff.b) + Mathf.Abs(diff.a);
|
||||
if (d > 0.0001f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
data.material.SetColor(data.valueName, newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void StartNewInterpolation(Flow flow)
|
||||
{
|
||||
base.StartNewInterpolation(flow);
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
data.startValue = data.material.GetColor(data.valueName);
|
||||
data.endValue = flow.GetValue<Color>(this.targetValue);
|
||||
data.lastSetValue = data.startValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30cf060000ac4905b2782ffadcba8f56
|
||||
timeCreated: 1739292248
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[UnitCategory("Material")]
|
||||
[UnitTitle("Material Float Interpolate")]
|
||||
public class MaterialFloatInterpolate : AbstractMaterialInterpolate<float>
|
||||
{
|
||||
public MaterialFloatInterpolate() : base() { }
|
||||
|
||||
protected override float defaultValue { get => 1f; }
|
||||
protected override string defaultValueName { get => "_smoothness"; }
|
||||
|
||||
protected override bool SetValue(Flow flow, Data data, float newValue)
|
||||
{
|
||||
float diff = data.material.GetFloat(data.valueName) - data.lastSetValue;
|
||||
if (Mathf.Abs(diff) > 0.0001f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
data.material.SetFloat(data.valueName, newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void StartNewInterpolation(Flow flow)
|
||||
{
|
||||
base.StartNewInterpolation(flow);
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
data.startValue = data.material.GetFloat(data.valueName);
|
||||
data.endValue = flow.GetValue<float>(this.targetValue);
|
||||
data.lastSetValue = data.startValue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aaef19495e9442b5910fdb375f7c7599
|
||||
timeCreated: 1739297504
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[UnitCategory("Material")]
|
||||
[UnitTitle("Material Texture Offset Interpolate")]
|
||||
public class MaterialOffsetInterpolate : AbstractMaterialInterpolate<Vector2>
|
||||
{
|
||||
public MaterialOffsetInterpolate() : base() { }
|
||||
|
||||
protected override Vector2 defaultValue { get => Vector2.zero; }
|
||||
protected override string defaultValueName { get => "_BaseTex"; }
|
||||
|
||||
protected override bool SetValue(Flow flow, Data data, Vector2 newValue)
|
||||
{
|
||||
var diff = data.material.GetTextureOffset(data.valueName) - data.lastSetValue;
|
||||
if (diff.magnitude > 0.0001f)
|
||||
return false;
|
||||
|
||||
data.material.SetTextureOffset(data.valueName, newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void StartNewInterpolation(Flow flow)
|
||||
{
|
||||
base.StartNewInterpolation(flow);
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
data.startValue = data.material.GetTextureOffset(data.valueName);
|
||||
data.endValue = flow.GetValue<Vector2>(this.targetValue);
|
||||
data.lastSetValue = data.startValue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba9f61012675422790f9f7139d5b2337
|
||||
timeCreated: 1739454084
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[UnitCategory("Material")]
|
||||
[UnitTitle("Material Texture Scale Interpolate")]
|
||||
public class MaterialScaleInterpolate : AbstractMaterialInterpolate<Vector2>
|
||||
{
|
||||
public MaterialScaleInterpolate() : base() { }
|
||||
|
||||
protected override Vector2 defaultValue { get => Vector2.zero; }
|
||||
protected override string defaultValueName { get => "_BaseTex"; }
|
||||
|
||||
protected override bool SetValue(Flow flow, Data data, Vector2 newValue)
|
||||
{
|
||||
var diff = data.material.GetTextureScale(data.valueName) - data.lastSetValue;
|
||||
if (diff.magnitude > 0.0001f)
|
||||
return false;
|
||||
|
||||
data.material.SetTextureScale(data.valueName, newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void StartNewInterpolation(Flow flow)
|
||||
{
|
||||
base.StartNewInterpolation(flow);
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
data.startValue = data.material.GetTextureScale(data.valueName);
|
||||
data.endValue = flow.GetValue<Vector2>(this.targetValue);
|
||||
data.lastSetValue = data.startValue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05d7f049e55d4f3c94b1df02e1825a57
|
||||
timeCreated: 1739456877
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"reference": "GUID:ea715009a4efd4c6cbc85be3ae097dd3"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8796cc4626ae84b4dadb32ec7dbf5294
|
||||
AssemblyDefinitionReferenceImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,264 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[UnitCategory("Variables")]
|
||||
[UnitTitle("Variable Interpolate")]
|
||||
public class VariableInterpolate : Unit, IUnifiedVariableUnit, IGraphElementWithData, IGraphEventListener
|
||||
{
|
||||
public sealed class Data : IGraphElementData
|
||||
{
|
||||
public bool isListening = false;
|
||||
public bool running = false;
|
||||
|
||||
public float time;
|
||||
|
||||
public object lastSetValue;
|
||||
public object startValue;
|
||||
|
||||
public object endValue;
|
||||
|
||||
public float duration;
|
||||
|
||||
public Vector2 pointA;
|
||||
public Vector2 pointB;
|
||||
|
||||
public Delegate update;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The kind of variable.
|
||||
/// </summary>
|
||||
[Serialize, Inspectable, UnitHeaderInspectable]
|
||||
public VariableKind kind { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the variable.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ValueInput name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The source of the variable.
|
||||
/// </summary>
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
[NullMeansSelf]
|
||||
public ValueInput @object { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabelHidden]
|
||||
public ControlInput assign { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Target Value")]
|
||||
public ValueInput targetValue { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Point A")]
|
||||
public ValueInput pointA { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Point B")]
|
||||
public ValueInput pointB { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
[PortLabel("Duration")]
|
||||
public ValueInput duration { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ControlOutput assigned { get; private set; }
|
||||
|
||||
[DoNotSerialize]
|
||||
public ControlOutput done { get; private set; }
|
||||
|
||||
protected override void Definition()
|
||||
{
|
||||
name = ValueInput(nameof(name), string.Empty);
|
||||
|
||||
if (kind == VariableKind.Object)
|
||||
{
|
||||
@object = ValueInput<GameObject>(nameof(@object), null).NullMeansSelf();
|
||||
}
|
||||
|
||||
assign = ControlInput(nameof(assign), Assign);
|
||||
|
||||
assigned = ControlOutput(nameof(assigned));
|
||||
done = ControlOutput(nameof(done));
|
||||
Succession(assign, assigned);
|
||||
Succession(assign, done);
|
||||
|
||||
targetValue = ValueInput<object>(nameof(targetValue)).AllowsNull();
|
||||
Requirement(targetValue, assign);
|
||||
|
||||
duration = ValueInput(typeof(float), nameof(duration));
|
||||
duration.SetDefaultValue(1f);
|
||||
Requirement(duration, assign);
|
||||
|
||||
pointA = ValueInput(typeof(Vector2), nameof(pointA));
|
||||
pointA.SetDefaultValue(new Vector2(1f,1f));
|
||||
Requirement(pointA, assign);
|
||||
|
||||
pointB = ValueInput(typeof(Vector2), nameof(pointB));
|
||||
pointB.SetDefaultValue(new Vector2(1f,1f));
|
||||
Requirement(pointB, assign);
|
||||
}
|
||||
|
||||
private ControlOutput Assign(Flow flow)
|
||||
{
|
||||
StartNewInterpolation(flow);
|
||||
return assigned;
|
||||
}
|
||||
|
||||
public IGraphElementData CreateData()
|
||||
{
|
||||
return new Data();
|
||||
}
|
||||
|
||||
public void StartListening(GraphStack stack)
|
||||
{
|
||||
var data = stack.GetElementData<Data>(this);
|
||||
|
||||
if (data.isListening)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var reference = stack.ToReference();
|
||||
var hook = new EventHook(EventHooks.Update, stack.machine);
|
||||
Action<EmptyEventArgs> update = args => TriggerUpdate(reference);
|
||||
EventBus.Register(hook, update);
|
||||
data.update = update;
|
||||
data.isListening = true;
|
||||
}
|
||||
|
||||
public void StopListening(GraphStack stack)
|
||||
{
|
||||
var data = stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.isListening)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var hook = new EventHook(EventHooks.Update, stack.machine);
|
||||
EventBus.Unregister(hook, data.update);
|
||||
|
||||
stack.ClearReference();
|
||||
|
||||
data.update = null;
|
||||
data.isListening = false;
|
||||
}
|
||||
|
||||
public bool IsListening(GraphPointer pointer)
|
||||
{
|
||||
return pointer.GetElementData<Data>(this).isListening;
|
||||
}
|
||||
|
||||
private void TriggerUpdate(GraphReference reference)
|
||||
{
|
||||
using (var flow = Flow.New(reference))
|
||||
{
|
||||
Update(flow);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void StartNewInterpolation(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
data.running = true;
|
||||
|
||||
data.duration = flow.GetValue<float>(this.duration);
|
||||
data.pointA = flow.GetValue<Vector2>(pointA);
|
||||
data.pointB = flow.GetValue<Vector2>(pointB);
|
||||
data.time = 0f;
|
||||
data.lastSetValue = GetValue(flow);
|
||||
data.startValue = data.lastSetValue;
|
||||
data.endValue = flow.GetValue<object>(targetValue);
|
||||
}
|
||||
|
||||
private VariableDeclarations GetDeclarations(Flow flow)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case VariableKind.Flow:
|
||||
return flow.variables;
|
||||
case VariableKind.Graph:
|
||||
return Variables.Graph(flow.stack);
|
||||
case VariableKind.Object:
|
||||
return Variables.Object(flow.GetValue<GameObject>(@object));
|
||||
case VariableKind.Scene:
|
||||
return Variables.Scene(flow.stack.scene);
|
||||
case VariableKind.Application:
|
||||
return Variables.Application;
|
||||
case VariableKind.Saved:
|
||||
return Variables.Saved;
|
||||
default:
|
||||
throw new UnexpectedEnumValueException<VariableKind>(kind);
|
||||
}
|
||||
}
|
||||
|
||||
private object GetValue(Flow flow)
|
||||
{
|
||||
var name = flow.GetValue<string>(this.name);
|
||||
var variables = GetDeclarations(flow);
|
||||
return variables.Get(name);
|
||||
}
|
||||
|
||||
protected bool SetValue(Flow flow, Data data, object newValue)
|
||||
{
|
||||
var name = flow.GetValue<string>(this.name);
|
||||
var currentSetValue = GetValue(flow);
|
||||
if (!InterpolateHelper.AreValuesEqual(data.lastSetValue, currentSetValue))
|
||||
return false;
|
||||
|
||||
var variables = GetDeclarations(flow);
|
||||
variables.Set(name, newValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Update(Flow flow)
|
||||
{
|
||||
var data = flow.stack.GetElementData<Data>(this);
|
||||
|
||||
if (!data.running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
data.time += Time.deltaTime;
|
||||
|
||||
var stack = flow.PreserveStack();
|
||||
var t = data.time / data.duration;
|
||||
var currentValue = InterpolateHelper.BezierInterpolate(data.pointA, data.pointB, data.startValue, data.endValue, t);
|
||||
if (!SetValue(flow, data, currentValue))
|
||||
{
|
||||
// Stop the interpolation if the value was changed externally
|
||||
data.running = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.lastSetValue = currentValue;
|
||||
}
|
||||
|
||||
if (!data.running || data.time >= data.duration)
|
||||
{
|
||||
bool callDone = data.running;
|
||||
|
||||
if (data.running)
|
||||
SetValue(flow, data, data.endValue);
|
||||
|
||||
data.running = false;
|
||||
|
||||
flow.RestoreStack(stack);
|
||||
|
||||
if (callDone)
|
||||
flow.Invoke(done);
|
||||
}
|
||||
|
||||
flow.DisposePreservedStack(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b32719cca6c4a83960e25cfbbb93ea0
|
||||
timeCreated: 1739447491
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "UnityGLTF.Interactivity.VisualScripting.Runtime",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [
|
||||
"HAVE_VISUAL_SCRIPTING"
|
||||
],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.visualscripting",
|
||||
"expression": "1.9",
|
||||
"define": "HAVE_VISUAL_SCRIPTING"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5144c6d6404c34f70b2d82609133a096
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user