Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
fbe4331
add simple impulse by pressing the key
popuz Feb 3, 2026
a595695
separate calculation for external force
popuz Feb 9, 2026
8668fd5
Merge remote-tracking branch 'refs/remotes/origin/dev' into feat/sdk/…
popuz Feb 10, 2026
46d3c4e
Merge remote-tracking branch 'refs/remotes/origin/dev' into feat/sdk/…
popuz Feb 11, 2026
68a482a
generetaed sdk component
popuz Feb 11, 2026
fb37670
add plugin, system and related infrastructure to handle SDK Component
popuz Feb 11, 2026
1ec130c
exposed new parameters to the Debug panel
popuz Feb 11, 2026
df9fec9
renamed sdk system
popuz Feb 11, 2026
0c09ee0
exposed settings to the debug panel
popuz Feb 11, 2026
01368d7
add force application
popuz Feb 11, 2026
1c23233
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Feb 12, 2026
a22b608
Merge remote-tracking branch 'origin/feat/sdk/physics-impulse' into f…
popuz Feb 12, 2026
d56a5f5
drag and friction re-work for External Force
popuz Feb 12, 2026
333c539
refactor impulse apllication out of SDK world
popuz Feb 12, 2026
ea57e74
updated protocol
popuz Feb 12, 2026
47bac71
add physics force handling
popuz Feb 12, 2026
f16e452
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Feb 13, 2026
602a137
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Feb 13, 2026
4fb39a9
forgotten ComponentID
popuz Feb 13, 2026
60c9175
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Feb 18, 2026
cc72c4f
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Feb 18, 2026
4c46c90
clean up from input test triggering impulse and force
popuz Feb 19, 2026
d0d3078
fixed compilation error
popuz Feb 19, 2026
94c6830
renamed the physics system and plugin
popuz Feb 19, 2026
3c10a93
moved vertical accelaration and velocity to the Gravity
popuz Feb 19, 2026
5ea4521
safety net for vertical velocity
popuz Feb 19, 2026
736d50f
brought back impulse to affect full velocity
popuz Feb 19, 2026
d77b77a
fixed pushing
popuz Feb 19, 2026
c834c71
small re-naming
popuz Feb 24, 2026
3c396d0
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Feb 24, 2026
e27de0b
fixed infinite jump pad
popuz Feb 25, 2026
fdc3904
add external velocity to animator calculus
popuz Feb 25, 2026
b50424d
updated protocol
popuz Feb 25, 2026
0bf77de
renamings
popuz Feb 25, 2026
8e3c5d6
small refactoring
popuz Feb 25, 2026
62c299b
updated protocol
popuz Feb 26, 2026
ef3e45d
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Feb 26, 2026
ca777af
Merge remote-tracking branch 'origin/feat/sdk/physics-impulse' into f…
popuz Feb 26, 2026
ccf2e53
fix to debug panel
popuz Feb 28, 2026
c72b972
extracted debug logic out of the core
popuz Feb 28, 2026
7bd1735
small fix for gravity
popuz Feb 28, 2026
ef0f6f9
set new settings for drag and friction
popuz Feb 28, 2026
eb9f34c
pointed to experimental proto
popuz Mar 2, 2026
63dc25f
fixed animations
popuz Mar 2, 2026
2f28b38
small refactoring clean-up
popuz Mar 2, 2026
3240da2
some wrong logic by forces
popuz Mar 2, 2026
6b3a422
remobed unneeded comment
popuz Mar 2, 2026
8b9b53e
small comment move
popuz Mar 2, 2026
fd4998e
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 2, 2026
9212ac6
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 3, 2026
f7cb50a
removed Editor from CharSettings
popuz Mar 3, 2026
baf1f4f
Merge remote-tracking branch 'origin/feat/sdk/physics-impulse' into f…
popuz Mar 3, 2026
759654d
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 3, 2026
fde4b95
Merge remote-tracking branch 'origin/dev' into feat/sdk/physics-impulse
popuz Mar 4, 2026
8c3a169
Merge remote-tracking branch 'origin/dev' into feat/sdk/physics-impulse
popuz Mar 5, 2026
8ef4b19
solved small conflits
popuz Mar 5, 2026
ada72c7
added gliding debug
popuz Mar 5, 2026
4a8668f
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 6, 2026
572f007
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 9, 2026
cff2a8a
add [None(typeof(DeleteEntityIntention))] to queries
popuz Mar 9, 2026
f26ebae
Merge remote-tracking branch 'origin/feat/sdk/physics-impulse' into f…
popuz Mar 9, 2026
21b3223
fixing forces
popuz Mar 9, 2026
880b342
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 9, 2026
f771aeb
Merge remote-tracking branch 'origin/dev' into feat/sdk/physics-impulse
popuz Mar 10, 2026
6d52ec0
fix for impulse accumulation
popuz Mar 10, 2026
6ba0fd9
merged comment
popuz Mar 10, 2026
8b23293
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 11, 2026
491fb0b
add reset for external forces/impulses on /reload command
popuz Mar 13, 2026
af4c95f
add reseting gravity and slope velocity as well
popuz Mar 13, 2026
5c005e2
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 13, 2026
6f97887
fix with broken test
popuz Mar 16, 2026
4b879f4
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 16, 2026
d6f5299
Merge branch 'dev' into feat/sdk/physics-impulse
popuz Mar 16, 2026
9595632
clean-up for NETWORK filtering
popuz Mar 16, 2026
f18fe8a
removed filtering test
popuz Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ public static void Execute(float dt,
in GlideState glideState)
{
bool isGrounded = rigidTransform is { IsGrounded: true, IsOnASteepSlope: false } || rigidTransform.IsStuck;

Vector3 velocity = rigidTransform.MoveVelocity.Velocity;
float verticalVelocity = rigidTransform.GravityVelocity.y + velocity.y;
float verticalVelocity = rigidTransform.GravityVelocity.y + velocity.y + rigidTransform.ExternalVelocity.y;

bool jumpTriggered = jumpState.JumpCount > animationComponent.States.JumpCount;
bool glidingTriggered = glideState.Value == GlideStateValue.OPENING_PROP && animationComponent.States.GlideState != GlideStateValue.OPENING_PROP;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using UnityEngine;
using UnityEngine;

namespace DCL.CharacterMotion.Components
{
Expand Down Expand Up @@ -48,6 +48,20 @@ public class CharacterRigidTransform
// This flag is set when the rigidTransform is between 2 slopes
public bool IsStuck;

// Net external force acting on the character (persistent while source is active, managed by the writer's lifecycle)
public Vector3 ExternalForce;

// Computed acceleration from ExternalForce (a = F / mass), per-frame
public Vector3 ExternalAcceleration;

// Pending external impulse to apply this frame (cleared after applying)
// Impulse = instant velocity change: Δv = J / mass
public Vector3 ExternalImpulse;

// External velocity from impulses, forces (jump pads, knockbacks, wind, etc.)
// Decays over time via drag/friction
public Vector3 ExternalVelocity;

public struct MovementVelocity
{
// Current sideways velocity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,7 @@ MonoBehaviour:
<HeadIKRemotePlayersDistance>k__BackingField: 10
<JumpPadForce>k__BackingField: 50
<AnimationSpeed>k__BackingField: 1
<CharacterMass>k__BackingField: 1
<ExternalEnvDrag>k__BackingField: 1.5
<ExternalGroundFriction>k__BackingField: 4
<MaxExternalVelocity>k__BackingField: 50
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using UnityEngine;
using UnityEngine;
using UnityEngine.Serialization;

namespace DCL.CharacterMotion.Settings
Expand Down Expand Up @@ -108,5 +108,11 @@ public class CharacterControllerSettings : ScriptableObject, ICharacterControlle
[field: SerializeField] public float HeadIKRemotePlayersDistance { get; set; } = 10;
[field: SerializeField] [field: Header("Cheat/Debug/Misc")] public float JumpPadForce { get; private set; } = 50f;
[field: SerializeField] public float AnimationSpeed { get; private set; } = 1;

[field: Header("Impulse / External Velocity")]
[field: SerializeField] public float CharacterMass { get; set; } = 1f;
[field: SerializeField] public float ExternalEnvDrag { get; set; } = 0.5f;
[field: SerializeField] public float ExternalGroundFriction { get; set; } = 4f;
[field: SerializeField] public float MaxExternalVelocity { get; set; } = 50f;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,11 @@ public interface ICharacterControllerSettings
float WallSlideDetectionDistance { get; }
float WallSlideMaxMoveSpeedMultiplier { get; }
float StepOffset { get; set; }

// Impulse / External Velocity settings
float CharacterMass { get; set; }
float ExternalEnvDrag { get; set; }
float ExternalGroundFriction { get; set; }
float MaxExternalVelocity { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using DCL.SDKComponents.AvatarLocomotion.Components;
using DCL.SDKComponents.AvatarLocomotion.Components;
using DCL.SDKComponents.AvatarLocomotion.Systems;
using UnityEngine;

Expand Down Expand Up @@ -366,6 +366,30 @@ public float StepOffset
set => impl.StepOffset = value;
}

public float CharacterMass
{
get => impl.CharacterMass;
set => impl.CharacterMass = value;
}

public float ExternalEnvDrag
{
get => impl.ExternalEnvDrag;
set => impl.ExternalEnvDrag = value;
}

public float ExternalGroundFriction
{
get => impl.ExternalGroundFriction;
set => impl.ExternalGroundFriction = value;
}

public float MaxExternalVelocity
{
get => impl.MaxExternalVelocity;
set => impl.MaxExternalVelocity = value;
}

public float HeadIKWeightChangeSpeed
{
get => impl.HeadIKWeightChangeSpeed;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
using Arch.Core;
using Arch.Core;
using Arch.System;
using Arch.SystemGroups;
using Arch.SystemGroups.DefaultSystemGroups;
using DCL.AvatarRendering.DemoScripts.Components;
using DCL.Character.CharacterMotion.Components;
using DCL.Character.CharacterMotion.Velocity;
using DCL.CharacterCamera;
using DCL.CharacterMotion;
using DCL.CharacterMotion.Components;
using DCL.CharacterMotion.Settings;
using DCL.DebugUtilities;
using DCL.DebugUtilities.UIBindings;
using DCL.Time.Systems;
using ECS.Abstract;
using ECS.LifeCycle.Components;
using UnityEngine;
using DCL.AvatarRendering.DemoScripts.Components;
using DCL.CharacterMotion.Utils;

namespace DCL.CharacterMotion.Systems
namespace DCL.Character.CharacterMotion.Systems
{
/// <summary>
/// Entry point to calculate everything that affects character's velocity
Expand All @@ -27,107 +26,17 @@ public partial class CalculateCharacterVelocitySystem : BaseUnityLoopSystem
{
private SingleInstanceEntity camera;
private SingleInstanceEntity fixedTick;
private SingleInstanceEntity entitySettings;

private readonly ElementBinding<float> cameraRunFov = new (0);
private readonly ElementBinding<float> walkSpeed = new (0);
private readonly ElementBinding<float> jogSpeed = new (0);
private readonly ElementBinding<float> runSpeed = new (0);
private readonly ElementBinding<float> jogJumpHeight = new (0);
private readonly ElementBinding<float> runJumpHeight = new (0);
private readonly ElementBinding<float> jumpHold = new (0);
private readonly ElementBinding<float> jumpHoldGravity = new (0);
private readonly ElementBinding<float> gravity = new (0);
private readonly ElementBinding<float> airAcc = new (0);
private readonly ElementBinding<float> maxAirAcc = new (0);
private readonly ElementBinding<float> airDrag = new (0);
private readonly ElementBinding<float> stopTime = new (0);

private readonly ElementBinding<int> airJumpCount = new (0);
private readonly ElementBinding<float> airJumpHeight = new (0);
private readonly ElementBinding<float> airJumpDelay = new (0);
private readonly ElementBinding<float> airJumpGravityDuringDelay = new (0);
private readonly ElementBinding<float> cooldownBetweenJumps = new (0);
private readonly ElementBinding<float> airJumpImpulse = new (0);

public CalculateCharacterVelocitySystem(World world, IDebugContainerBuilder debugBuilder) : base(world)
{
debugBuilder.TryAddWidget("Locomotion: Base")?
.AddFloatField("Camera Run FOV", cameraRunFov)
.AddFloatField("Walk Speed", walkSpeed)
.AddFloatField("Jog Speed", jogSpeed)
.AddFloatField("Run Speed", runSpeed)
.AddFloatField("Jog Jump Height", jogJumpHeight)
.AddFloatField("Run Jump Height", runJumpHeight)
.AddFloatField("Jump Hold Time", jumpHold)
.AddFloatField("Jump Hold Gravity Scale", jumpHoldGravity)
.AddFloatField("Gravity", gravity)
.AddFloatField("Air Acceleration", airAcc)
.AddFloatField("Max Air Acceleration", maxAirAcc)
.AddFloatField("Air Drag", airDrag)
.AddFloatField("Grounded Stop Time", stopTime);

debugBuilder.TryAddWidget("Locomotion: Air Jumping")?
.AddControl( new DebugConstLabelDef("Air Jump Count"), new DebugIntFieldDef(airJumpCount) )
.AddFloatField("Height", airJumpHeight)
.AddFloatField("Delay", airJumpDelay)
.AddFloatField("Gravity during Delay", airJumpGravityDuringDelay)
.AddFloatField("Cooldown", cooldownBetweenJumps)
.AddFloatField("Direction Change Impulse", airJumpImpulse);
}

public CalculateCharacterVelocitySystem(World world) : base(world) { }

public override void Initialize()
{
camera = World.CacheCamera();
fixedTick = World.CachePhysicsTick();
entitySettings = World.CacheCharacterSettings();

ICharacterControllerSettings settings = entitySettings.GetCharacterSettings(World);
cameraRunFov.Value = settings.CameraFOVWhileRunning;
walkSpeed.Value = settings.WalkSpeed;
jogSpeed.Value = settings.JogSpeed;
runSpeed.Value = settings.RunSpeed;
jogJumpHeight.Value = settings.JogJumpHeight;
runJumpHeight.Value = settings.RunJumpHeight;
jumpHold.Value = settings.LongJumpTime;
jumpHoldGravity.Value = settings.LongJumpGravityScale;
gravity.Value = settings.Gravity;
airAcc.Value = settings.AirAcceleration;
maxAirAcc.Value = settings.MaxAirAcceleration;
airDrag.Value = settings.AirDrag;
stopTime.Value = settings.StopTimeSec;
airJumpCount.Value = settings.AirJumpCount;
airJumpHeight.Value = settings.AirJumpHeight;
airJumpDelay.Value = settings.AirJumpDelay;
airJumpGravityDuringDelay.Value = settings.AirJumpGravityDuringDelay;
cooldownBetweenJumps.Value = settings.CooldownBetweenJumps;
airJumpImpulse.Value = settings.AirJumpDirectionChangeImpulse;
}

protected override void Update(float t)
{
ICharacterControllerSettings settings = entitySettings.GetCharacterSettings(World);

settings.CameraFOVWhileRunning = cameraRunFov.Value;
settings.WalkSpeed = walkSpeed.Value;
settings.JogSpeed = jogSpeed.Value;
settings.RunSpeed = runSpeed.Value;
settings.JogJumpHeight = jogJumpHeight.Value;
settings.RunJumpHeight = runJumpHeight.Value;
settings.LongJumpTime = jumpHold.Value;
settings.LongJumpGravityScale = jumpHoldGravity.Value;
settings.Gravity = gravity.Value;
settings.AirAcceleration = airAcc.Value;
settings.MaxAirAcceleration = maxAirAcc.Value;
settings.AirDrag = airDrag.Value;
settings.StopTimeSec = stopTime.Value;
settings.AirJumpCount = airJumpCount.Value;
settings.AirJumpHeight = airJumpHeight.Value;
settings.AirJumpDelay = airJumpDelay.Value;
settings.AirJumpGravityDuringDelay = airJumpGravityDuringDelay.Value;
settings.CooldownBetweenJumps = cooldownBetweenJumps.Value;
settings.AirJumpDirectionChangeImpulse = airJumpImpulse.Value;

ResolveVelocityQuery(World, t, fixedTick.GetPhysicsTickComponent(World).Tick, in camera.GetCameraComponent(World));
ResolveRandomAvatarVelocityQuery(World, t, fixedTick.GetPhysicsTickComponent(World).Tick, in camera.GetCameraComponent(World));
}
Expand Down Expand Up @@ -213,19 +122,29 @@ private void ResolveAvatarVelocity([Data] float dt,
// Apply velocity multiplier based on walls
ApplyWallSlide.Execute(ref rigidTransform, characterController, in settings);

// Apply vertical velocity
// External forces must run before gravity so ExternalAcceleration.y is available
ApplyExternalForce.Execute(settings, ref rigidTransform, dt);

// Vertical velocity (jump + gravity with effective gravity from external forces)
ApplyJump.Execute(settings, ref rigidTransform, ref jumpState, ref jumpInput, in movementInput, viewerForward, viewerRight, physicsTick, dt);
ApplyGravity.Execute(settings, ref rigidTransform, jumpState, in jumpInput, physicsTick, dt);
ApplyGliding.Execute(settings, in rigidTransform, jumpState, in jumpInput, ref glideState, physicsTick, dt);

ApplyAirDrag.Execute(settings, ref rigidTransform, dt);
// External impulses must run after gravity so it nullify gravity velocity.y
ApplyExternalImpulse.Execute(settings, ref rigidTransform);

// Drag
ApplyHorizontalAirDrag.Execute(settings, ref rigidTransform, dt);
ApplyExternalVelocityDragAndClamp.Execute(settings, ref rigidTransform, dt);

// Rotation
if (cameraComponent.Mode == CameraMode.FirstPerson)
ApplyFirstPersonRotation.Execute(ref rigidTransform, in cameraComponent);
else
ApplyThirdPersonRotation.Execute(ref rigidTransform, in movementInput);

ApplyConditionalRotation.Execute(ref rigidTransform, in settings);
if (settings.EnableCharacterRotationBySlope)
ApplySlopeConditionalRotation.Execute(ref rigidTransform, in settings);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
using Arch.SystemGroups;
using Arch.SystemGroups.DefaultSystemGroups;
using DCL.AvatarRendering.DemoScripts.Components;
using DCL.Character.CharacterMotion.Components;
using DCL.CharacterCamera;
using DCL.Character.CharacterMotion.Systems;
using DCL.CharacterMotion.Components;
using DCL.CharacterMotion.Settings;
using DCL.CharacterMotion.Utils;
using DCL.Time.Systems;
using ECS.Abstract;
using ECS.LifeCycle.Components;
using System;
using UnityEngine;

namespace DCL.CharacterMotion.Systems
{
Expand Down
Loading
Loading