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,172 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using Unity.Burst;
using Unity.CharacterController;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Systems;
using Unity.Transforms;
using UnityEngine;
using Random = Unity.Mathematics.Random;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
[BurstCompile]
partial struct CharacterControllerSystem: ISystem
{
static readonly FastAnimatorParameter groundedParam = new ("Grounded");
static readonly FastAnimatorParameter verticalSpeedParam = new ("VerticalSpeed");
static readonly FastAnimatorParameter airbornVerticalSpeedParam = new ("AirborneVerticalSpeed");
static readonly FastAnimatorParameter forwardSpeedParam = new ("ForwardSpeed");
static readonly FastAnimatorParameter inputDetectedParam = new ("InputDetected");
static readonly FastAnimatorParameter angleDeltaRadParam = new ("AngleDeltaRad");
static readonly FastAnimatorParameter randomIdleParam = new ("RandomIdle");
Random rng;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void OnCreate(ref SystemState ss)
{
rng = new Random(0xabcabc01);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float DeltaAngle(float current, float target)
{
float num = Mathf.Repeat(target - current, math.PI * 2);
if (num > math.PI)
num -= math.PI * 2;
return num;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void OnUpdate(ref SystemState ss)
{
foreach (var (kcb, acpitc, acpc, lt, tpcc) in SystemAPI.Query<
RefRO<KinematicCharacterBody>,
AnimatorControllerParameterIndexTableComponent,
DynamicBuffer<AnimatorControllerParameterComponent>,
LocalTransform,
ThirdPersonCharacterControl
>())
{
var apa = new AnimatorParametersAspect(acpc, acpitc);
var isGrounded = kcb.ValueRO.IsGrounded;
apa.SetBoolParameter(groundedParam, isGrounded);
var vertSpeed = math.select(0, kcb.ValueRO.RelativeVelocity.y, isGrounded);
var airborneVertSpeed = kcb.ValueRO.RelativeVelocity.y;
apa.SetFloatParameter(verticalSpeedParam, vertSpeed);
if (!isGrounded)
apa.SetFloatParameter(airbornVerticalSpeedParam, airborneVertSpeed);
var fwdSpeed = math.length(kcb.ValueRO.RelativeVelocity);
apa.SetFloatParameter(forwardSpeedParam, fwdSpeed);
var curAngle = math.atan2(lt.Forward().x, lt.Forward().z);
var targetAngle = math.atan2(kcb.ValueRO.RelativeVelocity.x, kcb.ValueRO.RelativeVelocity.z);
var deltaAngle = DeltaAngle(curAngle, targetAngle);
apa.SetFloatParameter(angleDeltaRadParam, deltaAngle);
// Attack
var randomVal = rng.NextInt(0, 3);
apa.SetIntParameter(randomIdleParam, randomVal);
var inputDetected = math.length(tpcc.MoveVector) > 0;
apa.SetBoolParameter(inputDetectedParam, inputDetected);
}
}
}
//----------------------------------------------------------------------------------------------------------------//
[UpdateInGroup(typeof(PhysicsSimulationGroup))]
[UpdateBefore(typeof(PhysicsCreateJacobiansGroup))]
[UpdateAfter(typeof(PhysicsCreateContactsGroup))]
[RequireMatchingQueriesForUpdate]
public partial struct HandleCannonballHitsSystem: ISystem
{
static readonly FastAnimatorParameter hurtParam = new ("Hurt");
static readonly FastAnimatorParameter hurtFromXParam = new ("HurtFromX");
static readonly FastAnimatorParameter hurtFromYParam = new ("HurtFromY");
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
private struct HandleCannonballCollisionsJob : IContactsJob
{
[ReadOnly]
public ComponentLookup<CannonballTag> cannonBallLookup;
[ReadOnly]
public ComponentLookup<AnimatorControllerParameterIndexTableComponent> indexTableComponentLookup;
[ReadOnly]
public ComponentLookup<LocalTransform> localTransformLookup;
public BufferLookup<AnimatorControllerParameterComponent> parametersLookup;
public EntityCommandBuffer ecb;
public FastAnimatorParameter hurtFromXParam;
public FastAnimatorParameter hurtFromYParam;
public FastAnimatorParameter hurtParam;
public void Execute(ref ModifiableContactHeader header, ref ModifiableContactPoint point)
{
var cannonballEntity = Entity.Null;
if (cannonBallLookup.HasComponent(header.EntityA))
cannonballEntity = header.EntityA;
if (cannonBallLookup.HasComponent(header.EntityB))
cannonballEntity = header.EntityB;
var characterEntity = Entity.Null;
if (parametersLookup.HasBuffer(header.EntityA))
characterEntity = header.EntityA;
if (parametersLookup.HasBuffer(header.EntityB))
characterEntity = header.EntityB;
if (cannonballEntity == Entity.Null || characterEntity == Entity.Null)
return;
parametersLookup.TryGetBuffer(characterEntity, out var animationParamBuffer);
var paramsIndexTable = indexTableComponentLookup.GetRefRO(characterEntity).ValueRO;
var apa = new AnimatorParametersAspect(animationParamBuffer, paramsIndexTable);
var lt = localTransformLookup.GetRefRO(characterEntity).ValueRO;
var hitNormalLocalSpace = -math.rotate(math.inverse(lt.Rotation), header.Normal);
apa.SetTrigger(hurtParam);
apa.SetFloatParameter(hurtFromXParam, math.sign(hitNormalLocalSpace.x));
apa.SetFloatParameter(hurtFromYParam, math.sign(hitNormalLocalSpace.z));
ecb.RemoveComponent<CannonballTag>(cannonballEntity);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void OnUpdate(ref SystemState ss)
{
PhysicsWorld physicsWorld = SystemAPI.GetSingletonRW<PhysicsWorldSingleton>().ValueRW.PhysicsWorld;
SimulationSingleton simulationSingleton = SystemAPI.GetSingleton<SimulationSingleton>();
var ecbs = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
var ecb = ecbs.CreateCommandBuffer(ss.WorldUnmanaged);
var handleCollisionJob = new HandleCannonballCollisionsJob()
{
hurtParam = hurtParam,
hurtFromXParam = hurtFromXParam,
hurtFromYParam = hurtFromYParam,
parametersLookup = SystemAPI.GetBufferLookup<AnimatorControllerParameterComponent>(),
indexTableComponentLookup = SystemAPI.GetComponentLookup<AnimatorControllerParameterIndexTableComponent>(true),
cannonBallLookup = SystemAPI.GetComponentLookup<CannonballTag>(true),
localTransformLookup = SystemAPI.GetComponentLookup<LocalTransform>(true),
ecb = ecb
};
ss.Dependency = handleCollisionJob.Schedule(simulationSingleton, ref physicsWorld, ss.Dependency);
}
}
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 260a3082491ab3b4eb85c1778ce8ea16
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/25. Character Controller/Scripts/CharacterController.cs
uploadId: 897522
@@ -0,0 +1,90 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.InputSystem;
using Random = Unity.Mathematics.Random;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public struct SimpleCannonComponent: IComponentData
{
public float distanceFromTarget;
public float startSpeed;
public Entity cannonBallPrefab;
public Entity targetEntity;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[BurstCompile]
public partial struct SimpleCannonSystem: ISystem
{
Random rng;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void OnCreate(ref SystemState ss)
{
rng = new Random(0x12312313);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
float3 GetWorldPosition(ref SystemState ss, Entity e)
{
var targetPose = SystemAPI.GetComponent<LocalTransform>(e);
var bt = new BoneTransform(targetPose);
while (SystemAPI.HasComponent<Parent>(e))
{
var pe = SystemAPI.GetComponent<Parent>(e);
var parentPose = SystemAPI.GetComponent<LocalTransform>(pe.Value);
var pbt = new BoneTransform(parentPose);
bt = BoneTransform.Multiply(pbt, bt);
e = pe.Value;
}
return bt.pos;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void OnUpdate(ref SystemState ss)
{
if (!Keyboard.current.fKey.wasPressedThisFrame)
return;
var ecbs = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
var ecb = ecbs.CreateCommandBuffer(ss.WorldUnmanaged);
foreach (var (ccc, _) in SystemAPI.Query<SimpleCannonComponent>().WithEntityAccess())
{
var targetPos = GetWorldPosition(ref ss, ccc.targetEntity);
var randomDir = rng.NextFloat3Direction();
randomDir.y = randomDir.y * 0.5f + 0.5f;
var cannonEntity = ss.EntityManager.Instantiate(ccc.cannonBallPrefab);
var l2w = new LocalTransform()
{
Position = targetPos + randomDir * ccc.distanceFromTarget,
Rotation = quaternion.identity,
Scale = 1
};
var pv = new PhysicsVelocity()
{
Angular = float3.zero,
Linear = -randomDir * ccc.startSpeed
};
SystemAPI.SetComponent(cannonEntity, pv);
SystemAPI.SetComponent(cannonEntity, l2w);
ecb.AddComponent<CannonballTag>(cannonEntity);
}
}
}
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: f7287c3475c299c4ca20d5d7082e0f43
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/25. Character Controller/Scripts/SimpleCannon.cs
uploadId: 897522
@@ -0,0 +1,39 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using Unity.Entities;
using UnityEngine;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rukhanka.Samples
{
public struct CannonballTag: IComponentData {}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class SimpleCannonAuthoring: MonoBehaviour
{
public GameObject cannonPrefab;
public GameObject target;
public float distanceToTarget;
public float startSpeed;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class SimpleCannonBaker: Baker<SimpleCannonAuthoring>
{
public override void Bake(SimpleCannonAuthoring a)
{
var ccc = new SimpleCannonComponent()
{
cannonBallPrefab = GetEntity(a.cannonPrefab, TransformUsageFlags.Dynamic),
targetEntity = GetEntity(a.target, TransformUsageFlags.Dynamic),
distanceFromTarget = a.distanceToTarget,
startSpeed = a.startSpeed
};
var e = GetEntity(TransformUsageFlags.None);
AddComponent(e, ccc);
}
}
}
#endif
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 5dd4c79123194344bbe378d8799022f8
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/25. Character Controller/Scripts/SimpleCannonAuthoring.cs
uploadId: 897522
@@ -0,0 +1,16 @@
using Unity.Entities;
using Unity.Transforms;
[UpdateInGroup(typeof(PresentationSystemGroup))]
public partial class MainCameraSystem : SystemBase
{
protected override void OnUpdate()
{
if (MainGameObjectCamera.Instance != null && SystemAPI.HasSingleton<MainEntityCamera>())
{
Entity mainEntityCameraEntity = SystemAPI.GetSingletonEntity<MainEntityCamera>();
LocalToWorld targetLocalToWorld = SystemAPI.GetComponent<LocalToWorld>(mainEntityCameraEntity);
MainGameObjectCamera.Instance.transform.SetPositionAndRotation(targetLocalToWorld.Position, targetLocalToWorld.Rotation);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 7d4fbc2db2fb32d48b168c795a5c3afd
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/Common/Scripts/Camera/MainCameraSystem.cs
uploadId: 897522
@@ -0,0 +1,7 @@
using System;
using Unity.Entities;
[Serializable]
public struct MainEntityCamera : IComponentData
{
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 9680d5663c7e4b24a9308dce893ab885
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/Common/Scripts/Camera/MainEntityCamera.cs
uploadId: 897522
@@ -0,0 +1,15 @@
using UnityEngine;
using Unity.Entities;
[DisallowMultipleComponent]
public class MainEntityCameraAuthoring : MonoBehaviour
{
public class Baker : Baker<MainEntityCameraAuthoring>
{
public override void Bake(MainEntityCameraAuthoring authoring)
{
Entity entity = GetEntity(TransformUsageFlags.Dynamic);
AddComponent<MainEntityCamera>(entity);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 91cffade3faa23640921cbb79b1e6bb0
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/Common/Scripts/Camera/MainEntityCameraAuthoring.cs
uploadId: 897522
@@ -0,0 +1,11 @@
using UnityEngine;
public class MainGameObjectCamera : MonoBehaviour
{
public static Camera Instance;
void Awake()
{
Instance = GetComponent<Camera>();
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ef98a7c3224c6704d976c8bd33dfc59e
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/Common/Scripts/Camera/MainGameObjectCamera.cs
uploadId: 897522
@@ -0,0 +1,29 @@
using Unity.Burst;
using Unity.Entities;
using UnityEngine;
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup), OrderLast = true)]
[BurstCompile]
public partial struct FixedTickSystem : ISystem
{
public struct Singleton : IComponentData
{
public uint Tick;
}
public void OnCreate(ref SystemState state)
{
if (!SystemAPI.HasSingleton<Singleton>())
{
Entity singletonEntity = state.EntityManager.CreateEntity();
state.EntityManager.AddComponentData(singletonEntity, new Singleton());
}
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
ref Singleton singleton = ref SystemAPI.GetSingletonRW<Singleton>().ValueRW;
singleton.Tick++;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d6fbafd4891f00443b6216ceb5e730e2
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/Common/Scripts/FixedTickSystem.cs
uploadId: 897522
@@ -0,0 +1,24 @@
using System;
using UnityEngine;
public struct FixedInputEvent
{
byte m_WasEverSet;
uint m_LastSetTick;
public void Set(uint tick)
{
m_LastSetTick = tick;
m_WasEverSet = 1;
}
public bool IsSet(uint tick)
{
if (m_WasEverSet == 1)
{
return tick == m_LastSetTick;
}
return false;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: b8544c6607fc2464898a9419ad9e6edf
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/Common/Scripts/InputUtilities.cs
uploadId: 897522
@@ -0,0 +1,60 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &7568817337597995144
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7568817337597995142}
- component: {fileID: 7568817337597995143}
m_Layer: 0
m_Name: OrbitCamera
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7568817337597995142
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7568817337597995144}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1.09, z: -3.54}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &7568817337597995143
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7568817337597995144}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 70c323b4be4b1fa4089d1a1fd2872754, type: 3}
m_Name:
m_EditorClassIdentifier:
RotationSpeed: 0.2
MaxVAngle: 89
MinVAngle: -89
RotateWithCharacterParent: 1
StartDistance: 5
MinDistance: 0
MaxDistance: 10
DistanceMovementSpeed: 1
DistanceMovementSharpness: 20
ObstructionRadius: 0.1
ObstructionInnerSmoothingSharpness: 3.4028235e+38
ObstructionOuterSmoothingSharpness: 5
PreventFixedUpdateJitter: 1
IgnoredEntities: []
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 492a184cc1501fe4da86d69b5eddc366
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Prefabs/OrbitCamera.prefab
uploadId: 897522
@@ -0,0 +1,332 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1692896102597148395
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1692896102597148394}
- component: {fileID: 8041698241194078798}
- component: {fileID: 6689285571920954877}
- component: {fileID: 7542772330835976783}
m_Layer: 0
m_Name: ThirdPersonCharacter
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1692896102597148394
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1692896102597148395}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1692896103431116737}
- {fileID: 2861637503494133750}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!136 &8041698241194078798
CapsuleCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1692896102597148395}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 2
m_Radius: 0.5
m_Height: 2
m_Direction: 1
m_Center: {x: 0, y: 1, z: 0}
--- !u!114 &6689285571920954877
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1692896102597148395}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c854a728d43c7cf47bec103607a449f9, type: 3}
m_Name:
m_EditorClassIdentifier:
CharacterProperties:
CustomPhysicsBodyTags:
Tag00: 0
Tag01: 0
Tag02: 0
Tag03: 0
Tag04: 0
Tag05: 0
Tag06: 0
Tag07: 0
InterpolatePosition: 1
InterpolateRotation: 0
EvaluateGrounding: 1
SnapToGround: 1
GroundSnappingDistance: 0.5
EnhancedGroundPrecision: 0
MaxGroundedSlopeAngle: 60
DetectMovementCollisions: 1
DecollideFromOverlaps: 1
ProjectVelocityOnInitialOverlaps: 0
MaxContinuousCollisionsIterations: 8
MaxOverlapDecollisionIterations: 2
DiscardMovementWhenExceedMaxIterations: 1
KillVelocityWhenExceedMaxIterations: 1
DetectObstructionsForParentBodyMovement: 0
SimulateDynamicBody: 1
Mass: 1
RotationSharpness: 25
GroundMaxSpeed: 10
GroundedMovementSharpness: 15
AirAcceleration: 50
AirMaxSpeed: 10
AirDrag: 0
JumpSpeed: 10
Gravity:
x: -0
y: -30
z: -0
PreventAirAccelerationAgainstUngroundedHits: 1
StepAndSlopeHandling:
StepHandling: 0
MaxStepHeight: 0.5
ExtraStepChecksDistance: 0.1
CharacterWidthForStepGroundingCheck: 1
PreventGroundingWhenMovingTowardsNoGrounding: 1
HasMaxDownwardSlopeChangeAngle: 0
MaxDownwardSlopeChangeAngle: 90
ConstrainVelocityToGroundPlane: 1
--- !u!114 &7542772330835976783
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1692896102597148395}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d3a88336df575c34e80048c54a815367, type: 3}
m_Name:
m_EditorClassIdentifier:
Target: {fileID: 2861637503494133753}
--- !u!1 &1692896103431116738
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1692896103431116737}
- component: {fileID: 1692896103431116743}
- component: {fileID: 1692896103431116736}
m_Layer: 0
m_Name: Capsule
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1692896103431116737
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1692896103431116738}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 6498846982015491111}
m_Father: {fileID: 1692896102597148394}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &1692896103431116743
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1692896103431116738}
m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &1692896103431116736
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1692896103431116738}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 257
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 70c3442346d77cb4781288146feb488a, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &2787829476024719926
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6498846982015491111}
- component: {fileID: 6362252827327739790}
- component: {fileID: 1601238720869374913}
m_Layer: 0
m_Name: Cylinder
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6498846982015491111
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2787829476024719926}
m_LocalRotation: {x: -0.70710677, y: -0, z: -0, w: 0.7071068}
m_LocalPosition: {x: 0, y: 0.487, z: 0.357}
m_LocalScale: {x: 0.78007, y: 0.17738, z: 0.34445}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1692896103431116737}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: -90, y: 0, z: 0}
--- !u!33 &6362252827327739790
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2787829476024719926}
m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &1601238720869374913
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2787829476024719926}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 257
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: 70c3442346d77cb4781288146feb488a, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!1 &2861637503494133753
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2861637503494133750}
m_Layer: 0
m_Name: CameraTarget
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2861637503494133750
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2861637503494133753}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1.2, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1692896102597148394}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 5fbcc801dea8fd640a004697d22ed448
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Prefabs/ThirdPersonCharacter.prefab
uploadId: 897522
@@ -0,0 +1,48 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4729649056687684238
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4729649056687684239}
- component: {fileID: 5910332505473654983}
m_Layer: 0
m_Name: ThirdPersonPlayer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4729649056687684239
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4729649056687684238}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5910332505473654983
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4729649056687684238}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3fbdb3174a73a07408595a85d3e7fb6a, type: 3}
m_Name:
m_EditorClassIdentifier:
ControlledCharacter: {fileID: 0}
ControlledCamera: {fileID: 0}
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 65701a63aea96444fa3a4b2ed4edbb25
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 298480
packageName: Rukhanka Animation System 2
packageVersion: 2.9.0
assetPath: Packages/com.rukhanka.animation/Samples~/Samples/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Prefabs/ThirdPersonPlayer.prefab
uploadId: 897522
@@ -0,0 +1,8 @@
using System;
using Unity.Entities;
[Serializable]
public struct CameraTarget : IComponentData
{
public Entity TargetEntity;
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 74ff9a59933a5494bbc1bb465a5f2180
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/OrbitCamera/CameraTarget.cs
uploadId: 897522
@@ -0,0 +1,20 @@
using UnityEngine;
using Unity.Entities;
[DisallowMultipleComponent]
public class CameraTargetAuthoring : MonoBehaviour
{
public GameObject Target;
public class Baker : Baker<CameraTargetAuthoring>
{
public override void Bake(CameraTargetAuthoring authoring)
{
Entity entity = GetEntity(TransformUsageFlags.Dynamic);
AddComponent(entity, new CameraTarget
{
TargetEntity = GetEntity(authoring.Target, TransformUsageFlags.Dynamic),
});
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d3a88336df575c34e80048c54a815367
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/OrbitCamera/CameraTargetAuthoring.cs
uploadId: 897522
@@ -0,0 +1,43 @@
using System;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
[Serializable]
public struct OrbitCamera : IComponentData
{
public float RotationSpeed;
public float MaxVAngle;
public float MinVAngle;
public bool RotateWithCharacterParent;
public float MinDistance;
public float MaxDistance;
public float DistanceMovementSpeed;
public float DistanceMovementSharpness;
public float ObstructionRadius;
public float ObstructionInnerSmoothingSharpness;
public float ObstructionOuterSmoothingSharpness;
public bool PreventFixedUpdateJitter;
public float TargetDistance;
public float SmoothedTargetDistance;
public float ObstructedDistance;
public float PitchAngle;
public float3 PlanarForward;
}
[Serializable]
public struct OrbitCameraControl : IComponentData
{
public Entity FollowedCharacterEntity;
public float2 LookDegreesDelta;
public float ZoomDelta;
}
[Serializable]
public struct OrbitCameraIgnoredEntityBufferElement : IBufferElementData
{
public Entity Entity;
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 441900b2dca2cda429cba5f372fcf5fe
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/OrbitCamera/OrbitCamera.cs
uploadId: 897522
@@ -0,0 +1,76 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using System.Collections.Generic;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
[DisallowMultipleComponent]
public class OrbitCameraAuthoring : MonoBehaviour
{
[Header("Rotation")]
public float RotationSpeed = 2f;
public float MaxVAngle = 89f;
public float MinVAngle = -89f;
public bool RotateWithCharacterParent = true;
[Header("Distance")]
public float StartDistance = 5f;
public float MinDistance = 0f;
public float MaxDistance = 10f;
public float DistanceMovementSpeed = 1f;
public float DistanceMovementSharpness = 20f;
[Header("Obstructions")]
public float ObstructionRadius = 0.1f;
public float ObstructionInnerSmoothingSharpness = float.MaxValue;
public float ObstructionOuterSmoothingSharpness = 5f;
public bool PreventFixedUpdateJitter = true;
[Header("Misc")]
public List<GameObject> IgnoredEntities = new List<GameObject>();
public class Baker : Baker<OrbitCameraAuthoring>
{
public override void Bake(OrbitCameraAuthoring authoring)
{
Entity entity = GetEntity(TransformUsageFlags.Dynamic | TransformUsageFlags.WorldSpace);
AddComponent(entity, new OrbitCamera
{
RotationSpeed = authoring.RotationSpeed,
MaxVAngle = authoring.MaxVAngle,
MinVAngle = authoring.MinVAngle,
RotateWithCharacterParent = authoring.RotateWithCharacterParent,
MinDistance = authoring.MinDistance,
MaxDistance = authoring.MaxDistance,
DistanceMovementSpeed = authoring.DistanceMovementSpeed,
DistanceMovementSharpness = authoring.DistanceMovementSharpness,
ObstructionRadius = authoring.ObstructionRadius,
ObstructionInnerSmoothingSharpness = authoring.ObstructionInnerSmoothingSharpness,
ObstructionOuterSmoothingSharpness = authoring.ObstructionOuterSmoothingSharpness,
PreventFixedUpdateJitter = authoring.PreventFixedUpdateJitter,
TargetDistance = authoring.StartDistance,
SmoothedTargetDistance = authoring.StartDistance,
ObstructedDistance = authoring.StartDistance,
PitchAngle = 0f,
PlanarForward = -math.forward(),
});
AddComponent(entity, new OrbitCameraControl());
DynamicBuffer<OrbitCameraIgnoredEntityBufferElement> ignoredEntitiesBuffer = AddBuffer<OrbitCameraIgnoredEntityBufferElement>(entity);
for (int i = 0; i < authoring.IgnoredEntities.Count; i++)
{
ignoredEntitiesBuffer.Add(new OrbitCameraIgnoredEntityBufferElement
{
Entity = GetEntity(authoring.IgnoredEntities[i], TransformUsageFlags.None),
});
}
}
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 70c323b4be4b1fa4089d1a1fd2872754
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/OrbitCamera/OrbitCameraAuthoring.cs
uploadId: 897522
@@ -0,0 +1,369 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Transforms;
using Unity.CharacterController;
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(ThirdPersonPlayerVariableStepControlSystem))]
[UpdateAfter(typeof(ThirdPersonCharacterVariableUpdateSystem))]
[UpdateBefore(typeof(TransformSystemGroup))]
[BurstCompile]
public partial struct OrbitCameraSimulationSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<OrbitCamera, OrbitCameraControl>().Build());
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
OrbitCameraSimulationJob job = new OrbitCameraSimulationJob
{
DeltaTime = SystemAPI.Time.DeltaTime,
LocalTransformLookup = SystemAPI.GetComponentLookup<LocalTransform>(false),
ParentLookup = SystemAPI.GetComponentLookup<Parent>(true),
PostTransformMatrixLookup = SystemAPI.GetComponentLookup<PostTransformMatrix>(true),
CameraTargetLookup = SystemAPI.GetComponentLookup<CameraTarget>(true),
KinematicCharacterBodyLookup = SystemAPI.GetComponentLookup<KinematicCharacterBody>(true),
};
job.Schedule();
}
[BurstCompile]
[WithAll(typeof(Simulate))]
public partial struct OrbitCameraSimulationJob : IJobEntity
{
public float DeltaTime;
public ComponentLookup<LocalTransform> LocalTransformLookup;
[ReadOnly] public ComponentLookup<Parent> ParentLookup;
[ReadOnly] public ComponentLookup<PostTransformMatrix> PostTransformMatrixLookup;
[ReadOnly] public ComponentLookup<CameraTarget> CameraTargetLookup;
[ReadOnly] public ComponentLookup<KinematicCharacterBody> KinematicCharacterBodyLookup;
void Execute(Entity entity, ref OrbitCamera orbitCamera, in OrbitCameraControl cameraControl)
{
if (OrbitCameraUtilities.TryGetCameraTargetSimulationWorldTransform(
cameraControl.FollowedCharacterEntity,
ref LocalTransformLookup,
ref ParentLookup,
ref PostTransformMatrixLookup,
ref CameraTargetLookup,
out float4x4 targetWorldTransform))
{
float3 targetUp = targetWorldTransform.Up();
float3 targetPosition = targetWorldTransform.Translation();
// Update planar forward based on target up direction and rotation from parent
{
quaternion tmpPlanarRotation = MathUtilities.CreateRotationWithUpPriority(targetUp, orbitCamera.PlanarForward);
// Rotation from character parent
if (orbitCamera.RotateWithCharacterParent &&
KinematicCharacterBodyLookup.TryGetComponent(cameraControl.FollowedCharacterEntity, out KinematicCharacterBody characterBody))
{
// Only consider rotation around the character up, since the camera is already adjusting itself to character up
quaternion planarRotationFromParent = characterBody.RotationFromParent;
KinematicCharacterUtilities.AddVariableRateRotationFromFixedRateRotation(ref tmpPlanarRotation, planarRotationFromParent, DeltaTime, characterBody.LastPhysicsUpdateDeltaTime);
}
orbitCamera.PlanarForward = MathUtilities.GetForwardFromRotation(tmpPlanarRotation);
}
// Yaw
float yawAngleChange = cameraControl.LookDegreesDelta.x * orbitCamera.RotationSpeed;
quaternion yawRotation = quaternion.Euler(targetUp * math.radians(yawAngleChange));
orbitCamera.PlanarForward = math.rotate(yawRotation, orbitCamera.PlanarForward);
// Pitch
orbitCamera.PitchAngle += -cameraControl.LookDegreesDelta.y * orbitCamera.RotationSpeed;
orbitCamera.PitchAngle = math.clamp(orbitCamera.PitchAngle, orbitCamera.MinVAngle, orbitCamera.MaxVAngle);
// Calculate final rotation
quaternion cameraRotation = OrbitCameraUtilities.CalculateCameraRotation(targetUp, orbitCamera.PlanarForward, orbitCamera.PitchAngle);
// Distance input
float desiredDistanceMovementFromInput = cameraControl.ZoomDelta * orbitCamera.DistanceMovementSpeed;
orbitCamera.TargetDistance = math.clamp(orbitCamera.TargetDistance + desiredDistanceMovementFromInput, orbitCamera.MinDistance, orbitCamera.MaxDistance);
// Calculate camera position (no smoothing or obstructions yet; these are done in the camera late update)
float3 cameraPosition = OrbitCameraUtilities.CalculateCameraPosition(targetPosition, cameraRotation, orbitCamera.TargetDistance);
// Write back to component
LocalTransformLookup[entity] = LocalTransform.FromPositionRotation(cameraPosition, cameraRotation);
}
}
}
}
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(TransformSystemGroup))]
[BurstCompile]
public partial struct OrbitCameraLateUpdateSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<PhysicsWorldSingleton>();
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<OrbitCamera, OrbitCameraControl>().Build());
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
OrbitCameraLateUpdateJob job = new OrbitCameraLateUpdateJob
{
DeltaTime = SystemAPI.Time.DeltaTime,
PhysicsWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>().PhysicsWorld,
LocalToWorldLookup = SystemAPI.GetComponentLookup<LocalToWorld>(false),
CameraTargetLookup = SystemAPI.GetComponentLookup<CameraTarget>(true),
KinematicCharacterBodyLookup = SystemAPI.GetComponentLookup<KinematicCharacterBody>(true),
};
job.Schedule();
}
[BurstCompile]
[WithAll(typeof(Simulate))]
public partial struct OrbitCameraLateUpdateJob : IJobEntity
{
public float DeltaTime;
[ReadOnly]
public PhysicsWorld PhysicsWorld;
public ComponentLookup<LocalToWorld> LocalToWorldLookup;
[ReadOnly]
public ComponentLookup<CameraTarget> CameraTargetLookup;
[ReadOnly]
public ComponentLookup<KinematicCharacterBody> KinematicCharacterBodyLookup;
void Execute(
Entity entity,
ref OrbitCamera orbitCamera,
in OrbitCameraControl cameraControl,
in DynamicBuffer<OrbitCameraIgnoredEntityBufferElement> ignoredEntitiesBuffer)
{
if (OrbitCameraUtilities.TryGetCameraTargetInterpolatedWorldTransform(
cameraControl.FollowedCharacterEntity,
ref LocalToWorldLookup,
ref CameraTargetLookup,
out LocalToWorld targetWorldTransform))
{
quaternion cameraRotation = OrbitCameraUtilities.CalculateCameraRotation(targetWorldTransform.Up, orbitCamera.PlanarForward, orbitCamera.PitchAngle);
float3 cameraForward = math.mul(cameraRotation, math.forward());
float3 targetPosition = targetWorldTransform.Position;
// Distance smoothing
orbitCamera.SmoothedTargetDistance = math.lerp(orbitCamera.SmoothedTargetDistance, orbitCamera.TargetDistance, MathUtilities.GetSharpnessInterpolant(orbitCamera.DistanceMovementSharpness, DeltaTime));
// Obstruction handling
// Obstruction detection is handled here, because we have to adjust the obstruction distance
// to match the interpolated physics body transform (as opposed to the "simulation" transform). Otherwise, a
// camera getting obstructed by a moving physics body would have visible jitter.
if (orbitCamera.ObstructionRadius > 0f)
{
float obstructionCheckDistance = orbitCamera.SmoothedTargetDistance;
CameraObstructionHitsCollector collector = new CameraObstructionHitsCollector(cameraControl.FollowedCharacterEntity, ignoredEntitiesBuffer, cameraForward);
PhysicsWorld.SphereCastCustom(
targetPosition,
orbitCamera.ObstructionRadius,
-cameraForward,
obstructionCheckDistance,
ref collector,
CollisionFilter.Default,
QueryInteraction.IgnoreTriggers);
float newObstructedDistance = obstructionCheckDistance;
if (collector.NumHits > 0)
{
newObstructedDistance = obstructionCheckDistance * collector.ClosestHit.Fraction;
// Redo cast with the interpolated body transform to prevent FixedUpdate jitter in obstruction detection
if (orbitCamera.PreventFixedUpdateJitter)
{
RigidBody hitBody = PhysicsWorld.Bodies[collector.ClosestHit.RigidBodyIndex];
if (LocalToWorldLookup.TryGetComponent(hitBody.Entity, out LocalToWorld hitBodyLocalToWorld))
{
// Adjust the rigidbody transform for interpolation, so we can raycast it in that state
hitBody.WorldFromBody = new RigidTransform(quaternion.LookRotationSafe(hitBodyLocalToWorld.Forward, hitBodyLocalToWorld.Up), hitBodyLocalToWorld.Position);
collector = new CameraObstructionHitsCollector(cameraControl.FollowedCharacterEntity, ignoredEntitiesBuffer, cameraForward);
hitBody.SphereCastCustom(
targetPosition,
orbitCamera.ObstructionRadius,
-cameraForward,
obstructionCheckDistance,
ref collector,
CollisionFilter.Default,
QueryInteraction.IgnoreTriggers);
if (collector.NumHits > 0)
{
newObstructedDistance = obstructionCheckDistance * collector.ClosestHit.Fraction;
}
}
}
}
// Update current distance based on obstructed distance
if (orbitCamera.ObstructedDistance < newObstructedDistance)
{
// Move outer
orbitCamera.ObstructedDistance = math.lerp(orbitCamera.ObstructedDistance, newObstructedDistance, MathUtilities.GetSharpnessInterpolant(orbitCamera.ObstructionOuterSmoothingSharpness, DeltaTime));
}
else if (orbitCamera.ObstructedDistance > newObstructedDistance)
{
// Move inner
orbitCamera.ObstructedDistance = math.lerp(orbitCamera.ObstructedDistance, newObstructedDistance, MathUtilities.GetSharpnessInterpolant(orbitCamera.ObstructionInnerSmoothingSharpness, DeltaTime));
}
}
else
{
orbitCamera.ObstructedDistance = orbitCamera.SmoothedTargetDistance;
}
// Place camera at the final distance (includes smoothing and obstructions)
float3 cameraPosition = OrbitCameraUtilities.CalculateCameraPosition(targetPosition, cameraRotation, orbitCamera.ObstructedDistance);
// Write to LtW
LocalToWorldLookup[entity] = new LocalToWorld { Value = new float4x4(cameraRotation, cameraPosition) };
}
}
}
}
public static class OrbitCameraUtilities
{
public static bool TryGetCameraTargetSimulationWorldTransform(
Entity targetCharacterEntity,
ref ComponentLookup<LocalTransform> localTransformLookup,
ref ComponentLookup<Parent> parentLookup,
ref ComponentLookup<PostTransformMatrix> postTransformMatrixLookup,
ref ComponentLookup<CameraTarget> cameraTargetLookup,
out float4x4 worldTransform)
{
bool foundValidCameraTarget = false;
worldTransform = float4x4.identity;
// Camera target is either defined by the CameraTarget component, or if not, the transform of the followed character
if (cameraTargetLookup.TryGetComponent(targetCharacterEntity, out CameraTarget cameraTarget) &&
localTransformLookup.HasComponent(cameraTarget.TargetEntity))
{
TransformHelpers.ComputeWorldTransformMatrix(
cameraTarget.TargetEntity,
out worldTransform,
ref localTransformLookup,
ref parentLookup,
ref postTransformMatrixLookup);
foundValidCameraTarget = true;
}
else if (localTransformLookup.TryGetComponent(targetCharacterEntity, out LocalTransform characterLocalTransform))
{
worldTransform = float4x4.TRS(characterLocalTransform.Position, characterLocalTransform.Rotation, 1f);
foundValidCameraTarget = true;
}
return foundValidCameraTarget;
}
public static bool TryGetCameraTargetInterpolatedWorldTransform(
Entity targetCharacterEntity,
ref ComponentLookup<LocalToWorld> localToWorldLookup,
ref ComponentLookup<CameraTarget> cameraTargetLookup,
out LocalToWorld worldTransform)
{
bool foundValidCameraTarget = false;
worldTransform = default;
// Get the interpolated transform of the target
if (cameraTargetLookup.TryGetComponent(targetCharacterEntity, out CameraTarget cameraTarget) &&
localToWorldLookup.TryGetComponent(cameraTarget.TargetEntity, out worldTransform))
{
foundValidCameraTarget = true;
}
else if (localToWorldLookup.TryGetComponent(targetCharacterEntity, out worldTransform))
{
foundValidCameraTarget = true;
}
return foundValidCameraTarget;
}
public static quaternion CalculateCameraRotation(float3 targetUp, float3 planarForward, float pitchAngle)
{
quaternion pitchRotation = quaternion.Euler(math.right() * math.radians(pitchAngle));
quaternion cameraRotation = MathUtilities.CreateRotationWithUpPriority(targetUp, planarForward);
cameraRotation = math.mul(cameraRotation, pitchRotation);
return cameraRotation;
}
public static float3 CalculateCameraPosition(float3 targetPosition, quaternion cameraRotation, float distance)
{
return targetPosition + (-MathUtilities.GetForwardFromRotation(cameraRotation) * distance);
}
}
public struct CameraObstructionHitsCollector : ICollector<ColliderCastHit>
{
public bool EarlyOutOnFirstHit => false;
public float MaxFraction => 1f;
public int NumHits { get; private set; }
public ColliderCastHit ClosestHit;
private float m_ClosestHitFraction;
private float3 m_CameraDirection;
private Entity m_FollowedCharacter;
private DynamicBuffer<OrbitCameraIgnoredEntityBufferElement> m_IgnoredEntitiesBuffer;
public CameraObstructionHitsCollector(Entity followedCharacter, DynamicBuffer<OrbitCameraIgnoredEntityBufferElement> ignoredEntitiesBuffer, float3 cameraDirection)
{
NumHits = 0;
ClosestHit = default;
m_ClosestHitFraction = float.MaxValue;
m_CameraDirection = cameraDirection;
m_FollowedCharacter = followedCharacter;
m_IgnoredEntitiesBuffer = ignoredEntitiesBuffer;
}
public bool AddHit(ColliderCastHit hit)
{
if (m_FollowedCharacter == hit.Entity)
{
return false;
}
if (math.dot(hit.SurfaceNormal, m_CameraDirection) < 0f || !PhysicsUtilities.IsCollidable(hit.Material))
{
return false;
}
for (int i = 0; i < m_IgnoredEntitiesBuffer.Length; i++)
{
if (m_IgnoredEntitiesBuffer[i].Entity == hit.Entity)
{
return false;
}
}
// Process valid hit
if (hit.Fraction < m_ClosestHitFraction)
{
m_ClosestHitFraction = hit.Fraction;
ClosestHit = hit;
}
NumHits++;
return true;
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6d6d36bc694f390408f5683be8de8c7d
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/OrbitCamera/OrbitCameraSystems.cs
uploadId: 897522
@@ -0,0 +1,49 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using Unity.CharacterController;
[DisallowMultipleComponent]
public class ThirdPersonCharacterAuthoring : MonoBehaviour
{
public AuthoringKinematicCharacterProperties CharacterProperties = AuthoringKinematicCharacterProperties.GetDefault();
public float RotationSharpness = 25f;
public float GroundMaxSpeed = 10f;
public float GroundedMovementSharpness = 15f;
public float AirAcceleration = 50f;
public float AirMaxSpeed = 10f;
public float AirDrag = 0f;
public float JumpSpeed = 10f;
public float3 Gravity = math.up() * -30f;
public bool PreventAirAccelerationAgainstUngroundedHits = true;
public BasicStepAndSlopeHandlingParameters StepAndSlopeHandling = BasicStepAndSlopeHandlingParameters.GetDefault();
public class Baker : Baker<ThirdPersonCharacterAuthoring>
{
public override void Bake(ThirdPersonCharacterAuthoring authoring)
{
KinematicCharacterUtilities.BakeCharacter(this, authoring.gameObject, authoring.CharacterProperties);
Entity entity = GetEntity(TransformUsageFlags.Dynamic | TransformUsageFlags.WorldSpace);
AddComponent(entity, new ThirdPersonCharacterComponent
{
RotationSharpness = authoring.RotationSharpness,
GroundMaxSpeed = authoring.GroundMaxSpeed,
GroundedMovementSharpness = authoring.GroundedMovementSharpness,
AirAcceleration = authoring.AirAcceleration,
AirMaxSpeed = authoring.AirMaxSpeed,
AirDrag = authoring.AirDrag,
JumpSpeed = authoring.JumpSpeed,
Gravity = authoring.Gravity,
PreventAirAccelerationAgainstUngroundedHits = authoring.PreventAirAccelerationAgainstUngroundedHits,
StepAndSlopeHandling = authoring.StepAndSlopeHandling,
});
AddComponent(entity, new ThirdPersonCharacterControl());
}
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c854a728d43c7cf47bec103607a449f9
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/ThirdPersonCharacterAuthoring.cs
uploadId: 897522
@@ -0,0 +1,29 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using System;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using Unity.CharacterController;
[Serializable]
public struct ThirdPersonCharacterComponent : IComponentData
{
public float RotationSharpness;
public float GroundMaxSpeed;
public float GroundedMovementSharpness;
public float AirAcceleration;
public float AirMaxSpeed;
public float AirDrag;
public float JumpSpeed;
public float3 Gravity;
public bool PreventAirAccelerationAgainstUngroundedHits;
public BasicStepAndSlopeHandlingParameters StepAndSlopeHandling;
}
[Serializable]
public struct ThirdPersonCharacterControl : IComponentData
{
public float3 MoveVector;
public bool Jump;
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d8471dfde63584745b2234708055b211
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/ThirdPersonCharacterComponent.cs
uploadId: 897522
@@ -0,0 +1,310 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using System;
using Unity.Entities;
using Unity.CharacterController;
using Unity.Mathematics;
using Unity.Physics;
using UnityEngine;
public struct ThirdPersonCharacterUpdateContext
{
// Here, you may add additional global data for your character updates, such as ComponentLookups, Singletons, NativeCollections, etc...
// The data you add here will be accessible in your character updates and all of your character "callbacks".
public void OnSystemCreate(ref SystemState state)
{
// Get lookups
}
public void OnSystemUpdate(ref SystemState state)
{
// Update lookups
}
}
public struct ThirdPersonCharacterProcessor : IKinematicCharacterProcessor<ThirdPersonCharacterUpdateContext>
{
public KinematicCharacterDataAccess CharacterDataAccess;
public RefRW<ThirdPersonCharacterComponent> CharacterComponent;
public RefRW<ThirdPersonCharacterControl> CharacterControl;
public void PhysicsUpdate(ref ThirdPersonCharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext)
{
ref ThirdPersonCharacterComponent characterComponent = ref CharacterComponent.ValueRW;
ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW;
ref float3 characterPosition = ref CharacterDataAccess.LocalTransform.ValueRW.Position;
// First phase of default character update
KinematicCharacterUtilities.Update_Initialize(
in this,
ref context,
ref baseContext,
ref characterBody,
CharacterDataAccess.CharacterHitsBuffer,
CharacterDataAccess.DeferredImpulsesBuffer,
CharacterDataAccess.VelocityProjectionHits,
baseContext.Time.DeltaTime);
KinematicCharacterUtilities.Update_ParentMovement(
in this,
ref context,
ref baseContext,
CharacterDataAccess.CharacterEntity,
ref characterBody,
CharacterDataAccess.CharacterProperties.ValueRO,
CharacterDataAccess.PhysicsCollider.ValueRO,
CharacterDataAccess.LocalTransform.ValueRO,
ref characterPosition,
characterBody.WasGroundedBeforeCharacterUpdate);
KinematicCharacterUtilities.Update_Grounding(
in this,
ref context,
ref baseContext,
ref characterBody,
CharacterDataAccess.CharacterEntity,
CharacterDataAccess.CharacterProperties.ValueRO,
CharacterDataAccess.PhysicsCollider.ValueRO,
CharacterDataAccess.LocalTransform.ValueRO,
CharacterDataAccess.VelocityProjectionHits,
CharacterDataAccess.CharacterHitsBuffer,
ref characterPosition);
// Update desired character velocity after grounding was detected, but before doing additional processing that depends on velocity
HandleVelocityControl(ref context, ref baseContext);
// Second phase of default character update
KinematicCharacterUtilities.Update_PreventGroundingFromFutureSlopeChange(
in this,
ref context,
ref baseContext,
CharacterDataAccess.CharacterEntity,
ref characterBody,
CharacterDataAccess.CharacterProperties.ValueRO,
CharacterDataAccess.PhysicsCollider.ValueRO,
in characterComponent.StepAndSlopeHandling);
KinematicCharacterUtilities.Update_GroundPushing(
in this,
ref context,
ref baseContext,
ref characterBody,
CharacterDataAccess.CharacterProperties.ValueRO,
CharacterDataAccess.LocalTransform.ValueRO,
CharacterDataAccess.DeferredImpulsesBuffer,
characterComponent.Gravity);
KinematicCharacterUtilities.Update_MovementAndDecollisions(
in this,
ref context,
ref baseContext,
CharacterDataAccess.CharacterEntity,
ref characterBody,
CharacterDataAccess.CharacterProperties.ValueRO,
CharacterDataAccess.PhysicsCollider.ValueRO,
CharacterDataAccess.LocalTransform.ValueRO,
CharacterDataAccess.VelocityProjectionHits,
CharacterDataAccess.CharacterHitsBuffer,
CharacterDataAccess.DeferredImpulsesBuffer,
ref characterPosition);
KinematicCharacterUtilities.Update_MovingPlatformDetection(
ref baseContext,
ref characterBody);
KinematicCharacterUtilities.Update_ParentMomentum(
ref baseContext,
ref characterBody,
CharacterDataAccess.LocalTransform.ValueRO.Position);
KinematicCharacterUtilities.Update_ProcessStatefulCharacterHits(
CharacterDataAccess.CharacterHitsBuffer,
CharacterDataAccess.StatefulHitsBuffer);
}
void HandleVelocityControl(ref ThirdPersonCharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext)
{
float deltaTime = baseContext.Time.DeltaTime;
ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW;
ref ThirdPersonCharacterComponent characterComponent = ref CharacterComponent.ValueRW;
ref ThirdPersonCharacterControl characterControl = ref CharacterControl.ValueRW;
// Rotate move input and velocity to take into account parent rotation
if (characterBody.ParentEntity != Entity.Null)
{
characterControl.MoveVector = math.rotate(characterBody.RotationFromParent, characterControl.MoveVector);
characterBody.RelativeVelocity = math.rotate(characterBody.RotationFromParent, characterBody.RelativeVelocity);
}
if (characterBody.IsGrounded)
{
// Move on ground
float3 targetVelocity = characterControl.MoveVector * characterComponent.GroundMaxSpeed;
CharacterControlUtilities.StandardGroundMove_Interpolated(ref characterBody.RelativeVelocity, targetVelocity, characterComponent.GroundedMovementSharpness, deltaTime, characterBody.GroundingUp, characterBody.GroundHit.Normal);
// Jump
if (characterControl.Jump)
{
CharacterControlUtilities.StandardJump(ref characterBody, characterBody.GroundingUp * characterComponent.JumpSpeed, true, characterBody.GroundingUp);
}
}
else
{
// Move in air
float3 airAcceleration = characterControl.MoveVector * characterComponent.AirAcceleration;
if (math.lengthsq(airAcceleration) > 0f)
{
float3 tmpVelocity = characterBody.RelativeVelocity;
CharacterControlUtilities.StandardAirMove(ref characterBody.RelativeVelocity, airAcceleration, characterComponent.AirMaxSpeed, characterBody.GroundingUp, deltaTime, false);
// Cancel air acceleration from input if we would hit a non-grounded surface (prevents air-climbing slopes at high air accelerations)
if (characterComponent.PreventAirAccelerationAgainstUngroundedHits
&& KinematicCharacterUtilities.MovementWouldHitNonGroundedObstruction(
in this,
ref context,
ref baseContext,
CharacterDataAccess.CharacterProperties.ValueRO,
CharacterDataAccess.LocalTransform.ValueRO,
CharacterDataAccess.CharacterEntity,
CharacterDataAccess.PhysicsCollider.ValueRO,
characterBody.RelativeVelocity * deltaTime,
out ColliderCastHit hit))
{
characterBody.RelativeVelocity = tmpVelocity;
}
}
// Gravity
CharacterControlUtilities.AccelerateVelocity(ref characterBody.RelativeVelocity, characterComponent.Gravity, deltaTime);
// Drag
CharacterControlUtilities.ApplyDragToVelocity(ref characterBody.RelativeVelocity, deltaTime, characterComponent.AirDrag);
}
}
public void VariableUpdate(ref ThirdPersonCharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext)
{
ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW;
ref ThirdPersonCharacterComponent characterComponent = ref CharacterComponent.ValueRW;
ref ThirdPersonCharacterControl characterControl = ref CharacterControl.ValueRW;
ref quaternion characterRotation = ref CharacterDataAccess.LocalTransform.ValueRW.Rotation;
// Add rotation from parent body to the character rotation
// (this is for allowing a rotating moving platform to rotate your character as well, and handle interpolation properly)
KinematicCharacterUtilities.AddVariableRateRotationFromFixedRateRotation(ref characterRotation, characterBody.RotationFromParent, baseContext.Time.DeltaTime, characterBody.LastPhysicsUpdateDeltaTime);
// Rotate towards move direction
if (math.lengthsq(characterControl.MoveVector) > 0f)
{
CharacterControlUtilities.SlerpRotationTowardsDirectionAroundUp(ref characterRotation, baseContext.Time.DeltaTime, math.normalizesafe(characterControl.MoveVector), MathUtilities.GetUpFromRotation(characterRotation), characterComponent.RotationSharpness);
}
}
#region Character Processor Callbacks
public void UpdateGroundingUp(ref ThirdPersonCharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext)
{
ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW;
KinematicCharacterUtilities.Default_UpdateGroundingUp(
ref characterBody,
CharacterDataAccess.LocalTransform.ValueRO.Rotation);
}
public bool CanCollideWithHit(
ref ThirdPersonCharacterUpdateContext context,
ref KinematicCharacterUpdateContext baseContext,
in BasicHit hit)
{
return PhysicsUtilities.IsCollidable(hit.Material);
}
public bool IsGroundedOnHit(
ref ThirdPersonCharacterUpdateContext context,
ref KinematicCharacterUpdateContext baseContext,
in BasicHit hit,
int groundingEvaluationType)
{
ThirdPersonCharacterComponent characterComponent = CharacterComponent.ValueRO;
return KinematicCharacterUtilities.Default_IsGroundedOnHit(
in this,
ref context,
ref baseContext,
CharacterDataAccess.CharacterEntity,
CharacterDataAccess.PhysicsCollider.ValueRO,
CharacterDataAccess.CharacterBody.ValueRO,
CharacterDataAccess.CharacterProperties.ValueRO,
in hit,
in characterComponent.StepAndSlopeHandling,
groundingEvaluationType);
}
public void OnMovementHit(
ref ThirdPersonCharacterUpdateContext context,
ref KinematicCharacterUpdateContext baseContext,
ref KinematicCharacterHit hit,
ref float3 remainingMovementDirection,
ref float remainingMovementLength,
float3 originalVelocityDirection,
float hitDistance)
{
ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW;
ref float3 characterPosition = ref CharacterDataAccess.LocalTransform.ValueRW.Position;
ThirdPersonCharacterComponent characterComponent = CharacterComponent.ValueRO;
KinematicCharacterUtilities.Default_OnMovementHit(
in this,
ref context,
ref baseContext,
ref characterBody,
CharacterDataAccess.CharacterEntity,
CharacterDataAccess.CharacterProperties.ValueRO,
CharacterDataAccess.PhysicsCollider.ValueRO,
CharacterDataAccess.LocalTransform.ValueRO,
ref characterPosition,
CharacterDataAccess.VelocityProjectionHits,
ref hit,
ref remainingMovementDirection,
ref remainingMovementLength,
originalVelocityDirection,
hitDistance,
characterComponent.StepAndSlopeHandling.StepHandling,
characterComponent.StepAndSlopeHandling.MaxStepHeight,
characterComponent.StepAndSlopeHandling.CharacterWidthForStepGroundingCheck);
}
public void OverrideDynamicHitMasses(
ref ThirdPersonCharacterUpdateContext context,
ref KinematicCharacterUpdateContext baseContext,
ref PhysicsMass characterMass,
ref PhysicsMass otherMass,
BasicHit hit)
{
// Custom mass overrides
}
public void ProjectVelocityOnHits(
ref ThirdPersonCharacterUpdateContext context,
ref KinematicCharacterUpdateContext baseContext,
ref float3 velocity,
ref bool characterIsGrounded,
ref BasicHit characterGroundHit,
in DynamicBuffer<KinematicVelocityProjectionHit> velocityProjectionHits,
float3 originalVelocityDirection)
{
ThirdPersonCharacterComponent characterComponent = CharacterComponent.ValueRO;
KinematicCharacterUtilities.Default_ProjectVelocityOnHits(
ref velocity,
ref characterIsGrounded,
ref characterGroundHit,
in velocityProjectionHits,
originalVelocityDirection,
characterComponent.StepAndSlopeHandling.ConstrainVelocityToGroundPlane,
in CharacterDataAccess.CharacterBody.ValueRO);
}
#endregion
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6cfd976dbc67c744991a587c048d1e46
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/ThirdPersonCharacterProcessor.cs
uploadId: 897522
@@ -0,0 +1,193 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using Unity.Burst;
using Unity.Entities;
using Unity.Physics;
using Unity.Transforms;
using Unity.CharacterController;
using Unity.Burst.Intrinsics;
[UpdateInGroup(typeof(KinematicCharacterPhysicsUpdateGroup))]
[BurstCompile]
public partial struct ThirdPersonCharacterPhysicsUpdateSystem : ISystem
{
EntityQuery m_CharacterQuery;
ThirdPersonCharacterUpdateContext m_Context;
KinematicCharacterUpdateContext m_BaseContext;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
m_CharacterQuery = KinematicCharacterUtilities.GetBaseCharacterQueryBuilder()
.WithAll<ThirdPersonCharacterComponent, ThirdPersonCharacterControl>()
.Build(ref state);
m_Context = new ThirdPersonCharacterUpdateContext();
m_Context.OnSystemCreate(ref state);
m_BaseContext = new KinematicCharacterUpdateContext();
m_BaseContext.OnSystemCreate(ref state);
state.RequireForUpdate(m_CharacterQuery);
state.RequireForUpdate<PhysicsWorldSingleton>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
m_Context.OnSystemUpdate(ref state);
m_BaseContext.OnSystemUpdate(ref state, SystemAPI.Time, SystemAPI.GetSingleton<PhysicsWorldSingleton>());
ThirdPersonCharacterPhysicsUpdateJob job = new ThirdPersonCharacterPhysicsUpdateJob
{
Context = m_Context,
BaseContext = m_BaseContext,
};
job.ScheduleParallel();
}
[BurstCompile]
[WithAll(typeof(Simulate))]
public partial struct ThirdPersonCharacterPhysicsUpdateJob : IJobEntity, IJobEntityChunkBeginEnd
{
public ThirdPersonCharacterUpdateContext Context;
public KinematicCharacterUpdateContext BaseContext;
public void Execute(
Entity entity,
RefRW<LocalTransform> localTransform,
RefRW<KinematicCharacterProperties> characterProperties,
RefRW<KinematicCharacterBody> characterBody,
RefRW<PhysicsCollider> physicsCollider,
RefRW<ThirdPersonCharacterComponent> characterComponent,
RefRW<ThirdPersonCharacterControl> characterControl,
DynamicBuffer<KinematicCharacterHit> characterHitsBuffer,
DynamicBuffer<StatefulKinematicCharacterHit> statefulHitsBuffer,
DynamicBuffer<KinematicCharacterDeferredImpulse> deferredImpulsesBuffer,
DynamicBuffer<KinematicVelocityProjectionHit> velocityProjectionHits)
{
var characterProcessor = new ThirdPersonCharacterProcessor()
{
CharacterDataAccess = new KinematicCharacterDataAccess(
entity,
localTransform,
characterProperties,
characterBody,
physicsCollider,
characterHitsBuffer,
statefulHitsBuffer,
deferredImpulsesBuffer,
velocityProjectionHits
),
CharacterComponent = characterComponent,
CharacterControl = characterControl
};
characterProcessor.PhysicsUpdate(ref Context, ref BaseContext);
}
public bool OnChunkBegin(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
{
BaseContext.EnsureCreationOfTmpCollections();
return true;
}
public void OnChunkEnd(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask, bool chunkWasExecuted)
{ }
}
}
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(ThirdPersonPlayerVariableStepControlSystem))]
[UpdateBefore(typeof(TransformSystemGroup))]
[BurstCompile]
public partial struct ThirdPersonCharacterVariableUpdateSystem : ISystem
{
EntityQuery m_CharacterQuery;
ThirdPersonCharacterUpdateContext m_Context;
KinematicCharacterUpdateContext m_BaseContext;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<PhysicsWorldSingleton>();
m_CharacterQuery = KinematicCharacterUtilities.GetBaseCharacterQueryBuilder()
.WithAll<
ThirdPersonCharacterComponent,
ThirdPersonCharacterControl>()
.Build(ref state);
m_Context = new ThirdPersonCharacterUpdateContext();
m_Context.OnSystemCreate(ref state);
m_BaseContext = new KinematicCharacterUpdateContext();
m_BaseContext.OnSystemCreate(ref state);
state.RequireForUpdate(m_CharacterQuery);
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
m_Context.OnSystemUpdate(ref state);
m_BaseContext.OnSystemUpdate(ref state, SystemAPI.Time, SystemAPI.GetSingleton<PhysicsWorldSingleton>());
ThirdPersonCharacterVariableUpdateJob job = new ThirdPersonCharacterVariableUpdateJob
{
Context = m_Context,
BaseContext = m_BaseContext,
};
job.ScheduleParallel();
}
[BurstCompile]
[WithAll(typeof(Simulate))]
public partial struct ThirdPersonCharacterVariableUpdateJob : IJobEntity, IJobEntityChunkBeginEnd
{
public ThirdPersonCharacterUpdateContext Context;
public KinematicCharacterUpdateContext BaseContext;
public void Execute(
Entity entity,
RefRW<LocalTransform> localTransform,
RefRW<KinematicCharacterProperties> characterProperties,
RefRW<KinematicCharacterBody> characterBody,
RefRW<PhysicsCollider> physicsCollider,
RefRW<ThirdPersonCharacterComponent> characterComponent,
RefRW<ThirdPersonCharacterControl> characterControl,
DynamicBuffer<KinematicCharacterHit> characterHitsBuffer,
DynamicBuffer<StatefulKinematicCharacterHit> statefulHitsBuffer,
DynamicBuffer<KinematicCharacterDeferredImpulse> deferredImpulsesBuffer,
DynamicBuffer<KinematicVelocityProjectionHit> velocityProjectionHits)
{
var characterProcessor = new ThirdPersonCharacterProcessor()
{
CharacterDataAccess = new KinematicCharacterDataAccess(
entity,
localTransform,
characterProperties,
characterBody,
physicsCollider,
characterHitsBuffer,
statefulHitsBuffer,
deferredImpulsesBuffer,
velocityProjectionHits
),
CharacterComponent = characterComponent,
CharacterControl = characterControl
};
characterProcessor.VariableUpdate(ref Context, ref BaseContext);
}
public bool OnChunkBegin(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
{
BaseContext.EnsureCreationOfTmpCollections();
return true;
}
public void OnChunkEnd(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask, bool chunkWasExecuted)
{ }
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: b37392a281d8a5f45a770ad4cfd747a6
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/ThirdPersonCharacterSystems.cs
uploadId: 897522
@@ -0,0 +1,19 @@
using System;
using Unity.Entities;
using Unity.Mathematics;
[Serializable]
public struct ThirdPersonPlayer : IComponentData
{
public Entity ControlledCharacter;
public Entity ControlledCamera;
}
[Serializable]
public struct ThirdPersonPlayerInputs : IComponentData
{
public float2 MoveInput;
public float2 CameraLookInput;
public float CameraZoomInput;
public FixedInputEvent JumpPressed;
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8586d18bf7667c040949956b7ff40b6d
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/ThirdPersonPlayer.cs
uploadId: 897522
@@ -0,0 +1,23 @@
using UnityEngine;
using Unity.Entities;
[DisallowMultipleComponent]
public class ThirdPersonPlayerAuthoring : MonoBehaviour
{
public GameObject ControlledCharacter;
public GameObject ControlledCamera;
public class Baker : Baker<ThirdPersonPlayerAuthoring>
{
public override void Bake(ThirdPersonPlayerAuthoring authoring)
{
Entity entity = GetEntity(TransformUsageFlags.None);
AddComponent(entity, new ThirdPersonPlayer
{
ControlledCharacter = GetEntity(authoring.ControlledCharacter, TransformUsageFlags.Dynamic),
ControlledCamera = GetEntity(authoring.ControlledCamera, TransformUsageFlags.Dynamic),
});
AddComponent<ThirdPersonPlayerInputs>(entity);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 3fbdb3174a73a07408595a85d3e7fb6a
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/ThirdPersonPlayerAuthoring.cs
uploadId: 897522
@@ -0,0 +1,133 @@
#if RUKHANKA_SAMPLES_WITH_CHARACTER_CONTROLLER
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM
using UnityEngine.InputSystem;
#endif
using Unity.CharacterController;
[UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)]
[UpdateBefore(typeof(FixedStepSimulationSystemGroup))]
public partial class ThirdPersonPlayerInputsSystem : SystemBase
{
protected override void OnCreate()
{
RequireForUpdate<FixedTickSystem.Singleton>();
RequireForUpdate(SystemAPI.QueryBuilder().WithAll<ThirdPersonPlayer, ThirdPersonPlayerInputs>().Build());
}
protected override void OnUpdate()
{
uint tick = SystemAPI.GetSingleton<FixedTickSystem.Singleton>().Tick;
#if ENABLE_INPUT_SYSTEM
foreach (var (playerInputs, player) in SystemAPI.Query<RefRW<ThirdPersonPlayerInputs>, RefRO<ThirdPersonPlayer>>())
{
playerInputs.ValueRW.MoveInput = new float2
{
x = (Keyboard.current.dKey.isPressed ? 1f : 0f) + (Keyboard.current.aKey.isPressed ? -1f : 0f),
y = (Keyboard.current.wKey.isPressed ? 1f : 0f) + (Keyboard.current.sKey.isPressed ? -1f : 0f),
};
playerInputs.ValueRW.CameraLookInput = Mouse.current.delta.ReadValue();
playerInputs.ValueRW.CameraZoomInput = -Mouse.current.scroll.ReadValue().y;
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
playerInputs.ValueRW.JumpPressed.Set(tick);
}
}
#endif
}
}
/// <summary>
/// Apply inputs that need to be read at a variable rate
/// </summary>
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
[BurstCompile]
public partial struct ThirdPersonPlayerVariableStepControlSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<ThirdPersonPlayer, ThirdPersonPlayerInputs>().Build());
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
foreach (var (playerInputs, player) in SystemAPI.Query<RefRO<ThirdPersonPlayerInputs>, RefRO<ThirdPersonPlayer>>().WithAll<Simulate>())
{
if (SystemAPI.HasComponent<OrbitCameraControl>(player.ValueRO.ControlledCamera))
{
OrbitCameraControl cameraControl = SystemAPI.GetComponent<OrbitCameraControl>(player.ValueRO.ControlledCamera);
cameraControl.FollowedCharacterEntity = player.ValueRO.ControlledCharacter;
cameraControl.LookDegreesDelta = playerInputs.ValueRO.CameraLookInput;
cameraControl.ZoomDelta = playerInputs.ValueRO.CameraZoomInput;
SystemAPI.SetComponent(player.ValueRO.ControlledCamera, cameraControl);
}
}
}
}
/// <summary>
/// Apply inputs that need to be read at a fixed rate.
/// It is necessary to handle this as part of the fixed step group, in case your framerate is lower than the fixed step rate.
/// </summary>
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup), OrderFirst = true)]
[BurstCompile]
public partial struct ThirdPersonPlayerFixedStepControlSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<FixedTickSystem.Singleton>();
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<ThirdPersonPlayer, ThirdPersonPlayerInputs>().Build());
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
uint tick = SystemAPI.GetSingleton<FixedTickSystem.Singleton>().Tick;
foreach (var (playerInputs, player) in SystemAPI.Query<RefRO<ThirdPersonPlayerInputs>, RefRO<ThirdPersonPlayer>>().WithAll<Simulate>())
{
if (SystemAPI.HasComponent<ThirdPersonCharacterControl>(player.ValueRO.ControlledCharacter))
{
ThirdPersonCharacterControl characterControl = SystemAPI.GetComponent<ThirdPersonCharacterControl>(player.ValueRO.ControlledCharacter);
float3 characterUp = MathUtilities.GetUpFromRotation(SystemAPI.GetComponent<LocalTransform>(player.ValueRO.ControlledCharacter).Rotation);
// Get camera rotation, since our movement is relative to it.
quaternion cameraRotation = quaternion.identity;
if (SystemAPI.HasComponent<OrbitCamera>(player.ValueRO.ControlledCamera))
{
// Camera rotation is calculated rather than gotten from transform, because this allows us to
// reduce the size of the camera ghost state in a netcode prediction context.
// If not using netcode prediction, we could simply get rotation from transform here instead.
OrbitCamera orbitCamera = SystemAPI.GetComponent<OrbitCamera>(player.ValueRO.ControlledCamera);
cameraRotation = OrbitCameraUtilities.CalculateCameraRotation(characterUp, orbitCamera.PlanarForward, orbitCamera.PitchAngle);
}
float3 cameraForwardOnUpPlane = math.normalizesafe(MathUtilities.ProjectOnPlane(MathUtilities.GetForwardFromRotation(cameraRotation), characterUp));
float3 cameraRight = MathUtilities.GetRightFromRotation(cameraRotation);
// Move
characterControl.MoveVector = (playerInputs.ValueRO.MoveInput.y * cameraForwardOnUpPlane) + (playerInputs.ValueRO.MoveInput.x * cameraRight);
characterControl.MoveVector = MathUtilities.ClampToMaxLength(characterControl.MoveVector, 1f);
// Jump
characterControl.Jump = playerInputs.ValueRO.JumpPressed.IsSet(tick);
SystemAPI.SetComponent(player.ValueRO.ControlledCharacter, characterControl);
}
}
}
}
#endif
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 427fac77ddc96db4a87e6d5b4a31555f
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/Scenes/25. Character Controller/Scripts/UnityCharacterController/Standard Characters/ThirdPerson/Scripts/ThirdPersonPlayerSystems.cs
uploadId: 897522