Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_VehicleDustPerWheelComponent.c
Go to the documentation of this file.
1 // Spawns dust particle effect that drags with the vehicle during ride
2 
3 [ComponentEditorProps(category: "GameScripted/Test", description:"SCR_VehicleDustPerWheel")]
5 {
6  [Attribute("0", UIWidgets.Auto, "Vehicle index in ParticleEffectInfo")]
7  int m_iVehicleIndex;
8 
9  [Attribute("", UIWidgets.Auto, "Simulation IDs of wheels to apply particle effects to")]
10  ref array<int> m_aWheels;
11 
12  [Attribute("10", UIWidgets.Slider, "Minimal speed for 0% effect intensity interpolation\n[km/h]", "0 300 1")]
13  float m_fDustStartSpeed;
14 
15  [Attribute("80", UIWidgets.Slider, "Maximal speed for 100% effect intensity interpolation\n[km/h]", "0 300 1")]
16  float m_fDustTopSpeed;
17 
18  [Attribute("250", UIWidgets.Slider, "Maximal distance at which the effect is visible\n[m]", "0 2000 1")]
19  float m_fMaxDistanceVisible;
20 
21  float m_fMaxDistanceVisibleSqr;
22 
23  override static array<typename> Requires(IEntityComponentSource src)
24  {
25  array<typename> requires = new array<typename>;
26 
27  requires.Insert(RplComponent);
28 
29  return requires;
30  }
31 };
32 
35 {
36  vector m_vLocalDustPos;
37  bool m_bWheelHasContact;
38  int m_iLastSwap;
39  GameMaterial m_Material;
40  ParticleEffectEntity m_pParticleEffectEntity;
41 };
42 
43 class SCR_VehicleDustPerWheel : ScriptGameComponent
44 {
45  protected static const float UPDATE_TIME = 1.0 / 30.0;
46  static const int UPDATE_TIMEOUT = 1000; //Minimal delay between two particle swaps.
47 
48  protected VehicleWheeledSimulation m_Simulation;
49  protected VehicleWheeledSimulation_SA m_Simulation_SA;
50  protected Physics m_Physics;
51  protected NwkMovementComponent m_NwkMovementComponent;
52  protected SCR_VehicleDustPerWheelClass m_ComponentData;
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;
58 
59  //------------------------------------------------------------------------------------------------
60  override void OnPostInit(IEntity owner)
61  {
62  m_pOwner = owner;
63 
64  if (System.IsConsoleApp())
65  {
66  Deactivate(m_pOwner);
67  return;
68  }
69 
70  m_ComponentData = SCR_VehicleDustPerWheelClass.Cast(GetComponentData(m_pOwner));
71  if (!m_ComponentData || m_ComponentData.m_fDustStartSpeed > m_ComponentData.m_fDustTopSpeed || m_ComponentData.m_fMaxDistanceVisible <= 0)
72  {
73  Deactivate(m_pOwner);
74  return;
75  }
76 
77  if (!m_ComponentData.m_fMaxDistanceVisibleSqr)
78  {
79  m_ComponentData.m_fMaxDistanceVisibleSqr = m_ComponentData.m_fMaxDistanceVisible * m_ComponentData.m_fMaxDistanceVisible;
80  }
81 
82  m_NwkMovementComponent = NwkMovementComponent.Cast(m_pOwner.FindComponent(NwkMovementComponent));
83 
84  m_Physics = m_pOwner.GetPhysics();
85 
86  m_RplComponent = RplComponent.Cast(owner.FindComponent(RplComponent));
87 
89  {
90  m_Simulation = VehicleWheeledSimulation.Cast(m_pOwner.FindComponent(VehicleWheeledSimulation));
91  if (!m_Simulation || !m_Simulation.IsValid())
92  {
93  Deactivate(m_pOwner);
94  return;
95  }
96  }
97  else
98  {
99  m_Simulation_SA = VehicleWheeledSimulation_SA.Cast(m_pOwner.FindComponent(VehicleWheeledSimulation_SA));
100  if (!m_Simulation_SA || !m_Simulation_SA.IsValid())
101  {
102  Deactivate(m_pOwner);
103  return;
104  }
105  }
106 
107  m_fUpdateTime = UPDATE_TIME;
108  m_fTime = 0.0;
109 
110  SetEventMask(owner, EntityEvent.INIT);
111  }
112 
113  override void OnDelete(IEntity owner)
114  {
115  DisconnectFromVehiclesDustSystem();
116 
117  super.OnDelete(owner);
118  }
119 
120  //------------------------------------------------------------------------------------------------
121  override bool OnTicksOnRemoteProxy()
122  {
123  return true;
124  }
125 
126  //------------------------------------------------------------------------------------------------
127  override void EOnInit(IEntity owner)
128  {
129  super.EOnInit(owner);
130 
131  ConnectToVehiclesDustSystem();
132 
133  int count;
135  count = Math.Min(m_Simulation.WheelCount(), m_ComponentData.m_aWheels.Count());
136  else
137  count = Math.Min(m_Simulation_SA.WheelCount(), m_ComponentData.m_aWheels.Count());
138 
139  m_aVehicleDusts.Resize(count);
140  for (int i = 0; i < count; ++i)
141  m_aVehicleDusts[i] = new VehicleDust();
142 
143 #ifdef ENABLE_DIAG
144  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_PARTICLES_VEHICLE_DUST, "", "Show dust materials", "Vehicles");
145 #endif
146  }
147 
148  protected void ConnectToVehiclesDustSystem()
149  {
150  World world = GetOwner().GetWorld();
151  VehiclesDustSystem updateSystem = VehiclesDustSystem.Cast(world.FindSystem(VehiclesDustSystem));
152  if (!updateSystem)
153  return;
154 
155  updateSystem.Register(this);
156  }
157 
158  protected void DisconnectFromVehiclesDustSystem()
159  {
160  World world = GetOwner().GetWorld();
161  VehiclesDustSystem updateSystem = VehiclesDustSystem.Cast(world.FindSystem(VehiclesDustSystem));
162  if (!updateSystem)
163  return;
164 
165  updateSystem.Unregister(this);
166  }
167 
168  //------------------------------------------------------------------------------------------------
169  void Update(float timeSlice)
170  {
171  if (!m_RplComponent.IsProxy() || m_RplComponent.IsOwner())
172  {
173  if ((!m_Physics || !m_Physics.IsActive()))
174  return;
175  }
176  else if (m_NwkMovementComponent && !m_NwkMovementComponent.IsInterpolating())
177  {
178  return;
179  }
180 
182  {
183  if (m_Simulation.GetSpeedKmh() < m_ComponentData.m_fDustStartSpeed)
184  m_fUpdateTime = UPDATE_TIME;
185  else
186  m_fUpdateTime = -1.0;
187  }
188  else
189  {
190  if (m_Simulation_SA.GetSpeedKmh() < m_ComponentData.m_fDustStartSpeed)
191  m_fUpdateTime = UPDATE_TIME;
192  else
193  m_fUpdateTime = -1.0;
194  }
195 
196  m_fTime += timeSlice;
197  if (m_fUpdateTime < 0.0 || m_fTime >= m_fUpdateTime)
198  {
199  m_fTime = 0.0;
200 
201  UpdateBatch();
202  }
203  }
204 
205  //------------------------------------------------------------------------------------------------
206  protected void UpdateBatch()
207  {
208  vector camMat[4];
209  m_pOwner.GetWorld().GetCurrentCamera(camMat);
210 
211  float distanceFromCamera = vector.DistanceSq(m_pOwner.GetOrigin(), camMat[3]);
212  float speed;
214  speed = m_Simulation.GetSpeedKmh();
215  else
216  speed = m_Simulation_SA.GetSpeedKmh();
217 
218  foreach (int index, VehicleDust vehicleDust : m_aVehicleDusts)
219  {
220  UpdateEffect(vehicleDust, index, speed, distanceFromCamera);
221  }
222  }
223 
224  //------------------------------------------------------------------------------------------------
225  protected TraceParam TraceWheelContact(int index, out vector position)
226  {
227  int wheelIdx = m_ComponentData.m_aWheels[index];
228 
229  vector worldTransform[4];
230  m_pOwner.GetWorldTransform(worldTransform);
231 
232  float radius;
233 
235  radius = m_Simulation.WheelGetRadiusState(wheelIdx);
236  else
237  radius = m_Simulation_SA.WheelGetRadiusState(wheelIdx);
238 
239  // Physics are offset by center of mass
240  Physics physics = m_pOwner.GetPhysics();
241  vector centerOfMass = physics.GetCenterOfMass();
242 
243  TraceParam trace = new TraceParam();
245  {
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;
248  }
249  else
250  {
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;
253  }
254 
255  trace.Flags = TraceFlags.WORLD;
256  trace.LayerMask = EPhysicsLayerDefs.VehicleCast;
257 
258  float hit = m_pOwner.GetWorld().TraceMove(trace, null);
259 
260  vector remotePosition = trace.Start + (trace.End - trace.Start) * hit;
261  position = remotePosition.InvMultiply4(worldTransform);
262 
263 #ifdef ENABLE_DIAG
264  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_PARTICLES_VEHICLE_DUST))
265  {
266  vector p[2];
267  p[0] = trace.Start;
268  p[1] = trace.End;
269  Shape.CreateLines(Color.BLUE, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER, p, 2);
270  Shape.CreateSphere(Color.RED, ShapeFlags.ONCE | ShapeFlags.NOZBUFFER, remotePosition, 0.05);
271  }
272 #endif
273 
274  return trace;
275  }
276 
277  //------------------------------------------------------------------------------------------------
278  protected void UpdateEffect(VehicleDust vehicleDust, int index, float speed, float distanceFromCamera)
279  {
280  int wheelIdx = m_ComponentData.m_aWheels[index];
281 
282  if (speed < m_ComponentData.m_fDustStartSpeed || distanceFromCamera >= m_ComponentData.m_fMaxDistanceVisibleSqr)
283  {
284  vehicleDust.m_Material = null;
285  if (vehicleDust.m_pParticleEffectEntity)
286  {
287  vehicleDust.m_pParticleEffectEntity.StopEmission();
288  UpdatePosition(vehicleDust, wheelIdx);
289  }
290  return;
291  }
292 
293  int ticks = System.GetTickCount();
294  int dif = Math.AbsInt(ticks - vehicleDust.m_iLastSwap);
295 
296  if (vehicleDust.m_pParticleEffectEntity && dif < UPDATE_TIMEOUT)
297  {
298  UpdateCurrent(vehicleDust, speed, wheelIdx);
299  return;
300  }
301 
302  GameMaterial newMaterial;
303  bool wheelHasContact;
304  if (m_RplComponent && m_RplComponent.IsRemoteProxy())
305  {
306  vector position;
307  TraceParam trace = TraceWheelContact(index, position);
308  if (trace)
309  {
310  newMaterial = trace.SurfaceProps;
311  wheelHasContact = trace.TraceEnt != null;
312  vehicleDust.m_vLocalDustPos = position;
313  }
314  }
315  else
316  {
318  {
319  if (m_Simulation.WheelGetContactLiquidState(wheelIdx) > 0)
320  newMaterial = m_Simulation.WheelGetContactLiquidMaterial(wheelIdx);
321  else
322  newMaterial = m_Simulation.WheelGetContactMaterial(wheelIdx);
323 
324  wheelHasContact = m_Simulation.WheelHasContact(wheelIdx);
325  }
326  else
327  {
328  if (m_Simulation_SA.WheelGetContactLiquidState(wheelIdx) > 0)
329  newMaterial = m_Simulation_SA.WheelGetContactLiquidMaterial(wheelIdx);
330  else
331  newMaterial = m_Simulation_SA.WheelGetContactMaterial(wheelIdx);
332 
333  wheelHasContact = m_Simulation_SA.WheelHasContact(wheelIdx);
334  }
335  }
336 
337  vehicleDust.m_bWheelHasContact = wheelHasContact;
338 
339  GameMaterial currentMaterial = vehicleDust.m_Material;
340  ResourceName newResource;
341 
342  if (newMaterial && newMaterial != currentMaterial) //different materials -> check resource
343  {
344  ParticleEffectInfo effectInfo = newMaterial.GetParticleEffectInfo();
345  if (effectInfo)
346  newResource = effectInfo.GetVehicleDustResource(m_ComponentData.m_iVehicleIndex);
347  }
348 
349  //update current effect
350  if (currentMaterial && vehicleDust.m_pParticleEffectEntity && (newMaterial == currentMaterial || (currentMaterial.GetParticleEffectInfo() && currentMaterial.GetParticleEffectInfo().GetResourceName() == newResource)))
351  {
352  if (newMaterial != currentMaterial) //different GameMats, but resources are the same
353  {
354  vehicleDust.m_Material = newMaterial;
355  }
356 
357  UpdateCurrent(vehicleDust, speed, wheelIdx);
358  return;
359  }
360 
361  vehicleDust.m_Material = newMaterial;
362  if (vehicleDust.m_pParticleEffectEntity) // stop old effect
363  {
364  vehicleDust.m_pParticleEffectEntity.StopEmission();
365  vehicleDust.m_pParticleEffectEntity = null;
366  }
367 
368  //Create new effect
369  if (newResource && newResource.Length() > 0)
370  {
371  ParticleEffectEntitySpawnParams spawnParams();
372  spawnParams.TargetWorld = GetOwner().GetWorld();
373  spawnParams.Parent = GetOwner();
374  spawnParams.UseFrameEvent = true;
375  vehicleDust.m_pParticleEffectEntity = ParticleEffectEntity.SpawnParticleEffect(newResource, spawnParams);
376  vehicleDust.m_iLastSwap = ticks;
377  }
378 
379  UpdateCurrent(vehicleDust, speed, wheelIdx);
380  }
381 
382  //------------------------------------------------------------------------------------------------
383  protected void UpdateCurrent(VehicleDust vehicleDust, float speed, int wheelIdx)
384  {
385  if (!vehicleDust.m_pParticleEffectEntity)
386  return;
387 
388  UpdatePosition(vehicleDust, wheelIdx);
389  UpdateVehicleDustEffect(vehicleDust, speed, wheelIdx);
390  }
391 
392  //------------------------------------------------------------------------------------------------
393  protected void UpdatePosition(VehicleDust vehicleDust, int wheelIdx)
394  {
395  vector position;
396  if (m_RplComponent && m_RplComponent.IsRemoteProxy())
397  {
398  vector worldTransform[4];
399  GetOwner().GetWorldTransform(worldTransform);
400  position = vehicleDust.m_vLocalDustPos.Multiply4(worldTransform);
401  }
402  else
403  {
405  {
406  if(!m_Simulation.WheelHasContact(wheelIdx))
407  return;
408 
409  position = m_Simulation.WheelGetContactPosition(wheelIdx);
410  }
411  else
412  {
413  if(!m_Simulation_SA.WheelHasContact(wheelIdx))
414  return;
415 
416  position = m_Simulation_SA.WheelGetContactPosition(wheelIdx);
417  }
418  }
419 
420  vehicleDust.m_pParticleEffectEntity.SetOrigin(position);
421  }
422 
423  //------------------------------------------------------------------------------------------------
424  protected void UpdateVehicleDustEffect(VehicleDust vehicleDust, float speed, int wheelIdx)
425  {
426  float endSpeed = m_ComponentData.m_fDustTopSpeed;
427  float speedCoef = 0;
428  float birthCoef = 0;
429  float gravityCoef = 0;
430 
431  float longitudinalSlip = 0;
432  float lateralSlip = 0;
433 
435  {
436  longitudinalSlip = m_Simulation.WheelGetLongitudinalSlip(wheelIdx);
437  lateralSlip = m_Simulation.WheelGetLateralSlip(wheelIdx);
438  }
439  else
440  {
441  longitudinalSlip = m_Simulation_SA.WheelGetLongitudinalSlip(wheelIdx);
442  lateralSlip = m_Simulation_SA.WheelGetLateralSlip(wheelIdx);
443  }
444 
445  float effectiveSlip = Math.Clamp(longitudinalSlip + lateralSlip, 0, 1);
446 
447  if (vehicleDust.m_bWheelHasContact)
448  {
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);
452  }
453 
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);
459 
460 #ifdef ENABLE_DIAG
461  if (!DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_PARTICLES_VEHICLE_DUST))
462  return;
463 
464  if (!vehicleDust.m_bWheelHasContact)
465  return;
466 
467  if (!vehicleDust.m_Material)
468  return;
469 
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]);
472 #endif
473  }
474 };
ComponentEditorProps
SCR_FragmentEntityClass ComponentEditorProps
SCR_VehicleDustPerWheelClass
Definition: SCR_VehicleDustPerWheelComponent.c:4
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
ScriptGameComponentClass
Definition: ScriptGameComponent.c:12
m_Physics
private Physics m_Physics
Definition: InteractableBoxComponent.c:13
m_Simulation
protected VehicleBaseSimulation m_Simulation
Definition: SCR_VehicleDamageManagerComponent.c:198
GetIsClientAuthority
override bool GetIsClientAuthority()
Definition: game.c:268
VehiclesDustSystem
Definition: VehiclesDustSystem.c:1
Attribute
typedef Attribute
Post-process effect of scripted camera.
m_fTime
float m_fTime
Definition: SCR_CharacterCommandSwim.c:221
VehicleDust
Vehicle dust per wheel data;.
Definition: SCR_VehicleDustPerWheelComponent.c:34
Deactivate
protected void Deactivate()
Definition: SCR_BaseHintCondition.c:27
GetOwner
IEntity GetOwner()
Owner entity of the fuel tank.
Definition: SCR_FuelNode.c:128
m_RplComponent
protected RplComponent m_RplComponent
Definition: SCR_CampaignBuildingManagerComponent.c:42
index
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Definition: SCR_DestructionSynchronizationComponent.c:17
UPDATE_TIME
const protected float UPDATE_TIME
Definition: SCR_HelicopterSoundComponent.c:18
ParticleEffectInfo
Definition: ParticleEffectInfo.c:12
SCR_DebugMenuID
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition: DebugMenuID.c:3
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
m_ComponentData
protected SCR_FuelConsumptionComponentClass m_ComponentData
Definition: SCR_FuelConsumptionComponent.c:28
GameMaterial
Definition: GameMaterial.c:12
SCR_VehicleDustPerWheel
Definition: SCR_VehicleDustPerWheelComponent.c:43
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180