Progress character movement
This commit is contained in:
parent
08e27ca2f1
commit
01f38a19a1
@ -4,6 +4,7 @@ using Unity.Entities;
|
|||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Unity.CharacterController;
|
using Unity.CharacterController;
|
||||||
|
using Unity.NetCode;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct FirstPersonCharacterComponent : IComponentData
|
public struct FirstPersonCharacterComponent : IComponentData
|
||||||
@ -22,7 +23,7 @@ public struct FirstPersonCharacterComponent : IComponentData
|
|||||||
public float MaxViewAngle;
|
public float MaxViewAngle;
|
||||||
|
|
||||||
public Entity ViewEntity;
|
public Entity ViewEntity;
|
||||||
public float ViewPitchDegrees;
|
[GhostField] public float ViewPitchDegrees;
|
||||||
public quaternion ViewLocalRotation;
|
public quaternion ViewLocalRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ using Unity.Physics;
|
|||||||
using Unity.Transforms;
|
using Unity.Transforms;
|
||||||
using Unity.CharacterController;
|
using Unity.CharacterController;
|
||||||
using Unity.Burst.Intrinsics;
|
using Unity.Burst.Intrinsics;
|
||||||
|
using Unity.NetCode;
|
||||||
|
|
||||||
[UpdateInGroup(typeof(KinematicCharacterPhysicsUpdateGroup))]
|
[UpdateInGroup(typeof(KinematicCharacterPhysicsUpdateGroup))]
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
@ -72,10 +73,9 @@ public partial struct FirstPersonCharacterPhysicsUpdateSystem : ISystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
|
||||||
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
|
[UpdateAfter(typeof(PredictedFixedStepSimulationSystemGroup))]
|
||||||
[UpdateAfter(typeof(FirstPersonPlayerVariableStepControlSystem))]
|
[UpdateAfter(typeof(FirstPersonPlayerVariableStepControlSystem))]
|
||||||
[UpdateBefore(typeof(TransformSystemGroup))]
|
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public partial struct FirstPersonCharacterVariableUpdateSystem : ISystem
|
public partial struct FirstPersonCharacterVariableUpdateSystem : ISystem
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,18 +1,26 @@
|
|||||||
using System;
|
using System;
|
||||||
using Unity.Collections;
|
|
||||||
using Unity.Entities;
|
using Unity.Entities;
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
|
using Unity.NetCode;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct FirstPersonPlayer : IComponentData
|
public struct FirstPersonPlayer : IComponentData
|
||||||
{
|
{
|
||||||
public Entity ControlledCharacter;
|
[GhostField] public Entity ControlledCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct FirstPersonPlayerInputs : IComponentData
|
public struct FirstPersonPlayerInputs : IInputComponentData
|
||||||
{
|
{
|
||||||
public float2 MoveInput;
|
public float2 MoveInput;
|
||||||
public float2 LookInput;
|
public float2 LookInput;
|
||||||
public FixedInputEvent JumpPressed;
|
public FixedInputEvent JumpPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[GhostComponent(SendTypeOptimization = GhostSendType.OnlyPredictedClients)]
|
||||||
|
public struct FirstPersonPlayerNetworkInput : IComponentData
|
||||||
|
{
|
||||||
|
[GhostField()]
|
||||||
|
public float2 LastProcessedLookInput;
|
||||||
}
|
}
|
||||||
@ -16,6 +16,7 @@ public class FirstPersonPlayerAuthoring : MonoBehaviour
|
|||||||
ControlledCharacter = GetEntity(authoring.ControlledCharacter, TransformUsageFlags.Dynamic),
|
ControlledCharacter = GetEntity(authoring.ControlledCharacter, TransformUsageFlags.Dynamic),
|
||||||
});
|
});
|
||||||
AddComponent<FirstPersonPlayerInputs>(entity);
|
AddComponent<FirstPersonPlayerInputs>(entity);
|
||||||
|
AddComponent<FirstPersonPlayerNetworkInput>(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,26 +1,26 @@
|
|||||||
using Unity.Burst;
|
using Unity.Burst;
|
||||||
using Unity.Collections;
|
|
||||||
using Unity.Entities;
|
using Unity.Entities;
|
||||||
using Unity.Jobs;
|
|
||||||
using Unity.Mathematics;
|
using Unity.Mathematics;
|
||||||
using Unity.Transforms;
|
using Unity.Transforms;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Unity.CharacterController;
|
using Unity.CharacterController;
|
||||||
|
using Unity.NetCode;
|
||||||
|
|
||||||
[UpdateInGroup(typeof(InitializationSystemGroup))]
|
[UpdateInGroup(typeof(GhostInputSystemGroup))]
|
||||||
|
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
||||||
public partial class FirstPersonPlayerInputsSystem : SystemBase
|
public partial class FirstPersonPlayerInputsSystem : SystemBase
|
||||||
{
|
{
|
||||||
protected override void OnCreate()
|
protected override void OnCreate()
|
||||||
{
|
{
|
||||||
RequireForUpdate<FixedTickSystem.Singleton>();
|
RequireForUpdate<NetworkTime>();
|
||||||
RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
|
RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
uint tick = SystemAPI.GetSingleton<FixedTickSystem.Singleton>().Tick;
|
var time = SystemAPI.GetSingleton<FixedTickSystem.Singleton>();
|
||||||
|
|
||||||
foreach (var (playerInputs, player) in SystemAPI.Query<RefRW<FirstPersonPlayerInputs>, FirstPersonPlayer>())
|
foreach (var (playerInputs, player) in SystemAPI.Query<RefRW<FirstPersonPlayerInputs>, FirstPersonPlayer>().WithAll<GhostOwnerIsLocal>())
|
||||||
{
|
{
|
||||||
playerInputs.ValueRW.MoveInput = new float2
|
playerInputs.ValueRW.MoveInput = new float2
|
||||||
{
|
{
|
||||||
@ -28,11 +28,13 @@ public partial class FirstPersonPlayerInputsSystem : SystemBase
|
|||||||
y = (Input.GetKey(KeyCode.W) ? 1f : 0f) + (Input.GetKey(KeyCode.S) ? -1f : 0f),
|
y = (Input.GetKey(KeyCode.W) ? 1f : 0f) + (Input.GetKey(KeyCode.S) ? -1f : 0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
playerInputs.ValueRW.LookInput = new float2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
|
InputDeltaUtilities.AddInputDelta(ref playerInputs.ValueRW.LookInput.x, Input.GetAxis("Mouse X"));
|
||||||
|
InputDeltaUtilities.AddInputDelta(ref playerInputs.ValueRW.LookInput.y, Input.GetAxis("Mouse Y"));
|
||||||
|
|
||||||
|
playerInputs.ValueRW.JumpPressed = default;
|
||||||
if (Input.GetKeyDown(KeyCode.Space))
|
if (Input.GetKeyDown(KeyCode.Space))
|
||||||
{
|
{
|
||||||
playerInputs.ValueRW.JumpPressed.Set(tick);
|
playerInputs.ValueRW.JumpPressed.Set(time.Tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,28 +43,33 @@ public partial class FirstPersonPlayerInputsSystem : SystemBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply inputs that need to be read at a variable rate
|
/// Apply inputs that need to be read at a variable rate
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
|
||||||
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
|
[UpdateAfter(typeof(PredictedFixedStepSimulationSystemGroup))]
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public partial struct FirstPersonPlayerVariableStepControlSystem : ISystem
|
public partial struct FirstPersonPlayerVariableStepControlSystem : ISystem
|
||||||
{
|
{
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public void OnCreate(ref SystemState state)
|
public void OnCreate(ref SystemState state)
|
||||||
{
|
{
|
||||||
|
state.RequireForUpdate<NetworkTime>();
|
||||||
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
|
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public void OnUpdate(ref SystemState state)
|
public void OnUpdate(ref SystemState state)
|
||||||
{
|
{
|
||||||
foreach (var (playerInputs, player) in SystemAPI.Query<FirstPersonPlayerInputs, FirstPersonPlayer>().WithAll<Simulate>())
|
foreach (var (playerInputs, playerNetworkInput, player) in SystemAPI.Query<FirstPersonPlayerInputs, RefRW<FirstPersonPlayerNetworkInput>, FirstPersonPlayer>().WithAll<Simulate>())
|
||||||
{
|
{
|
||||||
|
// Compute input deltas, compared to last known values
|
||||||
|
float2 lookInputDelta = InputDeltaUtilities.GetInputDelta(
|
||||||
|
playerInputs.LookInput,
|
||||||
|
playerNetworkInput.ValueRO.LastProcessedLookInput);
|
||||||
|
playerNetworkInput.ValueRW.LastProcessedLookInput = playerInputs.LookInput;
|
||||||
|
|
||||||
if (SystemAPI.HasComponent<FirstPersonCharacterControl>(player.ControlledCharacter))
|
if (SystemAPI.HasComponent<FirstPersonCharacterControl>(player.ControlledCharacter))
|
||||||
{
|
{
|
||||||
FirstPersonCharacterControl characterControl = SystemAPI.GetComponent<FirstPersonCharacterControl>(player.ControlledCharacter);
|
FirstPersonCharacterControl characterControl = SystemAPI.GetComponent<FirstPersonCharacterControl>(player.ControlledCharacter);
|
||||||
|
characterControl.LookDegreesDelta = lookInputDelta;
|
||||||
characterControl.LookDegreesDelta = playerInputs.LookInput;
|
|
||||||
|
|
||||||
SystemAPI.SetComponent(player.ControlledCharacter, characterControl);
|
SystemAPI.SetComponent(player.ControlledCharacter, characterControl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,22 +80,23 @@ public partial struct FirstPersonPlayerVariableStepControlSystem : ISystem
|
|||||||
/// Apply inputs that need to be read at a fixed rate.
|
/// 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.
|
/// 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>
|
/// </summary>
|
||||||
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup), OrderFirst = true)]
|
[UpdateInGroup(typeof(PredictedFixedStepSimulationSystemGroup), OrderFirst = true)]
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public partial struct FirstPersonPlayerFixedStepControlSystem : ISystem
|
public partial struct FirstPersonPlayerFixedStepControlSystem : ISystem
|
||||||
{
|
{
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public void OnCreate(ref SystemState state)
|
public void OnCreate(ref SystemState state)
|
||||||
{
|
{
|
||||||
state.RequireForUpdate<FixedTickSystem.Singleton>();
|
|
||||||
|
state.RequireForUpdate<NetworkTime>();
|
||||||
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
|
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public void OnUpdate(ref SystemState state)
|
public void OnUpdate(ref SystemState state)
|
||||||
{
|
{
|
||||||
uint tick = SystemAPI.GetSingleton<FixedTickSystem.Singleton>().Tick;
|
var time = SystemAPI.GetSingleton<FixedTickSystem.Singleton>();
|
||||||
|
|
||||||
foreach (var (playerInputs, player) in SystemAPI.Query<FirstPersonPlayerInputs, FirstPersonPlayer>().WithAll<Simulate>())
|
foreach (var (playerInputs, player) in SystemAPI.Query<FirstPersonPlayerInputs, FirstPersonPlayer>().WithAll<Simulate>())
|
||||||
{
|
{
|
||||||
if (SystemAPI.HasComponent<FirstPersonCharacterControl>(player.ControlledCharacter))
|
if (SystemAPI.HasComponent<FirstPersonCharacterControl>(player.ControlledCharacter))
|
||||||
@ -104,7 +112,7 @@ public partial struct FirstPersonPlayerFixedStepControlSystem : ISystem
|
|||||||
characterControl.MoveVector = MathUtilities.ClampToMaxLength(characterControl.MoveVector, 1f);
|
characterControl.MoveVector = MathUtilities.ClampToMaxLength(characterControl.MoveVector, 1f);
|
||||||
|
|
||||||
// Jump
|
// Jump
|
||||||
characterControl.Jump = playerInputs.JumpPressed.IsSet(tick);
|
characterControl.Jump = playerInputs.JumpPressed.IsSet(time.Tick);
|
||||||
|
|
||||||
SystemAPI.SetComponent(player.ControlledCharacter, characterControl);
|
SystemAPI.SetComponent(player.ControlledCharacter, characterControl);
|
||||||
}
|
}
|
||||||
|
|||||||
52
Assets/Scripts/Common/GhostVariants.cs
Normal file
52
Assets/Scripts/Common/GhostVariants.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Unity.Entities;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using Unity.NetCode;
|
||||||
|
using Unity.CharacterController;
|
||||||
|
|
||||||
|
public partial class DefaultVariantSystem : DefaultVariantSystemBase
|
||||||
|
{
|
||||||
|
protected override void RegisterDefaultVariants(Dictionary<ComponentType, Rule> defaultVariants)
|
||||||
|
{
|
||||||
|
defaultVariants.Add(typeof(KinematicCharacterBody), Rule.ForAll(typeof(KinematicCharacterBody_DefaultVariant)));
|
||||||
|
defaultVariants.Add(typeof(CharacterInterpolation), Rule.ForAll(typeof(CharacterInterpolation_GhostVariant)));
|
||||||
|
defaultVariants.Add(typeof(TrackedTransform), Rule.ForAll(typeof(TrackedTransform_DefaultVariant)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[GhostComponentVariation(typeof(KinematicCharacterBody))]
|
||||||
|
[GhostComponent()]
|
||||||
|
public struct KinematicCharacterBody_DefaultVariant
|
||||||
|
{
|
||||||
|
// These two fields represent the basic synchronized state data that all networked characters will need.
|
||||||
|
[GhostField()]
|
||||||
|
public float3 RelativeVelocity;
|
||||||
|
[GhostField()]
|
||||||
|
public bool IsGrounded;
|
||||||
|
|
||||||
|
// The following fields are only needed for characters that need to support parent entities (stand on moving platforms).
|
||||||
|
// You can safely omit these from ghost sync if your game does not make use of character parent entities (any entities that have a TrackedTransform component).
|
||||||
|
[GhostField()]
|
||||||
|
public Entity ParentEntity;
|
||||||
|
[GhostField()]
|
||||||
|
public float3 ParentLocalAnchorPoint;
|
||||||
|
[GhostField()]
|
||||||
|
public float3 ParentVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Character interpolation must only exist on predicted clients:
|
||||||
|
// - for remote interpolated ghost characters, interpolation is handled by netcode.
|
||||||
|
// - for server, interpolation is superfluous.
|
||||||
|
[GhostComponentVariation(typeof(CharacterInterpolation))]
|
||||||
|
[GhostComponent(PrefabType = GhostPrefabType.PredictedClient)]
|
||||||
|
public struct CharacterInterpolation_GhostVariant
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[GhostComponentVariation(typeof(TrackedTransform))]
|
||||||
|
[GhostComponent()]
|
||||||
|
public struct TrackedTransform_DefaultVariant
|
||||||
|
{
|
||||||
|
[GhostField()]
|
||||||
|
public RigidTransform CurrentFixedRateTransform;
|
||||||
|
}
|
||||||
2
Assets/Scripts/Common/GhostVariants.cs.meta
Normal file
2
Assets/Scripts/Common/GhostVariants.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ad968c3972f1b5d45a01ff13d76c6073
|
||||||
46
Assets/Scripts/Common/InputDeltaUtilities.cs
Normal file
46
Assets/Scripts/Common/InputDeltaUtilities.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using Unity.Mathematics;
|
||||||
|
|
||||||
|
public static class InputDeltaUtilities
|
||||||
|
{
|
||||||
|
public const float InputWrapAroundValue = 2000f;
|
||||||
|
|
||||||
|
public static void AddInputDelta(ref float input, float addedDelta)
|
||||||
|
{
|
||||||
|
input = math.fmod(input + addedDelta, InputWrapAroundValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddInputDelta(ref float2 input, float2 addedDelta)
|
||||||
|
{
|
||||||
|
input = math.fmod(input + addedDelta, InputWrapAroundValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetInputDelta(float currentValue, float previousValue)
|
||||||
|
{
|
||||||
|
float delta = currentValue - previousValue;
|
||||||
|
|
||||||
|
// When delta is very large, consider that the input has wrapped around
|
||||||
|
if(math.abs(delta) > (InputWrapAroundValue * 0.5f))
|
||||||
|
{
|
||||||
|
delta += (math.sign(previousValue - currentValue) * InputWrapAroundValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float2 GetInputDelta(float2 currentValue, float2 previousValue)
|
||||||
|
{
|
||||||
|
float2 delta = currentValue - previousValue;
|
||||||
|
|
||||||
|
// When delta is very large, consider that the input has wrapped around
|
||||||
|
if(math.abs(delta.x) > (InputWrapAroundValue * 0.5f))
|
||||||
|
{
|
||||||
|
delta.x += (math.sign(previousValue.x - currentValue.x) * InputWrapAroundValue);
|
||||||
|
}
|
||||||
|
if(math.abs(delta.y) > (InputWrapAroundValue * 0.5f))
|
||||||
|
{
|
||||||
|
delta.y += (math.sign(previousValue.y - currentValue.y) * InputWrapAroundValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Common/InputDeltaUtilities.cs.meta
Normal file
3
Assets/Scripts/Common/InputDeltaUtilities.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: edf2b03f9a1d4b22b732a2d347673c5a
|
||||||
|
timeCreated: 1738609617
|
||||||
@ -56,7 +56,17 @@ MonoBehaviour:
|
|||||||
- rid: 7930710930656067584
|
- rid: 7930710930656067584
|
||||||
- rid: 4055230942537842688
|
- rid: 4055230942537842688
|
||||||
m_RuntimeSettings:
|
m_RuntimeSettings:
|
||||||
m_List: []
|
m_List:
|
||||||
|
- rid: 6852985685364965378
|
||||||
|
- rid: 6852985685364965379
|
||||||
|
- rid: 6852985685364965380
|
||||||
|
- rid: 6852985685364965381
|
||||||
|
- rid: 6852985685364965384
|
||||||
|
- rid: 6852985685364965385
|
||||||
|
- rid: 6852985685364965392
|
||||||
|
- rid: 6852985685364965394
|
||||||
|
- rid: 8712630790384254976
|
||||||
|
- rid: 7930710930656067584
|
||||||
m_AssetVersion: 8
|
m_AssetVersion: 8
|
||||||
m_ObsoleteDefaultVolumeProfile: {fileID: 0}
|
m_ObsoleteDefaultVolumeProfile: {fileID: 0}
|
||||||
m_RenderingLayerNames:
|
m_RenderingLayerNames:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user