Progress character movement

This commit is contained in:
Marius 2025-02-03 20:30:57 +01:00
parent 08e27ca2f1
commit 01f38a19a1
10 changed files with 160 additions and 29 deletions

View File

@ -4,6 +4,7 @@ using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
using Unity.CharacterController;
using Unity.NetCode;
[Serializable]
public struct FirstPersonCharacterComponent : IComponentData
@ -22,7 +23,7 @@ public struct FirstPersonCharacterComponent : IComponentData
public float MaxViewAngle;
public Entity ViewEntity;
public float ViewPitchDegrees;
[GhostField] public float ViewPitchDegrees;
public quaternion ViewLocalRotation;
}

View File

@ -7,6 +7,7 @@ using Unity.Physics;
using Unity.Transforms;
using Unity.CharacterController;
using Unity.Burst.Intrinsics;
using Unity.NetCode;
[UpdateInGroup(typeof(KinematicCharacterPhysicsUpdateGroup))]
[BurstCompile]
@ -72,10 +73,9 @@ public partial struct FirstPersonCharacterPhysicsUpdateSystem : ISystem
}
}
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
[UpdateAfter(typeof(PredictedFixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(FirstPersonPlayerVariableStepControlSystem))]
[UpdateBefore(typeof(TransformSystemGroup))]
[BurstCompile]
public partial struct FirstPersonCharacterVariableUpdateSystem : ISystem
{

View File

@ -1,18 +1,26 @@
using System;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.NetCode;
[Serializable]
public struct FirstPersonPlayer : IComponentData
{
public Entity ControlledCharacter;
[GhostField] public Entity ControlledCharacter;
}
[Serializable]
public struct FirstPersonPlayerInputs : IComponentData
public struct FirstPersonPlayerInputs : IInputComponentData
{
public float2 MoveInput;
public float2 LookInput;
public FixedInputEvent JumpPressed;
}
[Serializable]
[GhostComponent(SendTypeOptimization = GhostSendType.OnlyPredictedClients)]
public struct FirstPersonPlayerNetworkInput : IComponentData
{
[GhostField()]
public float2 LastProcessedLookInput;
}

View File

@ -16,6 +16,7 @@ public class FirstPersonPlayerAuthoring : MonoBehaviour
ControlledCharacter = GetEntity(authoring.ControlledCharacter, TransformUsageFlags.Dynamic),
});
AddComponent<FirstPersonPlayerInputs>(entity);
AddComponent<FirstPersonPlayerNetworkInput>(entity);
}
}
}

View File

@ -1,26 +1,26 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
using Unity.CharacterController;
using Unity.NetCode;
[UpdateInGroup(typeof(InitializationSystemGroup))]
[UpdateInGroup(typeof(GhostInputSystemGroup))]
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
public partial class FirstPersonPlayerInputsSystem : SystemBase
{
protected override void OnCreate()
{
RequireForUpdate<FixedTickSystem.Singleton>();
RequireForUpdate<NetworkTime>();
RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
}
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
{
@ -28,11 +28,13 @@ public partial class FirstPersonPlayerInputsSystem : SystemBase
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))
{
playerInputs.ValueRW.JumpPressed.Set(tick);
playerInputs.ValueRW.JumpPressed.Set(time.Tick);
}
}
}
@ -41,28 +43,33 @@ public partial class FirstPersonPlayerInputsSystem : SystemBase
/// <summary>
/// Apply inputs that need to be read at a variable rate
/// </summary>
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateAfter(typeof(FixedStepSimulationSystemGroup))]
[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
[UpdateAfter(typeof(PredictedFixedStepSimulationSystemGroup))]
[BurstCompile]
public partial struct FirstPersonPlayerVariableStepControlSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<NetworkTime>();
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
}
[BurstCompile]
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))
{
FirstPersonCharacterControl characterControl = SystemAPI.GetComponent<FirstPersonCharacterControl>(player.ControlledCharacter);
characterControl.LookDegreesDelta = playerInputs.LookInput;
characterControl.LookDegreesDelta = lookInputDelta;
SystemAPI.SetComponent(player.ControlledCharacter, characterControl);
}
}
@ -73,21 +80,22 @@ public partial struct FirstPersonPlayerVariableStepControlSystem : ISystem
/// 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)]
[UpdateInGroup(typeof(PredictedFixedStepSimulationSystemGroup), OrderFirst = true)]
[BurstCompile]
public partial struct FirstPersonPlayerFixedStepControlSystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<FixedTickSystem.Singleton>();
state.RequireForUpdate<NetworkTime>();
state.RequireForUpdate(SystemAPI.QueryBuilder().WithAll<FirstPersonPlayer, FirstPersonPlayerInputs>().Build());
}
[BurstCompile]
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>())
{
@ -104,7 +112,7 @@ public partial struct FirstPersonPlayerFixedStepControlSystem : ISystem
characterControl.MoveVector = MathUtilities.ClampToMaxLength(characterControl.MoveVector, 1f);
// Jump
characterControl.Jump = playerInputs.JumpPressed.IsSet(tick);
characterControl.Jump = playerInputs.JumpPressed.IsSet(time.Tick);
SystemAPI.SetComponent(player.ControlledCharacter, characterControl);
}

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

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ad968c3972f1b5d45a01ff13d76c6073

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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: edf2b03f9a1d4b22b732a2d347673c5a
timeCreated: 1738609617

View File

@ -56,7 +56,17 @@ MonoBehaviour:
- rid: 7930710930656067584
- rid: 4055230942537842688
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_ObsoleteDefaultVolumeProfile: {fileID: 0}
m_RenderingLayerNames: