Netcode Bootstrap

This commit is contained in:
Luis Gonzalez
2026-05-31 14:27:52 -07:00
parent 99d8d2d2a9
commit 7fa77ce821
1813 changed files with 2921554 additions and 84 deletions
@@ -0,0 +1,75 @@
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UIButtonHandler: MonoBehaviour
{
[Serializable]
public struct ShowcaseData
{
public Button UIBtn;
public GameObject UIRoot;
public Transform vCam;
}
public ShowcaseData[] showcases;
Camera cam;
Transform targetCamera;
/////////////////////////////////////////////////////////////////////////////////
void Start()
{
for (int i = 0; i < showcases.Length; ++i)
{
var sc = showcases[i];
var li = i;
sc.UIBtn.onClick.AddListener(() => OnBtnClick(li));
}
OnBtnClick(0);
showcases[0].UIBtn.Select();
cam = Camera.main;
targetCamera = showcases[0].vCam;
}
/////////////////////////////////////////////////////////////////////////////////
IEnumerator DelayedUISwitch(ShowcaseData sc, bool b)
{
yield return new WaitForSeconds(0.5f);
sc.UIRoot.SetActive(b);
}
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
var dp = targetCamera.position - cam.transform.position;
if (dp.magnitude < 0.1f)
return;
cam.transform.position += dp.normalized * Mathf.Max(dp.magnitude, 2.0f) * Time.deltaTime * 1.5f;
}
/////////////////////////////////////////////////////////////////////////////////
void OnBtnClick(int idx)
{
for (int i = 0; i < showcases.Length; ++i)
{
var sc = showcases[i];
var b = i == idx;
if (b)
targetCamera = sc.vCam;
StartCoroutine(DelayedUISwitch(sc, b));
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 330c15d18b0ad3c44a823b751b974314
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UIButtonHandler.cs
uploadId: 897522
@@ -0,0 +1,94 @@
using System.Collections.Generic;
using TMPro;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UIController_AnimatorOverrideController: MonoBehaviour
{
public TextMeshProUGUI animationListText;
public AnimatorOverrideController overrideController;
List<KeyValuePair<AnimationClip, AnimationClip>> originalOverrides = new ();
/////////////////////////////////////////////////////////////////////////////////
void Start()
{
overrideController.GetOverrides(originalOverrides);
SetAnimationList(true);
}
/////////////////////////////////////////////////////////////////////////////////
void OnDestroy()
{
GameObjectWorldSwitcher(true);
}
/////////////////////////////////////////////////////////////////////////////////
void SetAnimationList(bool on)
{
var animList = "Used animations: ";
var e = originalOverrides.Count;
for (var i = 0; i < e; ++i)
{
var kv = originalOverrides[i];
animList += on ? kv.Value.name : kv.Key.name;
if (i < e - 1)
animList += ", ";
}
animationListText.text = animList;
}
/////////////////////////////////////////////////////////////////////////////////
public void UseOverrideAnimationChange(bool on)
{
EntityWorldSwitcher(on);
GameObjectWorldSwitcher(on);
SetAnimationList(on);
}
/////////////////////////////////////////////////////////////////////////////////
void GameObjectWorldSwitcher(bool on)
{
for (var i = 0; i < originalOverrides.Count; ++i)
{
var kv = originalOverrides[i];
var srcAnim = kv.Key;
var dstAnim = on ? kv.Value : null;
overrideController[srcAnim] = dstAnim;
}
}
/////////////////////////////////////////////////////////////////////////////////
void EntityWorldSwitcher(bool on)
{
var em = World.DefaultGameObjectInjectionWorld.EntityManager;
var q = new EntityQueryBuilder(Allocator.Temp)
.WithAll<AnimatorOverrideAnimations>()
.WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)
.Build(em);
var chunks = q.ToArchetypeChunkArray(Allocator.Temp);
var entityHandle = em.GetEntityTypeHandle();
foreach (var c in chunks)
{
var entities = c.GetNativeArray(entityHandle);
for (int i = 0, ce = c.Count; i < ce; ++i)
{
var e = entities[i];
em.SetComponentEnabled<AnimatorOverrideAnimations>(e, on);
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ca54491ce25c7ac4aaffcde59986870e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UIController_AnimatorOverrideController.cs
uploadId: 897522
@@ -0,0 +1,67 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UIController_AvatarMask: MonoBehaviour
{
SystemHandle sysHandle;
/////////////////////////////////////////////////////////////////////////////////
void Start()
{
sysHandle = World.DefaultGameObjectInjectionWorld.CreateSystem<OverrideAvatarMaskSystem>();
var sysGroup = World.DefaultGameObjectInjectionWorld.GetOrCreateSystemManaged<RukhankaAnimationSystemGroup>();
sysGroup.AddSystemToUpdateList(sysHandle);
EntityWorldSwitcher(true);
}
/////////////////////////////////////////////////////////////////////////////////
public void UseOverrideAnimationChange(bool on)
{
EntityWorldSwitcher(on);
}
/////////////////////////////////////////////////////////////////////////////////
void EntityWorldSwitcher(bool on)
{
var wu = World.DefaultGameObjectInjectionWorld.Unmanaged;
var sys = wu.GetExistingUnmanagedSystem<OverrideAvatarMaskSystem>();
if (sys != SystemHandle.Null)
wu.ResolveSystemStateRef(sys).Enabled = !on;
}
}
//================================================================================//
[DisableAutoCreation]
[UpdateAfter(typeof(FillAnimationsFromControllerSystem))]
[UpdateBefore(typeof(AnimationProcessSystem))]
partial struct OverrideAvatarMaskSystem: ISystem
{
[BurstCompile]
public void OnUpdate(ref SystemState ss)
{
ss.Dependency.Complete();
var atpBufLookup = SystemAPI.GetBufferLookup<AnimationToProcessComponent>();
foreach (var (_, e) in SystemAPI.Query<RigDefinitionComponent>().WithAll<AnimationToProcessComponent>().WithEntityAccess())
{
var atps = atpBufLookup[e];
for (var i = 0; i < atps.Length; ++i)
{
var atp = atps[i];
atp.avatarMask = BlobAssetReference<AvatarMaskBlob>.Null;
atps[i] = atp;
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2988b13ed264638419ae09800ab18fc8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UIController_AvatarMask.cs
uploadId: 897522
@@ -0,0 +1,258 @@
using TMPro;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
[BurstCompile]
class UIController_CrowdSample: MonoBehaviour
{
public TextMeshProUGUI spawnCountLabel;
public TextMeshProUGUI counterLabel;
public TextMeshProUGUI bonesCountLabel;
public TextMeshProUGUI verticesCountLabel;
public Slider spawnCountSlider;
public Button spawnBtn;
public Button despawnBtn;
public Toggle visualizeSkeletonsToggle;
public TMP_Dropdown modeSelector;
public SimpleCameraDollyCart cameraCart;
public GameObject mmRoot;
public TextMeshProUGUI mmSwitchDistanceLabel;
public Slider mmSwitchDistanceSlider;
public TextMeshProUGUI animatorModeLabel;
EntityQuery
spawnerQuery,
rigsQuery,
skinnedMeshQuery,
visualizedRigsQuery,
notVisualizedRigsQuery,
gpuEntitiesQuery,
cpuEntitiesQuery;
EntityManager em;
DistanceBasedMixedModeAnimatorSystem dbs;
/////////////////////////////////////////////////////////////////////////////////
void Start()
{
spawnBtn.onClick.AddListener(SpawnPrefabs);
despawnBtn.onClick.AddListener(DespawnEntities);
var worlds = World.All;
foreach (var w in worlds)
{
if (RukhankaSystemsBootstrap.IsClientOrLocalSimulationWorld(w))
{
em = w.EntityManager;
break;
}
}
dbs = em.World.GetExistingSystemManaged<DistanceBasedMixedModeAnimatorSystem>();
spawnerQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<SpawnPrefabComponent>()
.Build(em);
rigsQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAllRW<RigDefinitionComponent>()
.Build(em);
skinnedMeshQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAllRW<SkinnedMeshRendererComponent>()
.Build(em);
visualizedRigsQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<RigDefinitionComponent, BoneVisualizationComponent>()
.Build(em);
notVisualizedRigsQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<RigDefinitionComponent>()
.WithNone<BoneVisualizationComponent>()
.Build(em);
gpuEntitiesQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<GPUAnimationEngineTag>()
.Build(em);
cpuEntitiesQuery = new EntityQueryBuilder(Allocator.Temp)
.WithDisabled<GPUAnimationEngineTag>()
.Build(em);
AnimatorModeChange(false);
#if !RUKHANKA_DEBUG_INFO
visualizeSkeletonsToggle.enabled = false;
visualizeSkeletonsToggle.isOn = false;
var tmp = visualizeSkeletonsToggle.GetComponentInChildren<TextMeshProUGUI>();
tmp.text += " (RUKHANKA_DEBUG_INFO is not defined)";
tmp.color = Color.gray;
#endif
}
/////////////////////////////////////////////////////////////////////////////////
void SpawnPrefabs()
{
var spawners = spawnerQuery.ToEntityArray(Allocator.Temp);
var multiplier = 1.0f;
#if ENABLE_INPUT_SYSTEM
multiplier = Keyboard.current.ctrlKey.isPressed ? 10 : 1;
#endif
foreach (var s in spawners)
{
var scc = new SpawnCommandComponent()
{
spawnCount = (int)(spawnCountSlider.value / spawners.Length * multiplier),
boneVisualizationOn = visualizeSkeletonsToggle.isOn,
gpuAnimator = modeSelector.value == 1
};
em.AddComponentData(s, scc);
}
}
/////////////////////////////////////////////////////////////////////////////////
void DespawnEntities()
{
var rigsArr = rigsQuery.ToEntityArray(Allocator.Temp);
var multiplier = 1.0f;
#if ENABLE_INPUT_SYSTEM
multiplier = Keyboard.current.ctrlKey.isPressed ? 10 : 1;
#endif
var numToDespawn = math.min(rigsArr.Length, (int)(spawnCountSlider.value * multiplier));
var allRigsIndices = new NativeList<int>(rigsArr.Length, Allocator.Temp);
var rigsToDespawn = new NativeArray<int>(numToDespawn, Allocator.Temp);
for (int i = 0; i < rigsArr.Length; ++i)
{
allRigsIndices.Add(i);
}
var rng = new Unity.Mathematics.Random((uint)numToDespawn + 1);
for (var i = 0; i < rigsToDespawn.Length; ++i)
{
var randomIndex = rng.NextInt(allRigsIndices.Length);
rigsToDespawn[i] = allRigsIndices[randomIndex];
allRigsIndices.RemoveAtSwapBack(randomIndex);
}
for (var i = 0; i < rigsToDespawn.Length; ++i)
{
em.DestroyEntity(rigsArr[rigsToDespawn[i]]);
}
}
/////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
static int CalculateTotalBonesCount(ref EntityQuery eq)
{
var rv = 0;
var rigs = eq.ToComponentDataArray<RigDefinitionComponent>(Allocator.Temp);
foreach (var r in rigs)
{
rv += r.rigBlob.Value.bones.Length;
}
return rv;
}
/////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
static int CalculateTotalSkinnedVerticesCount(ref EntityQuery eq)
{
var rv = 0;
var sms = eq.ToComponentDataArray<SkinnedMeshRendererComponent>(Allocator.Temp);
foreach (var sm in sms)
{
rv += sm.smrInfoBlob.Value.meshVerticesCount;
}
return rv;
}
/////////////////////////////////////////////////////////////////////////////////
public void SwitchBoneVisualization(Toggle t)
{
if (t.isOn)
{
em.AddComponent<BoneVisualizationComponent>(notVisualizedRigsQuery);
}
else
{
em.RemoveComponent<BoneVisualizationComponent>(visualizedRigsQuery);
}
}
/////////////////////////////////////////////////////////////////////////////////
public void AnimatorModeChange(bool switchAnimationEngine)
{
switch (modeSelector.value)
{
case 0:
dbs.Enabled = false;
mmRoot.SetActive(false);
if (switchAnimationEngine)
em.SetComponentEnabled<GPUAnimationEngineTag>(gpuEntitiesQuery, false);
animatorModeLabel.text = "All entities use <color=#0FF>CPU</color> animator";
break;
case 1:
dbs.Enabled = false;
mmRoot.SetActive(false);
if (switchAnimationEngine)
em.SetComponentEnabled<GPUAnimationEngineTag>(cpuEntitiesQuery, true);
animatorModeLabel.text = "All entities use <color=#0F0>GPU</color> animator";
break;
case 2:
mmRoot.SetActive(true);
dbs.Enabled = true;
animatorModeLabel.text = "Camera distance based animator switch";
break;
}
}
/////////////////////////////////////////////////////////////////////////////////
public void SwitchCameraCartMovement(Toggle toggle)
{
cameraCart.enabled = toggle.isOn;
}
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
spawnCountLabel.text = $"{spawnCountSlider.value}";
var animatedObjectsCount = rigsQuery.CalculateEntityCount();
counterLabel.text = $"Total Instance Count: {animatedObjectsCount}";
var totalBonesCount = CalculateTotalBonesCount(ref rigsQuery);
bonesCountLabel.text = $"Total Bone Count: {totalBonesCount}";
mmSwitchDistanceLabel.text = $"{mmSwitchDistanceSlider.value}";
if (verticesCountLabel != null)
{
var totalVerticesCount = CalculateTotalSkinnedVerticesCount(ref skinnedMeshQuery);
verticesCountLabel.text = $"Total Skinned Vertices Count: {totalVerticesCount}";
}
dbs.switchDistance = mmSwitchDistanceSlider.value;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f24db9bd466908f429f4176b356f10cf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UIController_CrowdSample.cs
uploadId: 897522
@@ -0,0 +1,71 @@
using System;
using TMPro;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UIController_RuntimeSkinnedMeshSwitch: MonoBehaviour
{
public Button headsSwitchBtn;
public Button bodiesSwitchBtn;
public Button leftArmsSwitchBtn;
public Button rightArmsSwitchBtn;
EntityQuery modularRigQuery;
/////////////////////////////////////////////////////////////////////////////////
void Start()
{
headsSwitchBtn.onClick.AddListener(() => OnSwitchButtonClick(ModularBodyPart.Head));
bodiesSwitchBtn.onClick.AddListener(() => OnSwitchButtonClick(ModularBodyPart.Body));
leftArmsSwitchBtn.onClick.AddListener(() => OnSwitchButtonClick(ModularBodyPart.LeftArm));
rightArmsSwitchBtn.onClick.AddListener(() => OnSwitchButtonClick(ModularBodyPart.RightArm));
modularRigQuery = new EntityQueryBuilder(Allocator.Temp)
.WithAll<ModularRigPartComponent>()
.Build(World.DefaultGameObjectInjectionWorld.EntityManager);
}
/////////////////////////////////////////////////////////////////////////////////
void SetSkinnedMeshEnabled(Entity smr, EntityCommandBuffer ecb, bool enabled)
{
ecb.SetEnabled(smr, enabled);
}
/////////////////////////////////////////////////////////////////////////////////
void OnSwitchButtonClick(ModularBodyPart mbp)
{
var em = World.DefaultGameObjectInjectionWorld.EntityManager;
var entities = modularRigQuery.ToEntityArray(Allocator.Temp);
var ecb = new EntityCommandBuffer(Allocator.Temp);
for (var i = 0; i < entities.Length; ++i)
{
var e = entities[i];
var mrcBuf = em.GetBuffer<ModularRigPartComponent>(e);
for (var k = 0; k < mrcBuf.Length; ++k)
{
ref var mrc = ref mrcBuf.ElementAt(k);
if (mrc.bodyPart == mbp)
{
var prevIdx = mrc.currentPartIndex;
var nextIdx = (mrc.currentPartIndex + 1) % mrc.partsList.Length;
SetSkinnedMeshEnabled(mrc.partsList[prevIdx], ecb, false);
SetSkinnedMeshEnabled(mrc.partsList[nextIdx], ecb, true);
mrc.currentPartIndex = nextIdx;
}
}
}
ecb.Playback(em);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0a5fbecafb27be84f81766e559ee4e53
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UIController_RuntimeSkinnedMeshSwitch.cs
uploadId: 897522
@@ -0,0 +1,30 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UILabelSetter_AnimationCulling: MonoBehaviour
{
public TextMeshProUGUI floatParam1Label;
public Slider floatParam1Slider;
public static UILabelSetter_AnimationCulling Instance { get; private set; }
/////////////////////////////////////////////////////////////////////////////////
void Awake()
{
Instance = this;
}
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
floatParam1Label.text = $"{floatParam1Slider.value:F2}";
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 9496eced063f387478471c37723ad099
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UILabelSetter_AnimationCulling.cs
uploadId: 897522
@@ -0,0 +1,24 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UILabelSetter_AnimatorParameters: MonoBehaviour
{
public TextMeshProUGUI moveSpeedLabel;
public TextMeshProUGUI selectAnimationLabel;
public Slider moveSpeedSlider;
public Slider selectAnimationSlider;
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
moveSpeedLabel.text = $"Animation Speed (float): {moveSpeedSlider.value:F2}f";
selectAnimationLabel.text = $"Select Animation (int): {selectAnimationSlider.value}";
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: bd1876f81da64364d85f6b7a2afd4602
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UILabelSetter_AnimatorParameters.cs
uploadId: 897522
@@ -0,0 +1,81 @@
using TMPro;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UILabelSetter_AnimatorStateQuery: MonoBehaviour
{
public TextMeshProUGUI stateInfoLabel;
public TextMeshProUGUI transitionInfoLabel;
public TextMeshProUGUI sampleDescription;
EntityManager em;
EntityQuery animatorsQuery;
/////////////////////////////////////////////////////////////////////////////////
void Start()
{
var worlds = World.All;
foreach (var w in worlds)
{
if (RukhankaSystemsBootstrap.IsClientOrLocalSimulationWorld(w))
{
em = w.EntityManager;
break;
}
}
var ecb0 = new EntityQueryBuilder(Allocator.Temp)
.WithAll<AnimatorControllerLayerComponent>();
animatorsQuery = em.CreateEntityQuery(ecb0);
#if !RUKHANKA_DEBUG_INFO
sampleDescription.text += " Define <color=red>RUKHANKA_DEBUG_INFO</color> script symbol to view state and transition names.";
#endif
}
/////////////////////////////////////////////////////////////////////////////////
void OnDestroy()
{
}
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
var animatedEntites = animatorsQuery.ToEntityArray(Allocator.Temp);
if (animatedEntites.Length > 0)
{
var e = animatedEntites[0];
var aclc = em.GetBuffer<AnimatorControllerLayerComponent>(e);
var a = new AnimatorStateQueryAspect(aclc);
var stateInfo = a.GetLayerCurrentStateInfo(0);
var transitionInfo = a.GetLayerCurrentTransitionInfo(0);
#if RUKHANKA_DEBUG_INFO
stateInfoLabel.text = $"<color=green>Current State:</color> name <color=green>'{stateInfo.name}'</color>, hash <color=green>'{stateInfo.hash}'</color>, and time <color=#ff4500>'{stateInfo.normalizedTime:F2}'</color>";
#else
stateInfoLabel.text = $"<color=green>Current State</color>: hash <color=green>'{stateInfo.hash}'</color>, and time <color=#ff4500>'{stateInfo.normalizedTime:F2}'</color>";
#endif
if (transitionInfo.hash != 0)
#if RUKHANKA_DEBUG_INFO
transitionInfoLabel.text = $"<color=blue>Current Transition:</color> name <color=blue>'{transitionInfo.name}'</color>, hash <color=blue>'{transitionInfo.hash}'</color> and time <color=#ff4500>'{transitionInfo.normalizedTime:F2}'</color>";
#else
transitionInfoLabel.text = $"<color=blue>Current Transition:</color> hash <color=blue>'{transitionInfo.hash}'</color> and time <color=#ff4500>'{transitionInfo.normalizedTime:F2}'</color>";
#endif
else
transitionInfoLabel.text = $"<color=blue>Not in transition</color>";
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: e48687f2ff02d084c9a8e92fc952a289
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UILabelSetter_AnimatorStateQuery.cs
uploadId: 897522
@@ -0,0 +1,40 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UILabelSetter_BlendTreeShowcase: MonoBehaviour
{
public TextMeshProUGUI floatParam1Label;
public TextMeshProUGUI floatParam2Label;
public Slider floatParam1Slider;
public Slider floatParam2Slider;
public int mode;
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
// Direct
if (mode == 0)
{
floatParam1Label.text = $"First Animation Weight: {floatParam1Slider.value:F2}f";
floatParam2Label.text = $"Second Animation Weight: {floatParam2Slider.value:F2}f";
}
// 1D
else if (mode == 1)
{
floatParam1Label.text = $"Blend Tree Parameter: {floatParam1Slider.value:F2}f";
}
// 2D Simple Directional
else
{
floatParam1Label.text = $"Blend Tree Parameter X: {floatParam1Slider.value:F2}f";
floatParam2Label.text = $"Blend Tree Parameter Y: {floatParam2Slider.value:F2}f";
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3e07523f22290584086bcdf0952f0031
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UILabelSetter_BlendTreeShowcase.cs
uploadId: 897522
@@ -0,0 +1,66 @@
using TMPro;
using UnityEditor;
#if UNITY_EDITOR
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
#endif
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UILabelSetter_CharacterController: MonoBehaviour
{
public TextMeshProUGUI textElement;
public Button installCharacterControllerBtn;
public GameObject netcodeRemoveWarning;
#if UNITY_EDITOR
static AddRequest Request;
#endif
/////////////////////////////////////////////////////////////////////////////////
void Awake()
{
#if !RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
installCharacterControllerBtn.gameObject.SetActive(true);
textElement.text += "\n\n <color=red>Warning</color>: The Unity Character Controller package is not installed but is required for the proper functioning of this sample. Click the Install Character Controller button to install it.";
#else
installCharacterControllerBtn.gameObject.SetActive(false);
#endif
#if RUKHANKA_SAMPLES_WITH_NETCODE && RUKHANKA_SAMPLES_WITH_PHYSICS
netcodeRemoveWarning.gameObject.SetActive(true);
#endif
}
/////////////////////////////////////////////////////////////////////////////////
public void ImportCharacterControllerPackage()
{
#if UNITY_EDITOR
EditorApplication.isPlaying = false;
Request = Client.Add("com.unity.charactercontroller");
EditorApplication.update += Progress;
#endif
}
/////////////////////////////////////////////////////////////////////////////////
#if UNITY_EDITOR
static void Progress()
{
if (Request.IsCompleted)
{
if (Request.Status == StatusCode.Success)
Debug.Log("Installed: " + Request.Result.packageId);
else if (Request.Status >= StatusCode.Failure)
Debug.Log(Request.Error.message);
EditorApplication.update -= Progress;
}
}
#endif
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d465d4d42a2fd2641ab23f4edc7fc2f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UILabelSetter_CharacterController.cs
uploadId: 897522
@@ -0,0 +1,49 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UILabelSetter_IK: MonoBehaviour
{
public TextMeshProUGUI floatParam1Label;
public TextMeshProUGUI floatParam2Label;
public TextMeshProUGUI floatParam3Label;
public Slider floatParam1Slider;
public Slider floatParam2Slider;
public Slider floatParam3Slider;
public int mode;
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
// Aim
if (mode == 0)
{
floatParam1Label.text = $"Weight: {floatParam1Slider.value:F2}f";
}
// Override
else if (mode == 1)
{
floatParam1Label.text = $"Position Weight: {floatParam1Slider.value:F2}f";
floatParam2Label.text = $"Rotation Weight: {floatParam2Slider.value:F2}f";
}
// FABRIK
else if (mode == 2)
{
floatParam1Label.text = $"Ellen Right Hand IK Weight: {floatParam1Slider.value:F2}f";
floatParam2Label.text = $"Ellen Left Leg IK Weight: {floatParam2Slider.value:F2}f";
floatParam3Label.text = $"Snake Tail IK Weight: {floatParam3Slider.value:F2}f";
}
// FABRIK
else if (mode == 3)
{
floatParam2Label.text = $"Right Leg IK Weight: {floatParam2Slider.value:F2}f";
floatParam3Label.text = $"Left Leg IK Weight: {floatParam3Slider.value:F2}f";
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: bcf919972bd2d1a459d335a3a1f543d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UILabelSetter_IK.cs
uploadId: 897522
@@ -0,0 +1,100 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class UILabelSetter_ScriptedAnimator: MonoBehaviour
{
public TextMeshProUGUI singleAnimClipTimeLabel;
public Slider singleAnimClipTimeSlider;
public TextMeshProUGUI singleAnimClipWeightLabel;
public Slider singleAnimClipWeightSlider;
public TextMeshProUGUI weightLabel;
public GameObject animation1Selector;
public Button singleAnimBtn;
public Button animationBlendingBtn;
public static UILabelSetter_ScriptedAnimator Instance { get; private set; }
/////////////////////////////////////////////////////////////////////////////////
void Awake()
{
Instance = this;
SetColors(singleAnimBtn, animationBlendingBtn);
}
/////////////////////////////////////////////////////////////////////////////////
void Update()
{
singleAnimClipTimeLabel.text = $"{singleAnimClipTimeSlider.value:F2}";
singleAnimClipWeightLabel.text = $"{singleAnimClipWeightSlider.value:F2}";
}
/////////////////////////////////////////////////////////////////////////////////
public void ManualTimeControlChange(bool on)
{
singleAnimClipTimeSlider.interactable = on;
ScriptedAnimatorSampleConf.Instance.manualTimeControl = on;
}
/////////////////////////////////////////////////////////////////////////////////
public void Animation0Change(int index)
{
ScriptedAnimatorSampleConf.Instance.animationIndices.x = index;
}
/////////////////////////////////////////////////////////////////////////////////
public void Animation1Change(int index)
{
ScriptedAnimatorSampleConf.Instance.animationIndices.y = index;
}
/////////////////////////////////////////////////////////////////////////////////
void SetColors(Button b0, Button b1)
{
var c = Color.cyan;
var colors = b0.colors;
colors.normalColor = c;
colors.highlightedColor = c;
colors.selectedColor = c;
b0.colors = colors;
c = Color.white;
colors = b1.colors;
colors.normalColor = c;
colors.highlightedColor = c;
colors.selectedColor = c;
b1.colors = colors;
}
/////////////////////////////////////////////////////////////////////////////////
public void AnimationBlendingClick()
{
ScriptedAnimatorSampleConf.Instance.doBlending = true;
weightLabel.text = "Blend Factor";
animation1Selector.SetActive(true);
SetColors(animationBlendingBtn, singleAnimBtn);
}
/////////////////////////////////////////////////////////////////////////////////
public void SingleAnimationClick()
{
ScriptedAnimatorSampleConf.Instance.doBlending = false;
weightLabel.text = "Clip Weight";
animation1Selector.SetActive(false);
SetColors(singleAnimBtn, animationBlendingBtn);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ab1b483b82586ea4cbba2f3d457d953e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/UI/UILabelSetter_ScriptedAnimator.cs
uploadId: 897522