initial game submission

This commit is contained in:
Caleb Sandford deQuincey
2025-06-11 13:04:35 +01:00
parent 47944971ca
commit e9c9bc4409
3041 changed files with 328378 additions and 71117 deletions

View File

@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("UnityGLTF.Interactivity.Tests.Editor")]

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef10b076887dc480d92b11adb8fe92c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 89de0c477eeb585418a50ee6bca64241
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8c99b5b31dcc4a78b8f802f9e2b98bef
timeCreated: 1739350159

View File

@@ -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]);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9e21c551bcee461e874573c4707d26e8
timeCreated: 1742287958

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3bce57772b9340ff9c2417a4ec752bc2
timeCreated: 1739281757

View File

@@ -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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b4e365d7ab8a2428aaef1c87d96c203a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 30cf060000ac4905b2782ffadcba8f56
timeCreated: 1739292248

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: aaef19495e9442b5910fdb375f7c7599
timeCreated: 1739297504

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ba9f61012675422790f9f7139d5b2337
timeCreated: 1739454084

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 05d7f049e55d4f3c94b1df02e1825a57
timeCreated: 1739456877

View File

@@ -0,0 +1,3 @@
{
"reference": "GUID:ea715009a4efd4c6cbc85be3ae097dd3"
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8796cc4626ae84b4dadb32ec7dbf5294
AssemblyDefinitionReferenceImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b32719cca6c4a83960e25cfbbb93ea0
timeCreated: 1739447491

View File

@@ -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
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5144c6d6404c34f70b2d82609133a096
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: