6 [
Attribute(
"0", UIWidgets.Auto,
"Vehicle index in ParticleEffectInfo")]
9 [
Attribute(
"", UIWidgets.Auto,
"Simulation IDs of wheels to apply particle effects to")]
10 ref array<int> m_aWheels;
12 [
Attribute(
"10", UIWidgets.Slider,
"Minimal speed for 0% effect intensity interpolation\n[km/h]",
"0 300 1")]
13 float m_fDustStartSpeed;
15 [
Attribute(
"80", UIWidgets.Slider,
"Maximal speed for 100% effect intensity interpolation\n[km/h]",
"0 300 1")]
16 float m_fDustTopSpeed;
18 [
Attribute(
"250", UIWidgets.Slider,
"Maximal distance at which the effect is visible\n[m]",
"0 2000 1")]
19 float m_fMaxDistanceVisible;
21 float m_fMaxDistanceVisibleSqr;
23 override static array<typename> Requires(IEntityComponentSource src)
25 array<typename> requires =
new array<typename>;
27 requires.Insert(RplComponent);
36 vector m_vLocalDustPos;
37 bool m_bWheelHasContact;
40 ParticleEffectEntity m_pParticleEffectEntity;
45 protected static const float UPDATE_TIME = 1.0 / 30.0;
46 static const int UPDATE_TIMEOUT = 1000;
48 protected VehicleWheeledSimulation m_Simulation;
49 protected VehicleWheeledSimulation_SA m_Simulation_SA;
50 protected Physics m_Physics;
51 protected NwkMovementComponent m_NwkMovementComponent;
53 protected RplComponent m_RplComponent;
54 protected ref array<ref VehicleDust> m_aVehicleDusts = {};
55 protected float m_fUpdateTime;
56 protected float m_fTime;
57 protected IEntity m_pOwner;
60 override void OnPostInit(IEntity owner)
64 if (System.IsConsoleApp())
82 m_NwkMovementComponent = NwkMovementComponent.Cast(m_pOwner.FindComponent(NwkMovementComponent));
86 m_RplComponent = RplComponent.Cast(owner.FindComponent(RplComponent));
90 m_Simulation = VehicleWheeledSimulation.Cast(m_pOwner.FindComponent(VehicleWheeledSimulation));
99 m_Simulation_SA = VehicleWheeledSimulation_SA.Cast(m_pOwner.FindComponent(VehicleWheeledSimulation_SA));
100 if (!m_Simulation_SA || !m_Simulation_SA.IsValid())
110 SetEventMask(owner, EntityEvent.INIT);
113 override void OnDelete(IEntity owner)
115 DisconnectFromVehiclesDustSystem();
117 super.OnDelete(owner);
121 override bool OnTicksOnRemoteProxy()
127 override void EOnInit(IEntity owner)
129 super.EOnInit(owner);
131 ConnectToVehiclesDustSystem();
137 count = Math.Min(m_Simulation_SA.WheelCount(),
m_ComponentData.m_aWheels.Count());
139 m_aVehicleDusts.Resize(count);
140 for (
int i = 0; i < count; ++i)
144 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_PARTICLES_VEHICLE_DUST,
"",
"Show dust materials",
"Vehicles");
148 protected void ConnectToVehiclesDustSystem()
150 World world =
GetOwner().GetWorld();
155 updateSystem.Register(
this);
158 protected void DisconnectFromVehiclesDustSystem()
160 World world =
GetOwner().GetWorld();
165 updateSystem.Unregister(
this);
169 void Update(
float timeSlice)
176 else if (m_NwkMovementComponent && !m_NwkMovementComponent.IsInterpolating())
186 m_fUpdateTime = -1.0;
193 m_fUpdateTime = -1.0;
197 if (m_fUpdateTime < 0.0 || m_fTime >= m_fUpdateTime)
206 protected void UpdateBatch()
209 m_pOwner.GetWorld().GetCurrentCamera(camMat);
211 float distanceFromCamera = vector.DistanceSq(m_pOwner.GetOrigin(), camMat[3]);
216 speed = m_Simulation_SA.GetSpeedKmh();
220 UpdateEffect(vehicleDust,
index, speed, distanceFromCamera);
225 protected TraceParam TraceWheelContact(
int index, out vector
position)
229 vector worldTransform[4];
230 m_pOwner.GetWorldTransform(worldTransform);
237 radius = m_Simulation_SA.WheelGetRadiusState(wheelIdx);
240 Physics physics = m_pOwner.GetPhysics();
241 vector centerOfMass = physics.GetCenterOfMass();
243 TraceParam trace =
new TraceParam();
246 trace.Start = (
m_Simulation.WheelGetPosition(wheelIdx, 1.0) + centerOfMass).Multiply4(worldTransform);
247 trace.End = (
m_Simulation.WheelGetPosition(wheelIdx, 0.0) + centerOfMass).Multiply4(worldTransform) + worldTransform[1] * -radius;
251 trace.Start = (m_Simulation_SA.WheelGetPosition(wheelIdx, 1.0) + centerOfMass).Multiply4(worldTransform);
252 trace.End = (m_Simulation_SA.WheelGetPosition(wheelIdx, 0.0) + centerOfMass).Multiply4(worldTransform) + worldTransform[1] * -radius;
255 trace.Flags = TraceFlags.WORLD;
256 trace.LayerMask = EPhysicsLayerDefs.VehicleCast;
258 float hit = m_pOwner.GetWorld().TraceMove(trace,
null);
260 vector remotePosition = trace.Start + (trace.End - trace.Start) * hit;
261 position = remotePosition.InvMultiply4(worldTransform);
269 Shape.CreateLines(Color.BLUE, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER, p, 2);
270 Shape.CreateSphere(Color.RED, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER, remotePosition, 0.05);
278 protected void UpdateEffect(
VehicleDust vehicleDust,
int index,
float speed,
float distanceFromCamera)
282 if (speed < m_ComponentData.m_fDustStartSpeed || distanceFromCamera >=
m_ComponentData.m_fMaxDistanceVisibleSqr)
284 vehicleDust.m_Material =
null;
285 if (vehicleDust.m_pParticleEffectEntity)
287 vehicleDust.m_pParticleEffectEntity.StopEmission();
288 UpdatePosition(vehicleDust, wheelIdx);
293 int ticks = System.GetTickCount();
294 int dif = Math.AbsInt(ticks - vehicleDust.m_iLastSwap);
296 if (vehicleDust.m_pParticleEffectEntity && dif < UPDATE_TIMEOUT)
298 UpdateCurrent(vehicleDust, speed, wheelIdx);
303 bool wheelHasContact;
310 newMaterial = trace.SurfaceProps;
311 wheelHasContact = trace.TraceEnt !=
null;
312 vehicleDust.m_vLocalDustPos =
position;
319 if (
m_Simulation.WheelGetContactLiquidState(wheelIdx) > 0)
320 newMaterial =
m_Simulation.WheelGetContactLiquidMaterial(wheelIdx);
322 newMaterial =
m_Simulation.WheelGetContactMaterial(wheelIdx);
324 wheelHasContact =
m_Simulation.WheelHasContact(wheelIdx);
328 if (m_Simulation_SA.WheelGetContactLiquidState(wheelIdx) > 0)
329 newMaterial = m_Simulation_SA.WheelGetContactLiquidMaterial(wheelIdx);
331 newMaterial = m_Simulation_SA.WheelGetContactMaterial(wheelIdx);
333 wheelHasContact = m_Simulation_SA.WheelHasContact(wheelIdx);
337 vehicleDust.m_bWheelHasContact = wheelHasContact;
340 ResourceName newResource;
342 if (newMaterial && newMaterial != currentMaterial)
346 newResource = effectInfo.GetVehicleDustResource(
m_ComponentData.m_iVehicleIndex);
350 if (currentMaterial && vehicleDust.m_pParticleEffectEntity && (newMaterial == currentMaterial || (currentMaterial.GetParticleEffectInfo() && currentMaterial.GetParticleEffectInfo().GetResourceName() == newResource)))
352 if (newMaterial != currentMaterial)
354 vehicleDust.m_Material = newMaterial;
357 UpdateCurrent(vehicleDust, speed, wheelIdx);
361 vehicleDust.m_Material = newMaterial;
362 if (vehicleDust.m_pParticleEffectEntity)
364 vehicleDust.m_pParticleEffectEntity.StopEmission();
365 vehicleDust.m_pParticleEffectEntity =
null;
369 if (newResource && newResource.Length() > 0)
371 ParticleEffectEntitySpawnParams spawnParams();
372 spawnParams.TargetWorld =
GetOwner().GetWorld();
374 spawnParams.UseFrameEvent =
true;
375 vehicleDust.m_pParticleEffectEntity = ParticleEffectEntity.SpawnParticleEffect(newResource, spawnParams);
376 vehicleDust.m_iLastSwap = ticks;
379 UpdateCurrent(vehicleDust, speed, wheelIdx);
383 protected void UpdateCurrent(
VehicleDust vehicleDust,
float speed,
int wheelIdx)
385 if (!vehicleDust.m_pParticleEffectEntity)
388 UpdatePosition(vehicleDust, wheelIdx);
389 UpdateVehicleDustEffect(vehicleDust, speed, wheelIdx);
393 protected void UpdatePosition(
VehicleDust vehicleDust,
int wheelIdx)
398 vector worldTransform[4];
399 GetOwner().GetWorldTransform(worldTransform);
400 position = vehicleDust.m_vLocalDustPos.Multiply4(worldTransform);
413 if(!m_Simulation_SA.WheelHasContact(wheelIdx))
416 position = m_Simulation_SA.WheelGetContactPosition(wheelIdx);
420 vehicleDust.m_pParticleEffectEntity.SetOrigin(
position);
424 protected void UpdateVehicleDustEffect(
VehicleDust vehicleDust,
float speed,
int wheelIdx)
429 float gravityCoef = 0;
431 float longitudinalSlip = 0;
432 float lateralSlip = 0;
436 longitudinalSlip =
m_Simulation.WheelGetLongitudinalSlip(wheelIdx);
437 lateralSlip =
m_Simulation.WheelGetLateralSlip(wheelIdx);
441 longitudinalSlip = m_Simulation_SA.WheelGetLongitudinalSlip(wheelIdx);
442 lateralSlip = m_Simulation_SA.WheelGetLateralSlip(wheelIdx);
445 float effectiveSlip = Math.Clamp(longitudinalSlip + lateralSlip, 0, 1);
447 if (vehicleDust.m_bWheelHasContact)
449 speedCoef = Math.AbsFloat(0.5 + speed * 0.5 / endSpeed + effectiveSlip);
450 birthCoef = Math.AbsFloat(0.5 + speed * 0.5 / endSpeed + effectiveSlip * 2);
451 gravityCoef = Math.AbsFloat(0.8 + speed * 0.2 / endSpeed);
454 Particles particles = vehicleDust.m_pParticleEffectEntity.GetParticles();
455 particles.MultParam(-1, EmitterParam.BIRTH_RATE, birthCoef);
456 particles.MultParam(-1, EmitterParam.GRAVITY_SCALE_RND, gravityCoef);
457 particles.MultParam(-1, EmitterParam.VELOCITY, speedCoef);
458 particles.MultParam(-1, EmitterParam.VELOCITY_RND, speedCoef);
464 if (!vehicleDust.m_bWheelHasContact)
467 if (!vehicleDust.m_Material)
470 vector effectPosition = vehicleDust.m_pParticleEffectEntity.GetWorldTransformAxis(3);
471 DebugTextWorldSpace.Create(
GetOwner().GetWorld(), vehicleDust.m_Material.GetName() +
"\nlongSlip: " + longitudinalSlip.ToString(-1, 3) +
" latSlip: " + lateralSlip.ToString(-1, 3), DebugTextFlags.CENTER | DebugTextFlags.ONCE, effectPosition[0], effectPosition[1] - 1, effectPosition[2]);