cumulative update

This commit is contained in:
Valera 2025-12-01 00:02:14 +07:00
parent e12b75be45
commit 66fcc6a2bb
12 changed files with 131 additions and 151 deletions

View File

@ -12,6 +12,7 @@
"NetworkMode": 2, "NetworkMode": 2,
"NetworkInterpolation": true, "NetworkInterpolation": true,
"NetworkOrphaned": 0, "NetworkOrphaned": 0,
"NetworkTransmit": true,
"OwnerTransfer": 1, "OwnerTransfer": 1,
"Components": [], "Components": [],
"Children": [ "Children": [
@ -28,6 +29,7 @@
"NetworkMode": 2, "NetworkMode": 2,
"NetworkInterpolation": true, "NetworkInterpolation": true,
"NetworkOrphaned": 0, "NetworkOrphaned": 0,
"NetworkTransmit": true,
"OwnerTransfer": 1, "OwnerTransfer": 1,
"Components": [ "Components": [
{ {
@ -197,7 +199,7 @@
"FaceVelocity": false, "FaceVelocity": false,
"FogStrength": 1, "FogStrength": 1,
"LeadingTrail": true, "LeadingTrail": true,
"Lighting": false, "Lighting": true,
"MotionBlur": false, "MotionBlur": false,
"OnComponentDestroy": null, "OnComponentDestroy": null,
"OnComponentDisabled": null, "OnComponentDisabled": null,
@ -206,6 +208,7 @@
"OnComponentStart": null, "OnComponentStart": null,
"OnComponentUpdate": null, "OnComponentUpdate": null,
"Opaque": false, "Opaque": false,
"PlaybackSpeed": 1,
"RenderOptions": { "RenderOptions": {
"GameLayer": true, "GameLayer": true,
"OverlayLayer": false, "OverlayLayer": false,
@ -215,7 +218,7 @@
"RotationOffset": 0, "RotationOffset": 0,
"Scale": 1, "Scale": 1,
"Shadows": true, "Shadows": true,
"SortMode": "Unsorted", "SortMode": "ByDistance",
"Sprite": { "Sprite": {
"$compiler": "embed", "$compiler": "embed",
"$source": null, "$source": null,
@ -228,7 +231,8 @@
"LoopMode": "Loop", "LoopMode": "Loop",
"Frames": [ "Frames": [
{ {
"Texture": "textures/smoketexturesheet.vtex" "Texture": "textures/smoketexturesheet.vtex",
"BroadcastMessages": []
} }
] ]
} }

View File

@ -4,10 +4,10 @@ namespace VeloX;
public abstract partial class VeloXBase public abstract partial class VeloXBase
{ {
[Feature( "Input" )] internal InputResolver Input { get; set; } = new(); internal InputResolver Input { get; set; } = new();
[Feature( "Input" )] public Connection Driver { get => Input.Driver; set => Input.Driver = value; } public Connection Driver { get => Input.Driver; set => Input.Driver = value; }
public bool IsDriver => Connection.Local == Driver;
private bool IsDriverActive => Driver is not null; private bool IsDriverActive => Driver is not null;
public Vector2 MouseDelta => IsDriverActive ? Input.MouseDelta : default; public Vector2 MouseDelta => IsDriverActive ? Input.MouseDelta : default;

View File

@ -52,12 +52,8 @@ public abstract partial class VeloXBase
v.BrakeTorque = HandbrakeForce; v.BrakeTorque = HandbrakeForce;
} }
v.Update( this, in dt );
v.DoPhysics( in dt );
} }
Body.Velocity = vehVel; Body.Velocity = vehVel;
Body.AngularVelocity = vehAngVel; Body.AngularVelocity = vehAngVel;
} }

View File

@ -4,7 +4,7 @@ using System;
namespace VeloX; namespace VeloX;
public abstract partial class VeloXBase : Component public abstract partial class VeloXBase : Component, IGameObjectNetworkEvents
{ {
[Sync, Change( nameof( OnEngineIgnitionChange ) )] [Sync, Change( nameof( OnEngineIgnitionChange ) )]
public bool EngineIgnition { get; set; } public bool EngineIgnition { get; set; }
@ -26,18 +26,24 @@ public abstract partial class VeloXBase : Component
[Sync( SyncFlags.Interpolate )] public Angles SteerAngle { get; set; } [Sync( SyncFlags.Interpolate )] public Angles SteerAngle { get; set; }
public Vector3 LocalVelocity; [Sync( SyncFlags.Interpolate )] public Vector3 LocalVelocity { get; set; }
[Sync( SyncFlags.Interpolate )] public Vector3 Velocity { get; set; }
public float ForwardSpeed; public float ForwardSpeed;
public float TotalSpeed; public float TotalSpeed;
protected override void OnFixedUpdate() protected override void OnFixedUpdate()
{ {
if ( !IsProxy )
{
LocalVelocity = WorldTransform.PointToLocal( WorldPosition + Body.Velocity );
Velocity = Body.Velocity;
}
ForwardSpeed = LocalVelocity.x;
TotalSpeed = LocalVelocity.Length;
if ( IsProxy ) if ( IsProxy )
return; return;
LocalVelocity = WorldTransform.PointToLocal( WorldPosition + Body.Velocity );
ForwardSpeed = LocalVelocity.x;
TotalSpeed = LocalVelocity.Length;
Body.PhysicsBody.Mass = Mass; Body.PhysicsBody.Mass = Mass;
FixedUpdate(); FixedUpdate();
@ -50,4 +56,10 @@ public abstract partial class VeloXBase : Component
PhysicsSimulate(); PhysicsSimulate();
} }
//void IGameObjectNetworkEvents.NetworkOwnerChanged( Connection newOwner, Connection previousOwner )
//{
// Driver = newOwner;
// EngineIgnition = Driver is not null;
//}
} }

View File

@ -4,9 +4,6 @@ namespace VeloX;
public struct Friction public struct Friction
{ {
public float SlipCoef { get; set; }
public float ForceCoef { get; set; }
public float Force { get; set; } public float Force { get; set; }
public float Slip { get; set; } public float Slip { get; set; }
public float Speed { get; set; } public float Speed { get; set; }

View File

@ -35,8 +35,6 @@ public partial class VeloXWheel
public float CounterTorque { get; private set; } public float CounterTorque { get; private set; }
//[Property, Range( 0, 2 )] public float BrakeMult { get; set; } = 1f; //[Property, Range( 0, 2 )] public float BrakeMult { get; set; } = 1f;
public Friction ForwardFriction = new();
public Friction SidewayFriction = new();
public Vector3 FrictionForce; public Vector3 FrictionForce;
@ -47,20 +45,32 @@ public partial class VeloXWheel
public Vector3 ContactRight => hitSidewaysDirection; public Vector3 ContactRight => hitSidewaysDirection;
public Vector3 ContactForward => hitForwardDirection; public Vector3 ContactForward => hitForwardDirection;
public float LongitudinalSlip => ForwardFriction.Slip; public float LongitudinalSlip => sx;
public float LongitudinalSpeed => vx;
public float LongitudinalSpeed => ForwardFriction.Speed;
public bool IsSkiddingLongitudinally => NormalizedLongitudinalSlip > 0.35f; public bool IsSkiddingLongitudinally => NormalizedLongitudinalSlip > 0.35f;
public float NormalizedLongitudinalSlip => Math.Clamp( Math.Abs( LongitudinalSlip ), 0, 1 ); public float NormalizedLongitudinalSlip => Math.Clamp( Math.Abs( LongitudinalSlip ), 0, 1 );
public float LateralSlip => sy;
public float LateralSlip => SidewayFriction.Slip; public float LateralSpeed => vy;
public float LateralSpeed => SidewayFriction.Speed;
public bool IsSkiddingLaterally => NormalizedLateralSlip > 0.35f; public bool IsSkiddingLaterally => NormalizedLateralSlip > 0.35f;
public float NormalizedLateralSlip => Math.Clamp( Math.Abs( LateralSlip ), 0, 1 ); public float NormalizedLateralSlip => Math.Clamp( Math.Abs( LateralSlip ), 0, 1 );
public bool IsSkidding => IsSkiddingLaterally || IsSkiddingLongitudinally; public bool IsSkidding => IsSkiddingLaterally || IsSkiddingLongitudinally;
public float NormalizedSlip => (NormalizedLateralSlip + NormalizedLongitudinalSlip) / 2f; public float NormalizedSlip => (NormalizedLateralSlip + NormalizedLongitudinalSlip) / 2f;
// speed
[Sync] private float vx { get; set; }
[Sync] private float vy { get; set; }
// force
[Sync] private float fx { get; set; }
[Sync] private float fy { get; set; }
// slip
[Sync] private float sx { get; set; }
[Sync] private float sy { get; set; }
private void UpdateHitVariables() private void UpdateHitVariables()
{ {
if ( IsOnGround ) if ( IsOnGround )
@ -70,13 +80,13 @@ public partial class VeloXWheel
hitForwardDirection = ContactNormal.Cross( TransformRotationSteer.Right ).Normal; hitForwardDirection = ContactNormal.Cross( TransformRotationSteer.Right ).Normal;
hitSidewaysDirection = Rotation.FromAxis( ContactNormal, 90f ) * hitForwardDirection; hitSidewaysDirection = Rotation.FromAxis( ContactNormal, 90f ) * hitForwardDirection;
ForwardFriction.Speed = hitContactVelocity.Dot( hitForwardDirection ).InchToMeter(); vx = hitContactVelocity.Dot( hitForwardDirection ).InchToMeter();
SidewayFriction.Speed = hitContactVelocity.Dot( hitSidewaysDirection ).InchToMeter(); vy = hitContactVelocity.Dot( hitSidewaysDirection ).InchToMeter();
} }
else else
{ {
ForwardFriction = new(); vx = 0;
SidewayFriction = new(); vy = 0;
} }
} }
@ -112,9 +122,9 @@ public partial class VeloXWheel
float slipLoadModifier = 1f - loadPercent * 0.4f; float slipLoadModifier = 1f - loadPercent * 0.4f;
float mass = Vehicle.Body.Mass; float mass = Vehicle.Body.Mass;
float absForwardSpeed = Math.Abs( ForwardFriction.Speed ); float absForwardSpeed = Math.Abs( vx );
float forwardForceClamp = mass * LoadContribution * absForwardSpeed * invDt; float forwardForceClamp = mass * LoadContribution * absForwardSpeed * invDt;
float absSideSpeed = Math.Abs( SidewayFriction.Speed ); float absSideSpeed = Math.Abs( vy );
float sideForceClamp = mass * LoadContribution * absSideSpeed * invDt; float sideForceClamp = mass * LoadContribution * absSideSpeed * invDt;
float forwardSpeedClamp = 1.5f * (dt / 0.005f); float forwardSpeedClamp = 1.5f * (dt / 0.005f);
@ -124,7 +134,7 @@ public partial class VeloXWheel
float peakForwardFrictionForce = 11000 * (1 - MathF.Exp( -0.00014f * forwardLoadFactor )); float peakForwardFrictionForce = 11000 * (1 - MathF.Exp( -0.00014f * forwardLoadFactor ));
float absCombinedBrakeTorque = Math.Max( 0, brakeTorque + RollingResistanceTorque ); float absCombinedBrakeTorque = Math.Max( 0, brakeTorque + RollingResistanceTorque );
float signedCombinedBrakeTorque = absCombinedBrakeTorque * -Math.Sign( ForwardFriction.Speed ); float signedCombinedBrakeTorque = absCombinedBrakeTorque * (vx > 0 ? -1 : 1);
float signedCombinedBrakeForce = signedCombinedBrakeTorque * invRadius; float signedCombinedBrakeForce = signedCombinedBrakeTorque * invRadius;
float motorForce = motorTorque * invRadius; float motorForce = motorTorque * invRadius;
float forwardInputForce = motorForce + signedCombinedBrakeForce; float forwardInputForce = motorForce + signedCombinedBrakeForce;
@ -134,7 +144,7 @@ public partial class VeloXWheel
float maxForwardForce = Math.Min( peakForwardFrictionForce, forwardForceClamp ); float maxForwardForce = Math.Min( peakForwardFrictionForce, forwardForceClamp );
maxForwardForce = absMotorTorque < absBrakeTorque ? maxForwardForce : peakForwardFrictionForce; maxForwardForce = absMotorTorque < absBrakeTorque ? maxForwardForce : peakForwardFrictionForce;
ForwardFriction.Force = forwardInputForce > maxForwardForce ? maxForwardForce fx = forwardInputForce > maxForwardForce ? maxForwardForce
: forwardInputForce < -maxForwardForce ? -maxForwardForce : forwardInputForce; : forwardInputForce < -maxForwardForce ? -maxForwardForce : forwardInputForce;
wheelIsBlocked = false; wheelIsBlocked = false;
@ -153,14 +163,14 @@ public partial class VeloXWheel
AngularVelocity += combinedWheelForce * mRadius * invInertia * dt; AngularVelocity += combinedWheelForce * mRadius * invInertia * dt;
// Surface (corrective) force // Surface (corrective) force
float noSlipAngularVelocity = ForwardFriction.Speed * invRadius; float noSlipAngularVelocity = vx * invRadius;
float angularVelocityError = AngularVelocity - noSlipAngularVelocity; float angularVelocityError = AngularVelocity - noSlipAngularVelocity;
float angularVelocityCorrectionForce = Math.Clamp( -angularVelocityError * inertia * invRadius * invDt, -maxForwardForce, maxForwardForce ); float angularVelocityCorrectionForce = Math.Clamp( -angularVelocityError * inertia * invRadius * invDt, -maxForwardForce, maxForwardForce );
if ( absMotorTorque < absBrakeTorque && Math.Abs( wheelForceClampOverflow ) > Math.Abs( angularVelocityCorrectionForce ) ) if ( absMotorTorque < absBrakeTorque && Math.Abs( wheelForceClampOverflow ) > Math.Abs( angularVelocityCorrectionForce ) )
{ {
wheelIsBlocked = true; wheelIsBlocked = true;
AngularVelocity += ForwardFriction.Speed > 0 ? 1e-10f : -1e-10f; AngularVelocity += vx > 0 ? 1e-10f : -1e-10f;
} }
else else
{ {
@ -178,24 +188,24 @@ public partial class VeloXWheel
float absAngularVelocity = AngularVelocity < 0 ? -AngularVelocity : AngularVelocity; float absAngularVelocity = AngularVelocity < 0 ? -AngularVelocity : AngularVelocity;
float maxCounterTorque = inertia * absAngularVelocity; float maxCounterTorque = inertia * absAngularVelocity;
CounterTorque = Math.Clamp( (signedCombinedBrakeForce - ForwardFriction.Force) * mRadius, -maxCounterTorque, maxCounterTorque ); CounterTorque = Math.Clamp( (signedCombinedBrakeForce - fx) * mRadius, -maxCounterTorque, maxCounterTorque );
ForwardFriction.Slip = (ForwardFriction.Speed - AngularVelocity * mRadius) / clampedAbsForwardSpeed; sx = (vx - AngularVelocity * mRadius) / clampedAbsForwardSpeed;
ForwardFriction.Slip *= slipLoadModifier; sx *= slipLoadModifier;
SidewayFriction.Slip = MathF.Atan2( SidewayFriction.Speed, clampedAbsForwardSpeed ); sy = MathF.Atan2( vy, clampedAbsForwardSpeed );
SidewayFriction.Slip *= slipLoadModifier; sy *= slipLoadModifier;
float sideSlipSign = SidewayFriction.Slip > 0 ? 1 : -1; float sideSlipSign = sy > 0 ? 1 : -1;
float absSideSlip = Math.Abs( SidewayFriction.Slip ); float absSideSlip = Math.Abs( sy );
float peakSideFrictionForce = 18000 * (1 - MathF.Exp( -0.0001f * sideLoadFactor )); float peakSideFrictionForce = 18000 * (1 - MathF.Exp( -0.0001f * sideLoadFactor ));
float sideForce = -sideSlipSign * Tire.Evaluate( absSideSlip ) * peakSideFrictionForce; float sideForce = -sideSlipSign * Tire.Evaluate( absSideSlip ) * peakSideFrictionForce;
SidewayFriction.Force = Math.Clamp( sideForce, -sideForceClamp, sideForceClamp ); fy = Math.Clamp( sideForce, -sideForceClamp, sideForceClamp );
// Calculate effect of camber on friction // Calculate effect of camber on friction
float camberFrictionCoeff = Math.Max( 0, Vehicle.WorldRotation.Up.Dot( ContactNormal ) ); float camberFrictionCoeff = Math.Max( 0, Vehicle.WorldRotation.Up.Dot( ContactNormal ) );
SidewayFriction.Force *= camberFrictionCoeff; fy *= camberFrictionCoeff;
if ( IsOnGround && absForwardSpeed < 0.12f && absSideSpeed < 0.12f ) if ( IsOnGround && absForwardSpeed < 0.12f && absSideSpeed < 0.12f )
{ {
@ -225,9 +235,9 @@ public partial class VeloXWheel
if ( wheelIsBlocked && absAngularVelocity < 0.5f ) if ( wheelIsBlocked && absAngularVelocity < 0.5f )
{ {
ForwardFriction.Force += correctiveForce.Dot( hitForwardDirection ); fx += correctiveForce.Dot( hitForwardDirection );
} }
SidewayFriction.Force += correctiveForce.Dot( hitSidewaysDirection ); fy += correctiveForce.Dot( hitSidewaysDirection );
} }
} }
else else
@ -235,52 +245,21 @@ public partial class VeloXWheel
lowSpeedReferenceIsSet = false; lowSpeedReferenceIsSet = false;
} }
fx = Math.Clamp( fx, -peakForwardFrictionForce, peakForwardFrictionForce );
fy = Math.Clamp( fy, -peakSideFrictionForce, peakSideFrictionForce );
//float forwardSlipPercent = -ForwardFriction.Slip / Tire.GetPeakSlip(); if ( absForwardSpeed > 0.01f || absAngularVelocity > 0.01f )
//float sideSlipPercent = SidewayFriction.Slip / Tire.GetPeakSlip(); {
//float slipCircleLimit = MathF.Sqrt( forwardSlipPercent * forwardSlipPercent + sideSlipPercent * sideSlipPercent ); var f = MathF.Sqrt( fx * fx + fy * fy );
//if ( slipCircleLimit > 1f ) var d = Math.Abs( new Vector2( sx, sy ).Normal.y );
//{ fy = f * d * Math.Sign( fy );
// float beta = MathF.Atan2( sideSlipPercent, forwardSlipPercent * 1.05f );
// float sinBeta = MathF.Sin( beta );
// float cosBeta = MathF.Cos( beta );
// float absForwardForce = ForwardFriction.Force < 0 ? -ForwardFriction.Force : ForwardFriction.Force;
// float absSideForce = SidewayFriction.Force < 0 ? -SidewayFriction.Force : SidewayFriction.Force;
// float f = absForwardForce * cosBeta * cosBeta + absSideForce * sinBeta * sinBeta;
// ForwardFriction.Force = 0.5f * ForwardFriction.Force - f * cosBeta;
// SidewayFriction.Force = 0.5f * SidewayFriction.Force - f * sinBeta;
//}
//var slipVector = new Vector2(
// ForwardFriction.Slip,
// SidewayFriction.Slip
//);
//if ( slipVector.Length > 0.001f )
//{
// var frictionDirection = slipVector.Normal;
// float frictionMagnitude = MathF.Sqrt(
// ForwardFriction.Force * ForwardFriction.Force +
// SidewayFriction.Force * SidewayFriction.Force
// );
// ForwardFriction.Force = Math.Abs( frictionDirection.x ) * frictionMagnitude * Math.Sign( ForwardFriction.Force );
// SidewayFriction.Force = Math.Abs( frictionDirection.y ) * frictionMagnitude * Math.Sign( SidewayFriction.Force );
//}
var f = MathF.Sqrt( ForwardFriction.Force * ForwardFriction.Force + SidewayFriction.Force * SidewayFriction.Force );
var d = Math.Abs( new Vector2( ForwardFriction.Slip, SidewayFriction.Slip ).Normal.y );
SidewayFriction.Force = f * d * Math.Sign( SidewayFriction.Force );
}
if ( IsOnGround ) if ( IsOnGround )
{ {
FrictionForce.x = (hitSidewaysDirection.x * SidewayFriction.Force + hitForwardDirection.x * ForwardFriction.Force).MeterToInch(); FrictionForce.x = (hitSidewaysDirection.x * fy + hitForwardDirection.x * fx).MeterToInch();
FrictionForce.y = (hitSidewaysDirection.y * SidewayFriction.Force + hitForwardDirection.y * ForwardFriction.Force).MeterToInch(); FrictionForce.y = (hitSidewaysDirection.y * fy + hitForwardDirection.y * fx).MeterToInch();
FrictionForce.z = (hitSidewaysDirection.z * SidewayFriction.Force + hitForwardDirection.z * ForwardFriction.Force).MeterToInch(); FrictionForce.z = (hitSidewaysDirection.z * fy + hitForwardDirection.z * fx).MeterToInch();
//DebugOverlay.Normal( WorldPosition, hitSidewaysDirection * 10, overlay: true, color: Color.Red ); //DebugOverlay.Normal( WorldPosition, hitSidewaysDirection * 10, overlay: true, color: Color.Red );
//DebugOverlay.Normal( WorldPosition, hitForwardDirection * 10, overlay: true, color: Color.Green ); //DebugOverlay.Normal( WorldPosition, hitForwardDirection * 10, overlay: true, color: Color.Green );

View File

@ -34,7 +34,7 @@ public partial class VeloXWheel
{ {
GameObject go = new() GameObject go = new()
{ {
WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * (Radius.MeterToInch() - 0.01f), WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * (Radius.MeterToInch() - 1f),
WorldRotation = Rotation.LookAt( hitSidewaysDirection ) WorldRotation = Rotation.LookAt( hitSidewaysDirection )
}; };
_skidMark = go.AddComponent<LineRenderer>(); _skidMark = go.AddComponent<LineRenderer>();
@ -53,8 +53,7 @@ public partial class VeloXWheel
protected void UpdateSkid() protected void UpdateSkid()
{ {
if ( IsProxy )
return;
while ( SkidMarks.Count > MaxSkid ) while ( SkidMarks.Count > MaxSkid )
{ {
SkidMarks.Dequeue()?.DestroyGameObject(); SkidMarks.Dequeue()?.DestroyGameObject();
@ -81,7 +80,7 @@ public partial class VeloXWheel
GameObject go = new() GameObject go = new()
{ {
Parent = _skidMark.GameObject, Parent = _skidMark.GameObject,
WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * Radius.MeterToInch(), WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * (Radius.MeterToInch() - 1f),
WorldRotation = Rotation.LookAt( ContactNormal.RotateAround( Vector3.Zero, Rotation.FromRoll( 90 ) ) ) WorldRotation = Rotation.LookAt( ContactNormal.RotateAround( Vector3.Zero, Rotation.FromRoll( 90 ) ) )
}; };
go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true ); go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true );

View File

@ -8,9 +8,8 @@ namespace VeloX;
public partial class VeloXWheel public partial class VeloXWheel
{ {
private static readonly GameObject SmokePrefab = GameObject.GetPrefab( "prefabs/particles/tire_smoke.prefab" );
private GameObject SmokeObject { get; set; } private GameObject SmokeObject;
public const float MIN_DRIFT_ANGLE = 10f; public const float MIN_DRIFT_ANGLE = 10f;
public const float MIN_DRIFT_SPEED = 30f; public const float MIN_DRIFT_SPEED = 30f;
public const float MAX_DRIFT_ANGLE = 110f; public const float MAX_DRIFT_ANGLE = 110f;
@ -19,11 +18,13 @@ public partial class VeloXWheel
protected override void OnStart() protected override void OnStart()
{ {
base.OnStart(); base.OnStart();
if ( IsProxy )
return;
if ( !SmokeObject.IsValid() )
SmokeObject = GameObject.GetPrefab( "prefabs/particles/tire_smoke.prefab" ).Clone( new CloneConfig() { Parent = GameObject, StartEnabled = true } ); SmokeObject = GameObject.GetPrefab( "prefabs/particles/tire_smoke.prefab" ).Clone( new CloneConfig() { Parent = GameObject, StartEnabled = true } );
SmokeObject.Flags = SmokeObject.Flags.WithFlag( GameObjectFlags.NotNetworked, true );
var emitter = SmokeObject.Components.Get<ParticleSphereEmitter>( FindMode.EverythingInSelfAndDescendants );
emitter.Enabled = false;
} }
public float GetSlip() public float GetSlip()
{ {
@ -36,12 +37,8 @@ public partial class VeloXWheel
// return val; // return val;
return val * 5; return val * 5;
} }
protected override void OnUpdate() private void UpdateSmoke()
{ {
base.OnUpdate();
if ( IsProxy )
return;
UpdateSkid();
SmokeObject.WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * Radius.MeterToInch(); SmokeObject.WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * Radius.MeterToInch();
smokeMul = Math.Max( 0, GetSlip() - 3 ); smokeMul = Math.Max( 0, GetSlip() - 3 );

View File

@ -29,7 +29,7 @@ public partial class VeloXWheel : Component
public float RPM { get => AngularVelocity * 60f / MathF.Tau; set => AngularVelocity = value / (60 / MathF.Tau); } public float RPM { get => AngularVelocity * 60f / MathF.Tau; set => AngularVelocity = value / (60 / MathF.Tau); }
private Vector3 StartPos { get; set; } [Sync] private Vector3 StartPos { get; set; }
private static Rotation CylinderOffset = Rotation.FromRoll( 90 ); private static Rotation CylinderOffset = Rotation.FromRoll( 90 );
[Sync] public bool IsOnGround { get; private set; } [Sync] public bool IsOnGround { get; private set; }
@ -39,13 +39,13 @@ public partial class VeloXWheel : Component
[Property] public float BrakeTorque { get; set; } [Property] public float BrakeTorque { get; set; }
public float Compression { get; protected set; } // meters public float Compression { get; protected set; } // meters
public float LastLength { get; protected set; } // meters [Sync( SyncFlags.Interpolate )] public float LastLength { get; protected set; } // meters
public float Fz { get; protected set; } // N public float Fz { get; protected set; } // N
public float AngularVelocity { get; protected set; } // rad/s public float AngularVelocity { get; protected set; } // rad/s
public float RollAngle { get; protected set; } // degrees [Sync( SyncFlags.Interpolate )] public float RollAngle { get; protected set; }
private VeloXBase Vehicle; public VeloXBase Vehicle { get; private set; }
[Sync] public Vector3 ContactNormal { get; protected set; } [Sync] public Vector3 ContactNormal { get; protected set; }
[Sync] public Vector3 ContactPosition { get; protected set; } [Sync] public Vector3 ContactPosition { get; protected set; }
Rotation TransformRotationSteer => Vehicle.WorldTransform.RotationToWorld( Vehicle.SteerAngle * SteerMultiplier ); Rotation TransformRotationSteer => Vehicle.WorldTransform.RotationToWorld( Vehicle.SteerAngle * SteerMultiplier );
@ -59,15 +59,9 @@ public partial class VeloXWheel : Component
Inertia = BaseInertia; Inertia = BaseInertia;
} }
internal void Update( VeloXBase vehicle, in float dt ) private void UpdateVisuals()
{ {
UpdateVisuals( vehicle, dt ); WorldRotation = Vehicle.WorldTransform.RotationToWorld( Vehicle.SteerAngle * SteerMultiplier ).RotateAroundAxis( Vector3.Right, -RollAngle );
}
private void UpdateVisuals( VeloXBase vehicle, in float dt )
{
WorldRotation = vehicle.WorldTransform.RotationToWorld( vehicle.SteerAngle * SteerMultiplier ).RotateAroundAxis( Vector3.Right, -RollAngle );
LocalPosition = StartPos + Vector3.Down * LastLength.MeterToInch(); LocalPosition = StartPos + Vector3.Down * LastLength.MeterToInch();
} }
@ -213,4 +207,15 @@ public partial class VeloXWheel : Component
RollAngle += MathX.RadianToDegree( AngularVelocity ) * dt; RollAngle += MathX.RadianToDegree( AngularVelocity ) * dt;
RollAngle = (RollAngle % 360f + 360f) % 360f; RollAngle = (RollAngle % 360f + 360f) % 360f;
} }
protected override void OnFixedUpdate()
{
UpdateSmoke();
}
protected override void OnUpdate()
{
UpdateVisuals();
UpdateSkid();
}
} }

View File

@ -1,6 +1,5 @@
using Sandbox; using Sandbox;
using System.Linq; using System.Linq;
using static Sandbox.Services.Inventory;
namespace VeloX; namespace VeloX;
internal sealed class WheelManager : GameObjectSystem internal sealed class WheelManager : GameObjectSystem
@ -23,17 +22,17 @@ internal sealed class WheelManager : GameObjectSystem
if ( !wheels.Any() ) return; if ( !wheels.Any() ) return;
var timeDelta = Time.Delta; var timeDelta = Time.Delta;
Sandbox.Utility.Parallel.ForEach( wheels, item => //Sandbox.Utility.Parallel.ForEach( wheels, item =>
{ //{
if ( !item.IsProxy && item.IsValid() )
item.DoPhysics( timeDelta );
} );
//foreach ( var item in wheels )
// if ( !item.IsProxy && item.IsValid() ) // if ( !item.IsProxy && item.IsValid() )
// item.DoPhysics( timeDelta ); // item.DoPhysics( timeDelta );
//} );
foreach ( var item in wheels )
if ( item.IsValid() && !item.IsProxy )
item.DoPhysics( timeDelta );
foreach ( var wheel in wheels ) foreach ( var wheel in wheels )
if ( !wheel.IsProxy && wheel.IsValid() ) if ( wheel.IsValid() && !wheel.IsProxy)
wheel.UpdateForce(); wheel.UpdateForce();
//sw.Stop(); //sw.Stop();
@ -50,15 +49,15 @@ internal sealed class WheelManager : GameObjectSystem
if ( !engines.Any() ) return; if ( !engines.Any() ) return;
var timeDelta = Time.Delta; var timeDelta = Time.Delta;
Sandbox.Utility.Parallel.ForEach( engines, item => //Sandbox.Utility.Parallel.ForEach( engines, item =>
{ //{
foreach ( var wheel in engines ) // foreach ( var wheel in engines )
if ( !wheel.IsProxy && wheel.IsValid() )
wheel.UpdateEngine( timeDelta );
} );
//foreach ( var wheel in engines )
// if ( !wheel.IsProxy && wheel.IsValid() ) // if ( !wheel.IsProxy && wheel.IsValid() )
// wheel.UpdateEngine( timeDelta ); // wheel.UpdateEngine( timeDelta );
//} );
foreach ( var wheel in engines )
if ( wheel.IsValid() )
wheel.UpdateEngine( timeDelta );
//sw.Stop(); //sw.Stop();

View File

@ -7,23 +7,14 @@ namespace VeloX;
[Title( "VeloX - Car" )] [Title( "VeloX - Car" )]
public partial class VeloXCar : VeloXBase public partial class VeloXCar : VeloXBase
{ {
protected override void FixedUpdate()
{
UpdateInput();
PhysicsSimulate();
UpdateABS();
UpdateESC();
}
protected override void OnFixedUpdate() protected override void OnFixedUpdate()
{ {
if ( IsProxy )
return;
base.OnFixedUpdate(); base.OnFixedUpdate();
if ( IsProxy )
return;
UpdateABS();
UpdateESC();
var dt = Time.Delta; var dt = Time.Delta;
//EngineThink( dt ); //EngineThink( dt );
SimulateAerodinamics( dt ); SimulateAerodinamics( dt );

View File

@ -10,7 +10,7 @@ namespace VeloX;
public class EngineStreamPlayer( EngineStream stream ) : IDisposable public class EngineStreamPlayer( EngineStream stream ) : IDisposable
{ {
private static readonly Mixer EngineMixer = Mixer.FindMixerByName( "Car Engine" ); private static readonly Mixer EngineMixer = Mixer.FindMixerByName( "Engine" );
public EngineStream Stream { get; set; } = stream; public EngineStream Stream { get; set; } = stream;
public EngineState EngineState { get; set; } public EngineState EngineState { get; set; }
@ -103,6 +103,7 @@ public class EngineStreamPlayer( EngineStream stream ) : IDisposable
channel.Position = position; channel.Position = position;
channel.ListenLocal = isLocal; channel.ListenLocal = isLocal;
channel.Paused = EngineSoundPaused || layer.IsMuted; channel.Paused = EngineSoundPaused || layer.IsMuted;
channel.FollowParent = true;
channel.TargetMixer = EngineMixer; channel.TargetMixer = EngineMixer;
} }