2 #define ENABLE_BASE_DESTRUCTION
4 [
EntityEditorProps(
category:
"GameScripted/Debris", description:
"Entity used to represent small chunks of debris. Automatically managed.", dynamicBox:
true)]
16 #ifdef ENABLE_BASE_DESTRUCTION
17 private static int s_iDebrisMaximumCount = 1000;
20 private static ref array<SCR_DebrisSmallEntity> s_aDebrisSmallList =
null;
23 private bool m_bDelete =
false;
25 private int m_iPriority = 0;
27 private float m_fLifeTime = 0.0;
29 private float m_fAgeTime = 0.0;
31 private float m_fMaxDistance = 0.0;
33 private Physics m_RigidBody =
null;
37 private vector m_vSoundPositionLast;
39 private static const float MINIMAL_DISTANCE_SQ = 0.25;
41 private static const float MINIMAL_AGE = 0.25;
43 private AudioHandle m_AudioHandle = AudioHandle.Invalid;
45 private float m_fSoundThreshold;
47 private static const int KINETIC_ENERGY_THRESHOLD = 12;
49 private float m_fdVelocity;
52 private ref DebugTextWorldSpace m_Text;
54 private float m_fTextMax;
56 private float m_fTextAgeTime;
60 static private int m_iSpawnedThisFrame = 0;
62 static private int m_iDebrisPerFrameLimit = 128;
67 private bool IsGamePlaying()
76 private void RegisterDebris()
82 if (!s_aDebrisSmallList)
84 s_aDebrisSmallList =
new array<SCR_DebrisSmallEntity>();
87 if (s_aDebrisSmallList)
89 s_aDebrisSmallList.Insert(
this);
95 private void UnregisterDebris()
101 if (s_aDebrisSmallList)
105 int idx = s_aDebrisSmallList.Find(
this);
106 int count = s_aDebrisSmallList.Count();
109 s_aDebrisSmallList.Remove(idx);
110 s_aDebrisSmallList.Resize(count-1);
112 if (s_aDebrisSmallList.Count() <= 0)
114 s_aDebrisSmallList =
null;
121 private static float GetDistanceToCamera(BaseWorld world, vector
position)
124 world.GetCurrentCamera(cameraMat);
125 return vector.Distance(cameraMat[3],
position);
129 override void EOnContact(IEntity owner, IEntity other, Contact contact)
134 float spdDiff = contact.GetRelativeNormalVelocityAfter() - contact.GetRelativeNormalVelocityBefore();
137 if (spdDiff > m_fSoundThreshold && vector.DistanceSq(m_vSoundPositionLast, contact.Position) >= MINIMAL_DISTANCE_SQ &&
m_eMaterialSoundType != 0 && m_fAgeTime > MINIMAL_AGE)
138 PlaySound(contact.Position, spdDiff);
142 m_fdVelocity = spdDiff;
153 private void PlaySound(vector pos,
float dVelocity)
156 if (!soundManagerEntity)
160 if (!destructionManager)
163 SCR_AudioSourceConfiguration audioSourceConfiguration = destructionManager.GetAudioSourceConfiguration();
164 if (!audioSourceConfiguration)
168 SCR_AudioSource audioSource = soundManagerEntity.CreateAudioSource(
this, audioSourceConfiguration);
173 AudioSystem.TerminateSound(m_AudioHandle);
176 audioSource.SetSignalValue(
SCR_AudioSource.COLLISION_D_V_SIGNAL_NAME, dVelocity - m_fSoundThreshold);
177 audioSource.SetSignalValue(
SCR_AudioSource.ENTITY_SIZE_SIGNAL_NAME, m_RigidBody.GetMass());
185 soundManagerEntity.PlayAudioSource(audioSource, mat);
186 m_AudioHandle = audioSource.m_AudioHandle;
189 m_vSoundPositionLast = pos;
193 if (DiagMenu.GetBool(
SCR_DebugMenuID.DEBUGUI_SOUNDS_MPDESTRUCTION_SHOW_IMPULSEVALUES))
195 m_Text = DebugTextWorldSpace.Create(GetWorld(), dVelocity.ToString(1, 2) +
"/" + m_fSoundThreshold.ToString(1, 2) +
"/" + m_RigidBody.GetMass().ToString(), DebugTextFlags.FACE_CAMERA, pos[0], pos[1], pos[2], 20, COLOR_BLUE);
196 m_fTextAgeTime = m_fAgeTime + 1;
202 override void EOnFrame(IEntity owner,
float timeSlice)
205 m_fAgeTime += timeSlice;
208 if (m_fAgeTime >= m_fLifeTime)
216 float distance = GetDistanceToCamera(owner.GetWorld(), owner.GetOrigin());
226 m_RigidBody.Destroy();
235 if (DiagMenu.GetBool(
SCR_DebugMenuID.DEBUGUI_SOUNDS_MPDESTRUCTION_SHOW_IMPULSEVALUES))
240 owner.GetWorldBounds(minsDebug, maxsDebug);
242 for (
int i = 0; i < 3; i++)
244 centerDebug[i] = minsDebug[i] + Math.AbsFloat(((maxsDebug[i] - minsDebug[i]) * 0.5));
248 if (m_fAgeTime - m_fTextAgeTime > 1 || m_fdVelocity > m_fTextMax)
250 m_Text = DebugTextWorldSpace.Create(GetWorld(), m_fdVelocity.ToString(1, 2) +
"/" + m_fSoundThreshold.ToString(1, 2) +
"/" + m_RigidBody.GetMass().ToString(), DebugTextFlags.FACE_CAMERA, centerDebug[0], centerDebug[1], centerDebug[2], 20);
251 m_fTextMax = m_fdVelocity;
252 m_fTextAgeTime = m_fAgeTime;
268 static SCR_DebrisSmallEntity SpawnDebris(BaseWorld world, vector mat[4], ResourceName model,
float mass = 10,
float lifeTime = 10.0,
float maxDistance = 256.0,
int priority = 1, vector linearVelocity =
"0 0 0", vector angularVelocity =
"0 0 0",
string remap =
"",
bool isStatic =
false,
SCR_EMaterialSoundTypeDebris materialSoundType = 0)
270 if (m_iSpawnedThisFrame >= m_iDebrisPerFrameLimit)
274 if (model ==
string.Empty)
278 if (GetDistanceToCamera(world, mat[3]) > maxDistance)
284 if (!s_aDebrisSmallList)
285 s_aDebrisSmallList =
new array<SCR_DebrisSmallEntity>();
288 if (s_aDebrisSmallList)
290 int count = s_aDebrisSmallList.Count();
292 if (count >= s_iDebrisMaximumCount)
294 for (
int i = 0; i < s_aDebrisSmallList.Count(); i++)
296 if (s_aDebrisSmallList[i])
300 entity = s_aDebrisSmallList[i];
308 if (entity.m_RigidBody)
310 entity.m_RigidBody.Destroy();
311 entity.m_RigidBody =
null;
326 m_iSpawnedThisFrame++;
328 entity.SetTransform(mat);
329 Resource resource = Resource.Load(model);
333 BaseResourceObject baseRes = resource.GetResource();
337 VObject obj = baseRes.ToVObject();
338 entity.SetObject(obj, remap);
340 entity.m_fLifeTime = lifeTime;
341 entity.m_iPriority = priority;
342 entity.m_fMaxDistance = maxDistance;
343 entity.m_eMaterialSoundType = materialSoundType;
346 entity.m_fSoundThreshold = Math.Sqrt(2 * KINETIC_ENERGY_THRESHOLD / mass);
351 entity.GetWorldBounds(mins, maxs);
353 entity.m_vSoundPositionLast = vector.Lerp(mins, maxs, 0.5);
356 if (!entity.m_RigidBody)
359 entity.m_RigidBody = Physics.CreateStatic(entity, -1);
362 entity.m_RigidBody = Physics.CreateDynamic(entity, mass, -1);
363 if (entity.m_RigidBody)
365 entity.m_RigidBody.SetVelocity(linearVelocity);
366 entity.m_RigidBody.SetAngularVelocity(angularVelocity * Math.DEG2RAD);
370 vector entityOrigin = entity.GetOrigin();
371 float terrainY =
GetGame().GetWorld().GetSurfaceY(entityOrigin[0], entityOrigin[2]);
372 if (mins[1] < terrainY && maxs[1] > terrainY)
374 float newHeight = terrainY - mins[1] + entityOrigin[1] + 0.001;
375 entity.SetOrigin({entityOrigin[0], newHeight, entityOrigin[2]});
379 if (entity.m_RigidBody)
380 entity.m_RigidBody.SetInteractionLayer(EPhysicsLayerDefs.Debris);
389 static void DeleteRandomDebris(
int count = 1)
391 for (
int i = 0; i < count; i++)
393 if (s_aDebrisSmallList)
395 if (s_aDebrisSmallList.Count() > 0)
413 ClearEventMask(EntityEvent.CONTACT);
417 override void EOnPostFrame(IEntity owner,
float timeSlice)
419 m_iSpawnedThisFrame = 0;
424 override void EOnInit(IEntity owner)
432 SetEventMask(EntityEvent.INIT | EntityEvent.FRAME | EntityEvent.POSTFRAME | EntityEvent.CONTACT);
433 SetFlags(EntityFlags.ACTIVE,
true);