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,53 @@
using Unity.Entities;
using UnityEngine;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public class BoneMarkerAuthoring: MonoBehaviour
{
public enum BoneID
{
EllenLeftLeg,
EllenRightLeg,
EllenLeftFoot,
EllenRightFoot,
EllenLeftHand,
EllenRightHand,
SnakeStartBone
}
public BoneID boneID;
}
/////////////////////////////////////////////////////////////////////////////////
public struct EllenLeftLegTag: IComponentData{}
public struct EllenRightLegTag: IComponentData{}
public struct EllenLeftFootTag: IComponentData{}
public struct EllenRightFootTag: IComponentData{}
public struct EllenRightHandTag: IComponentData{}
public struct EllenLeftHandTag: IComponentData{}
public struct SnakeTag: IComponentData{}
/////////////////////////////////////////////////////////////////////////////////
public class BoneMarkerBaker : Baker<BoneMarkerAuthoring>
{
public override void Bake(BoneMarkerAuthoring a)
{
var e = GetEntity(a, TransformUsageFlags.Dynamic);
switch (a.boneID)
{
case BoneMarkerAuthoring.BoneID.EllenLeftLeg: AddComponent<EllenLeftLegTag>(e); break;
case BoneMarkerAuthoring.BoneID.EllenRightLeg: AddComponent<EllenRightLegTag>(e); break;
case BoneMarkerAuthoring.BoneID.EllenLeftFoot: AddComponent<EllenLeftFootTag>(e); break;
case BoneMarkerAuthoring.BoneID.EllenRightFoot: AddComponent<EllenRightFootTag>(e); break;
case BoneMarkerAuthoring.BoneID.EllenLeftHand: AddComponent<EllenLeftHandTag>(e); break;
case BoneMarkerAuthoring.BoneID.EllenRightHand: AddComponent<EllenRightHandTag>(e); break;
case BoneMarkerAuthoring.BoneID.SnakeStartBone: AddComponent<SnakeTag>(e); break;
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a64a093eb1149d8459a1b6d439145d9c
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/BoneMarkerAuthoring.cs
uploadId: 897522
@@ -0,0 +1,55 @@
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
/////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.LocalSimulation | WorldSystemFilterFlags.ClientSimulation)]
partial class DistanceBasedMixedModeAnimatorSystem: SystemBase
{
public float switchDistance;
/////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
[WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)]
partial struct AnimatorSwitchJob: IJobEntity
{
public float3 refPose;
public float switchDistance;
void Execute(EnabledRefRW<GPUAnimationEngineTag> gt, in LocalTransform lt)
{
var dv = refPose - lt.Position;
var d = math.length(dv);
gt.ValueRW = d > switchDistance;
}
}
/////////////////////////////////////////////////////////////////////////////////
protected override void OnCreate()
{
Enabled = false;
}
/////////////////////////////////////////////////////////////////////////////////
protected override void OnUpdate()
{
var switchJob = new AnimatorSwitchJob()
{
refPose = Camera.main.transform.position,
switchDistance = switchDistance
};
switchJob.ScheduleParallel();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d242ab3781946e144bd6525eef027128
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/DistanceBasedMixedAnimatorSystem.cs
uploadId: 897522
@@ -0,0 +1,17 @@
using UnityEditor;
using UnityEngine;
namespace Rukhanka.Samples
{
#if !ENABLE_INPUT_SYSTEM
[InitializeOnLoad]
class InputSystemWarning
{
static InputSystemWarning()
{
Debug.LogWarning("Warning: The Rukhanka Samples use the \"Input System\" package for input handling. Input will not work until the \"Input System\" package has been imported.");
}
}
#endif
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 0c404e3323b431047bf9ac9a8914ad89
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scripts/InputSystemWarning.cs
uploadId: 897522
@@ -0,0 +1,199 @@
using System;
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.UI;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public struct InputStateData
{
public float floatParam1;
public float floatParam2;
public float floatParam3;
public int intParam1;
public bool boolParam1;
public bool triggerParam1;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[WorldSystemFilter(WorldSystemFilterFlags.LocalSimulation | WorldSystemFilterFlags.ClientSimulation)]
[UpdateBefore(typeof(RukhankaAnimationSystemGroup))]
[RequireMatchingQueriesForUpdate]
public partial class PlayerControllerSystem: SystemBase
{
static readonly string floatParam1Name = "FloatParam1";
static FastAnimatorParameter floatParam1 = new (floatParam1Name);
static readonly string floatParam2Name = "FloatParam2";
static FastAnimatorParameter floatParam2 = new (floatParam2Name);
static readonly string floatParam3Name = "FloatParam3";
static FastAnimatorParameter floatParam3 = new (floatParam3Name);
static readonly string intParam1Name = "IntParam1";
static FastAnimatorParameter intParam1 = new (intParam1Name);
static readonly string boolParam1Name = "BoolParam1";
static FastAnimatorParameter boolParam1 = new (boolParam1Name);
static readonly string triggerParam1Name = "TriggerParam1";
static FastAnimatorParameter triggerParam1 = new (triggerParam1Name);
Animator[] managedAnimators;
bool trigger1Value;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
partial struct ProcessInputJob: IJobEntity
{
public InputStateData inputData;
public FastAnimatorParameter floatParam3P;
public FastAnimatorParameter floatParam2P;
public FastAnimatorParameter floatParam1P;
public FastAnimatorParameter intParam1P;
public FastAnimatorParameter boolParam1P;
public FastAnimatorParameter triggerParam1P;
void Execute(AnimatorControllerParameterIndexTableComponent indexTable, DynamicBuffer<AnimatorControllerParameterComponent> parametersArr)
{
var paramAspect = new AnimatorParametersAspect(parametersArr, indexTable);
if (paramAspect.HasParameter(floatParam1P))
paramAspect.SetParameterValue(floatParam1P, inputData.floatParam1);
if (paramAspect.HasParameter(floatParam2P))
paramAspect.SetParameterValue(floatParam2P, inputData.floatParam2);
if (paramAspect.HasParameter(floatParam3P))
paramAspect.SetParameterValue(floatParam3P, inputData.floatParam2);
if (paramAspect.HasParameter(intParam1P))
paramAspect.SetParameterValue(intParam1P, inputData.intParam1);
if (paramAspect.HasParameter(boolParam1P))
paramAspect.SetParameterValue(boolParam1P, inputData.boolParam1);
if (inputData.triggerParam1)
paramAspect.SetParameterValue(triggerParam1P, inputData.triggerParam1);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected override void OnStartRunning()
{
base.OnStartRunning();
var setTriggerBtn = GameObject.Find(triggerParam1Name);
if (setTriggerBtn != null)
{
setTriggerBtn.GetComponent<Button>().onClick.AddListener(SetTriggerButtonClick);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void SetTriggerButtonClick()
{
trigger1Value = true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
InputStateData GatherInput()
{
var floatParam1Slider = GameObject.Find(floatParam1Name);
var floatParam1Value = 0.0f;
if (floatParam1Slider != null)
floatParam1Value = floatParam1Slider.GetComponent<Slider>().value;
var floatParam2Value = 0.0f;
var floatParam2Slider = GameObject.Find(floatParam2Name);
if (floatParam2Slider != null)
floatParam2Value = floatParam2Slider.GetComponent<Slider>().value;
var floatParam3Slider = GameObject.Find(floatParam3Name);
var floatParam3Value = 0.0f;
if (floatParam3Slider != null)
floatParam3Value = floatParam3Slider.GetComponent<Slider>().value;
int intParam1Value = 0;
var intSlider1 = GameObject.Find(intParam1Name);
if (intSlider1 != null)
intParam1Value = (int)intSlider1.GetComponent<Slider>().value;
bool boolParam1Value = false;
var boolToggle = GameObject.Find(boolParam1Name);
if (boolToggle != null)
boolParam1Value = boolToggle.GetComponent<Toggle>().isOn;
var rv = new InputStateData();
if (math.any(new float2(floatParam1Value, floatParam2Value)))
{
rv.floatParam1 = floatParam1Value;
rv.floatParam2 = floatParam2Value;
}
rv.floatParam3 = floatParam3Value;
rv.intParam1 = intParam1Value;
rv.triggerParam1 = trigger1Value;
rv.boolParam1 = boolParam1Value;
trigger1Value = false;
return rv;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ControlUnityManagedAnimatorControllers(in InputStateData isd)
{
if (managedAnimators == null)
managedAnimators = GameObject.FindObjectsByType<Animator>(FindObjectsSortMode.None);
for (int i = 0; i < managedAnimators.Length; ++i)
{
var a = managedAnimators[i];
if (a.runtimeAnimatorController == null || !a.isInitialized)
continue;
if (Array.FindIndex(a.parameters, x => x.name == boolParam1Name) >= 0)
a.SetBool(boolParam1Name, isd.boolParam1);
if (Array.FindIndex(a.parameters, x => x.name == triggerParam1Name) >= 0 && isd.triggerParam1)
a.SetTrigger(triggerParam1Name);
if (Array.FindIndex(a.parameters, x => x.name == floatParam1Name) >= 0)
a.SetFloat(floatParam1Name, isd.floatParam1);
if (Array.FindIndex(a.parameters, x => x.name == floatParam2Name) >= 0)
a.SetFloat(floatParam2Name, isd.floatParam2);
if (Array.FindIndex(a.parameters, x => x.name == floatParam3Name) >= 0)
a.SetFloat(floatParam3Name, isd.floatParam3);
if (Array.FindIndex(a.parameters, x => x.name == intParam1Name) >= 0)
a.SetInteger(intParam1Name, isd.intParam1);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
protected override void OnUpdate()
{
var inputData = GatherInput();
ControlUnityManagedAnimatorControllers(inputData);
var processInputJob = new ProcessInputJob()
{
inputData = inputData,
floatParam1P = floatParam1,
floatParam2P = floatParam2,
floatParam3P = floatParam3,
intParam1P = intParam1,
triggerParam1P = triggerParam1,
boolParam1P = boolParam1
};
Dependency = processInputJob.ScheduleParallel(Dependency);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 48148c92e188f8d46b009f9d902bd27d
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/PlayerControllerSystem.cs
uploadId: 897522
@@ -0,0 +1,92 @@
using Unity.Entities;
#if RUKHANKA_WITH_NETCODE
using Unity.NetCode;
#endif
using UnityEngine;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public class PrefabSpawner: MonoBehaviour
{
public GameObject[] prefabPool;
public int count;
public float spawnRadius;
public float spawnDelayInSeconds;
public bool spawnUnityObjects;
public bool initialSpawn;
void Start()
{
if (spawnUnityObjects)
Spawn();
}
public void Spawn()
{
for (int i = 0; i < prefabPool.Length; ++i)
{
var scc = new SpawnCommandComponent() { spawnCount = count / prefabPool.Length };
var p = prefabPool[i];
for (int l = 0; l < scc.spawnCount; ++l)
{
var g = GameObject.Instantiate(p);
var randomPos = new Vector2(Random.value, Random.value) * 2 - new Vector2(1, 1);
var position = new Vector3(randomPos.x, 0, randomPos.y) * spawnRadius;
var rot = Quaternion.Euler(new Vector3(0, Random.value * 360, 9));
g.transform.position += position;
g.transform.rotation = rot;
var a = g.GetComponent<Animator>();
var randomSpeedVal = (Random.value * 2 - 1) * 0.5f + 1;
a.SetFloat("Crowd_AnimationSpeed", randomSpeedVal);
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class PrefabSpawnerBaker: Baker<PrefabSpawner>
{
public override void Bake(PrefabSpawner a)
{
for (int i = 0; i < a.prefabPool.Length; ++i)
{
var p = a.prefabPool[i];
var spc = new SpawnPrefabComponent()
{
prefabToSpawn = GetEntity(p, TransformUsageFlags.Dynamic),
spawnRadius = a.spawnRadius,
};
var scc = new SpawnCommandComponent()
{
spawnCount = a.count / a.prefabPool.Length,
spawnTime = Time.time + a.spawnDelayInSeconds,
spawnerPos = a.transform.position,
boneVisualizationOn = true
};
if (!a.spawnUnityObjects)
{
var e = CreateAdditionalEntity(TransformUsageFlags.Dynamic);
AddComponent(e, spc);
if (a.initialSpawn)
AddComponent(e, scc);
#if RUKHANKA_WITH_NETCODE
if (p.GetComponent<GhostAuthoringComponent>() != null)
{
var netObjTag = default(NetworkedPrefab);
AddComponent(e, netObjTag);
}
#endif
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0408dc75808163c4680839a70c050711
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/PrefabSpawner.cs
uploadId: 897522
@@ -0,0 +1,101 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using static Unity.Entities.SystemAPI;
using Random = Unity.Mathematics.Random;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public struct SpawnPrefabComponent: IComponentData
{
public Entity prefabToSpawn;
public float spawnRadius;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public struct SpawnCommandComponent: IComponentData
{
public int spawnCount;
public float spawnTime;
public float3 spawnerPos;
public bool boneVisualizationOn;
public bool gpuAnimator;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public struct NetworkedPrefab: IComponentData {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
[WorldSystemFilter(WorldSystemFilterFlags.LocalSimulation | WorldSystemFilterFlags.ClientSimulation)]
public partial struct PrefabSpawnerSystem: ISystem
{
uint updateCounter;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
public void OnUpdate(ref SystemState ss)
{
var ecbs = GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
var ecb = ecbs.CreateCommandBuffer(ss.WorldUnmanaged);
FastAnimatorParameter animSpeed = new FastAnimatorParameter("Crowd_AnimationSpeed");
var t = SystemAPI.Time.ElapsedTime;
foreach (var (p0, _, sc, e) in Query<RefRW<SpawnPrefabComponent>, RefRO<LocalTransform>, RefRO<SpawnCommandComponent>>()
.WithNone<NetworkedPrefab>()
.WithEntityAccess())
{
var spc = p0.ValueRO;
var scc = sc.ValueRO;
if (scc.spawnTime > t)
continue;
var instances = ss.EntityManager.Instantiate(spc.prefabToSpawn, sc.ValueRO.spawnCount, Allocator.Temp);
var random = Random.CreateFromIndex(updateCounter++);
foreach (var entity in instances)
{
var randomPos = random.NextFloat2() * 2 - 1;
var position = new float3(randomPos.x, 0, randomPos.y) * spc.spawnRadius;
var rot = quaternion.RotateY(random.NextFloat() * math.PI * 2);
var transform = ss.EntityManager.GetComponentData<LocalTransform>(entity);
transform.Position += position + scc.spawnerPos;
transform.Rotation = rot;
ss.EntityManager.SetComponentData(entity, transform);
if (scc.boneVisualizationOn)
ecb.AddComponent<BoneVisualizationComponent>(entity);
else
ecb.RemoveComponent<BoneVisualizationComponent>(entity);
if (ss.EntityManager.HasComponent<GPUAnimationEngineTag>(entity))
ss.EntityManager.SetComponentEnabled<GPUAnimationEngineTag>(entity, scc.gpuAnimator);
if (HasComponent<AnimatorControllerParameterIndexTableComponent>(entity) && HasBuffer<AnimatorControllerParameterComponent>(entity))
{
var acpitc = GetComponent<AnimatorControllerParameterIndexTableComponent>(entity);
var acpc = GetBuffer<AnimatorControllerParameterComponent>(entity);
var apa = new AnimatorParametersAspect(acpc, acpitc);
var randomSpeedVal = (random.NextFloat() * 2 - 1) * 0.5f + 1;
if (apa.HasParameter(animSpeed))
apa.SetParameterValue(animSpeed, randomSpeedVal);
}
ecb.RemoveComponent<SpawnCommandComponent>(e);
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 4094f3e67fb5a454d8dc1e87c82094bd
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/PrefabSpawnerSystem.cs
uploadId: 897522
@@ -0,0 +1,46 @@
using System;
using UnityEngine;
///////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
class SimpleCameraDollyCart: MonoBehaviour
{
public Transform cart;
public float speed;
public Transform[] points;
public Transform lookTarget;
int nextPointIndex;
///////////////////////////////////////////////////////////////////////////////////////////
void Update()
{
var curPos = cart.position;
var nextPoint = points[nextPointIndex].position;
var v = nextPoint - curPos;
var dp = v.normalized * Time.deltaTime * speed;
var newCurPos = curPos + dp;
if (v.magnitude < dp.magnitude)
{
nextPointIndex = (nextPointIndex + 1) % points.Length;
}
cart.transform.LookAt(lookTarget);
cart.position = newCurPos;
}
///////////////////////////////////////////////////////////////////////////////////////////
void OnDrawGizmosSelected()
{
for (var i = 0; i < points.Length; ++i)
{
var pa = points[i].position;
var pb = points[(i + 1) % points.Length].position;
Debug.DrawLine(pa, pb, Color.cyan);
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: b90b8475c075cd141939e91a3e1b0936
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/SimpleCameraDollyCart.cs
uploadId: 897522
@@ -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