Пример #1
0
        //  Start explosion at specified position, with radius and lifespan.
        //      type - specifies what type of object exploded
        //      explosionSphere - position and radius
        //      lifespanInMiliseconds - explosion life span
        //  IMPORTANT: This class isn't realy inicialized by constructor, but by Start()
        public void Start(float playerDamage, float damage, float empDamage, MyExplosionTypeEnum type, BoundingSphere explosionSphere, int lifespanInMiliseconds, int cascadeLevel = 0, MyEntity hitEntity = null, float particleScale = 1.0f, MyEntity ownerEntity = null, bool forceDebris = false, bool createDecals = true, float voxelCutoutScale = 1.0f, bool playSound = true, bool checkIntersections = true)
        {
            //  Call main explosion starter
            MyExplosionInfo info = new MyExplosionInfo(playerDamage, damage, empDamage, explosionSphere, type, playSound)
            {
                LifespanMiliseconds     = lifespanInMiliseconds,
                ExplosionForceDirection = MyExplosionForceDirection.EXPLOSION,
                GroupMask          = MyGroupMask.Empty,
                ExplosionFlags     = MyExplosionFlags.CREATE_DEBRIS | MyExplosionFlags.AFFECT_VOXELS | MyExplosionFlags.APPLY_FORCE_AND_DAMAGE | MyExplosionFlags.CREATE_PARTICLE_EFFECT,
                CascadeLevel       = cascadeLevel,
                HitEntity          = hitEntity,
                ParticleScale      = particleScale,
                OwnerEntity        = ownerEntity,
                Direction          = null,
                VoxelCutoutScale   = voxelCutoutScale,
                CheckIntersections = checkIntersections,
            };

            info.ForceDebris          = forceDebris;
            info.CreateDecals         = createDecals;
            info.VoxelExplosionCenter = explosionSphere.Center;
            Start(ref info);
        }
Пример #2
0
        public void Start(float playerDamage, float damage, float empDamage, MyExplosionTypeEnum type, BoundingSphere explosionSphere, int lifespanInMiliseconds, MyExplosionForceDirection explosionForceDirection, MyGroupMask groupMask, bool createExplosionDebris, int cascadeLevel = 0, MyEntity hitEntity = null, float particleScale = 1.0f, MyEntity ownerEntity = null, bool affectVoxels = true, bool applyForceAndDamage = true, bool createDecals = true, Vector3?direction = null, bool forceDebris = false, bool playSound = false)
        {
            MyExplosionInfo info = new MyExplosionInfo(playerDamage, damage, empDamage, explosionSphere, type, playSound)
            {
                LifespanMiliseconds     = lifespanInMiliseconds,
                ExplosionForceDirection = explosionForceDirection,
                GroupMask        = groupMask,
                ExplosionFlags   = MyExplosionFlags.CREATE_PARTICLE_EFFECT,
                CascadeLevel     = cascadeLevel,
                HitEntity        = hitEntity,
                ParticleScale    = particleScale,
                OwnerEntity      = ownerEntity,
                Direction        = direction,
                VoxelCutoutScale = 1.0f,
            };

            info.AffectVoxels         = affectVoxels;
            info.ApplyForceAndDamage  = applyForceAndDamage;
            info.CreateDebris         = createExplosionDebris;
            info.CreateDecals         = createDecals;
            info.ForceDebris          = forceDebris;
            info.VoxelExplosionCenter = explosionSphere.Center;
            Start(ref info);
        }
Пример #3
0
        /// <summary>
        /// Starts the explosion.
        /// </summary>
        /// <param name="damage"></param>
        /// <param name="type"></param>
        /// <param name="explosionSphere"></param>
        /// <param name="lifespanInMiliseconds"></param>
        /// <param name="explosionForceDirection"></param>
        /// <param name="groupMask"></param>
        /// <param name="createExplosionDebris"></param>
        /// <param name="cascadeLevel"></param>
        /// <param name="hitEntity"></param>
        /// <param name="particleScale"></param>
        /// <param name="ownerEntity"></param>
        /// <param name="affectVoxels"></param>
        /// <param name="applyForceAndDamage"></param>
        /// <param name="createDecals"></param>
        /// <param name="direction">If applicable, gives the direction of the explosion, e.g. when it was caused by a missile (with its moving direction).</param>
        public void Start(ref MyExplosionInfo explosionInfo)
        {
            //MyCommonDebugUtils.AssertDebug(explosionInfo.ExplosionSphere.Radius <= MyExplosionsConstants.EXPLOSION_RADIUS_MAX);
            MyCommonDebugUtils.AssertDebug(explosionInfo.ExplosionSphere.Radius > 0);

            MyRender.GetRenderProfiler().StartProfilingBlock("MyExplosion.Start");

            m_explosionSphere       = explosionInfo.ExplosionSphere;
            m_elapsedMiliseconds    = 0;
            m_lifespanInMiliseconds = explosionInfo.LifespanMiliseconds;

            if (explosionInfo.PlaySound)
            {
                MyRender.GetRenderProfiler().StartProfilingBlock("Sound");
                //  Play explosion sound
                if (m_explosionCue != null && m_explosionCue.Value.IsPlaying)
                {
                    m_explosionCue.Value.Stop(SharpDX.XACT3.StopFlags.Immediate);
                }
                m_explosionCue = MyAudio.AddCue3D(GetCueEnumByExplosionType(explosionInfo.ExplosionType), m_explosionSphere.Center, Vector3.Zero, Vector3.Zero, Vector3.Zero);
                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            MyRender.GetRenderProfiler().StartProfilingBlock("Light");
            //  Light of explosion

            /*
             * m_light = MyLights.AddLight();
             * if (m_light != null)
             * {
             *  m_light.Start(MyLight.LightTypeEnum.PointLight, m_explosionSphere.Center, MyExplosionsConstants.EXPLOSION_LIGHT_COLOR, 1, Math.Min(m_explosionSphere.Radius * 8.0f, MyLightsConstants.MAX_POINTLIGHT_RADIUS));
             *  m_light.Intensity = 2.0f;
             * } */
            MyRender.GetRenderProfiler().EndProfilingBlock();

            // close explosion check
            bool close = IsExplosionClose(explosionInfo.ExplosionSphere);

            MyParticleEffectsIDEnum newParticlesType;

            switch (explosionInfo.ExplosionType)
            {
            case MyExplosionTypeEnum.SMALL_SHIP_EXPLOSION:
                //  Create metal debris objects thrown from the explosion
                //  This must be called before ApplyExplosionForceAndDamage (because there we apply impulses to the debris)
                //  Throw a lot of debrises, more than only if some metalic object is hit (because this is destruction of a ship)
                //MyPhysObjectExplosionDebrises.CreateExplosionDebris(m_explosionSphere.Center, 1);
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Smallship;
                break;

            case MyExplosionTypeEnum.MISSILE_EXPLOSION:
                newParticlesType =
                    // ? MyParticleEffectsIDEnum.Explosion_Missile_Close
                    MyParticleEffectsIDEnum.Explosion_Missile;
                break;

            case MyExplosionTypeEnum.BOMB_EXPLOSION:
            case MyExplosionTypeEnum.GRAVITY_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Bomb;
                break;

            case MyExplosionTypeEnum.AMMO_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Ammo;
                break;

            case MyExplosionTypeEnum.BLASTER_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Blaster;
                break;

            case MyExplosionTypeEnum.BIOCHEM_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_BioChem;
                break;

            case MyExplosionTypeEnum.EMP_EXPLOSION:
            case MyExplosionTypeEnum.FLASH_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_EMP;
                break;

            case MyExplosionTypeEnum.METEOR_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Meteor;
                break;

            case MyExplosionTypeEnum.NUCLEAR_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Nuclear;
                break;

            case MyExplosionTypeEnum.PLASMA_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Plasma;
                break;

            case MyExplosionTypeEnum.SMALL_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_SmallPrefab;
                break;

            case MyExplosionTypeEnum.LARGE_SHIP_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Huge;
                break;

            case MyExplosionTypeEnum.LARGE_PREFAB_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Large;
                break;

            case MyExplosionTypeEnum.MEDIUM_PREFAB_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Medium;
                break;

            case MyExplosionTypeEnum.ASTEROID_EXPLOSION:
                newParticlesType = MyParticleEffectsIDEnum.Explosion_Asteroid;
                break;

            default:
                throw new System.NotImplementedException();
                break;
            }


            if (explosionInfo.Damage > 0)
            {
                MyRender.GetRenderProfiler().StartProfilingBlock("Voxel or collision");

                //  If explosion sphere intersects a voxel map, we need to cut out a sphere, spawn debrises, etc
                MyVoxelMap voxelMap = explosionInfo.AffectVoxels && explosionInfo.EmpDamage == 0 ? MyVoxelMaps.GetOverlappingWithSphere(ref m_explosionSphere) : null;
                if (voxelMap != null)
                {
                    //  Dirty explosion with a lot of dust

                    MyMwcVoxelMaterialsEnum?voxelMaterial = null;
                    float voxelContentRemovedInPercent    = 0;

                    bool createDebris = true;            // We want to create debris

                    if (explosionInfo.HitEntity != null) // but not when we hit prefab
                    {
                        createDebris &= explosionInfo.HitEntity is MyVoxelMap;
                    }


                    //cut off
                    BoundingSphere voxelExpSphere = new BoundingSphere(explosionInfo.VoxelExplosionCenter, m_explosionSphere.Radius * explosionInfo.VoxelCutoutScale);
                    if (MyVoxelGenerator.CutOutSphereFast(voxelMap, voxelExpSphere, out voxelContentRemovedInPercent, out voxelMaterial, (explosionInfo.OwnerEntity is MySmallShip && explosionInfo.OwnerEntity == Managers.Session.MySession.PlayerShip), MyFakes.VOXELS_REMOVE_RATIO))
                    {
                        if (explosionInfo.HitEntity is MyVoxelMap)
                        {
                            HUD.MyHud.ShowIndestructableAsteroidNotification();
                        }
                        createDebris = false; // and no debris when voxel is indestructible
                    }

                    //  Only if at least something was removed from voxel map
                    //  If voxelContentRemovedInPercent is more than zero than also voxelMaterial shouldn't be null, but I rather check both of them.
                    if ((voxelContentRemovedInPercent > 0) && (voxelMaterial != null))
                    {
                        //remove decals
                        MyDecals.HideTrianglesAfterExplosion(voxelMap, ref voxelExpSphere);

                        MyRender.GetRenderProfiler().StartProfilingBlock("CreateDebris");

                        if (explosionInfo.CreateDebris && (createDebris || explosionInfo.ForceDebris) && MyRenderConstants.RenderQualityProfile.ExplosionDebrisCountMultiplier > 0)
                        {
                            //  Create debris rocks thrown from the explosion
                            //  This must be called before ApplyExplosionForceAndDamage (because there we apply impulses to the debris)
                            MyExplosionDebrisVoxel.CreateExplosionDebris(ref voxelExpSphere, voxelContentRemovedInPercent, voxelMaterial.Value, explosionInfo.GroupMask, voxelMap);
                        }

                        MyRender.GetRenderProfiler().EndProfilingBlock();

                        MyRender.GetRenderProfiler().StartProfilingBlock("CreateParticleEffect");

                        MyParticleEffect explosionEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.MaterialExplosion_Destructible);
                        explosionEffect.WorldMatrix          = Matrix.CreateTranslation(voxelExpSphere.Center);
                        explosionEffect.UserRadiusMultiplier = voxelExpSphere.Radius;

                        MyRender.GetRenderProfiler().EndProfilingBlock();
                    }
                }
                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            if (explosionInfo.Damage > 0)
            {
                //  Create dirt decals in player's cockpit glass
                MyRender.GetRenderProfiler().StartProfilingBlock("Cockpit Decals");
                CreateDirtDecalOnCockpitGlass(ref m_explosionSphere);
                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            if (DEBUG_EXPLOSIONS)
            {
                MyRender.GetRenderProfiler().EndProfilingBlock();
                return;
            }

            if (explosionInfo.Damage > 0)
            {
                BoundingSphere influenceExplosionSphere = m_explosionSphere;
                influenceExplosionSphere.Radius *= MyExplosionsConstants.EXPLOSION_RADIUS_MULTPLIER_FOR_IMPULSE;
                for (int i = 0; i < explosionInfo.CascadeLevel; i++)
                {
                    influenceExplosionSphere.Radius *= MyExplosionsConstants.EXPLOSION_CASCADE_FALLOFF;
                }

                //  Throws surrounding objects away from centre of the explosion.
                if (explosionInfo.ApplyForceAndDamage)
                {
                    if (explosionInfo.ExplosionType == MyExplosionTypeEnum.LARGE_PREFAB_EXPLOSION ||
                        explosionInfo.ExplosionType == MyExplosionTypeEnum.LARGE_SHIP_EXPLOSION ||
                        explosionInfo.ExplosionType == MyExplosionTypeEnum.MEDIUM_PREFAB_EXPLOSION)
                    {
                        DisableContainedDummyParticles(ref explosionInfo);
                    }

                    explosionInfo.StrengthImpulse        = MyExplosionsConstants.EXPLOSION_STRENGTH_IMPULSE * m_explosionSphere.Radius / 20;
                    explosionInfo.StrengthAngularImpulse = MyExplosionsConstants.EXPLOSION_STRENGTH_ANGULAR_IMPULSE;
                    explosionInfo.HitEntity = explosionInfo.HitEntity != null?explosionInfo.HitEntity.GetBaseEntity() : null;

                    MyRender.GetRenderProfiler().StartProfilingBlock("ApplyExplosionForceAndDamage");
                    MyEntities.ApplyExplosionForceAndDamage(ref explosionInfo);
                    MyRender.GetRenderProfiler().EndProfilingBlock();
                }

                //  Look for objects in explosion radius
                BoundingBox boundingBox;
                BoundingBox.CreateFromSphere(ref influenceExplosionSphere, out boundingBox);

                //if (explosionInfo.CreateDecals && explosionInfo.Direction.HasValue && explosionInfo.EmpDamage == 0)
                //{
                //    CreateDecals(explosionInfo.Direction.Value);
                //}
            }

            if (explosionInfo.CreateParticleEffect)
            {
                MyRender.GetRenderProfiler().StartProfilingBlock("Particles");

                if (explosionInfo.CustomEffect != null)
                {
                    if (explosionInfo.CustomEffect.ParticleID == 0)
                    {
                        explosionInfo.CustomEffect.ParticleID = (int)newParticlesType;
                    }
                    //Reload effect
                    explosionInfo.CustomEffect.Enabled = false;
                    explosionInfo.CustomEffect.Enabled = true;
                }
                else
                {
                    //  Explosion particles
                    GenerateExplosionParticles(newParticlesType, m_explosionSphere, explosionInfo.ParticleScale);
                }

                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            MyRender.GetRenderProfiler().EndProfilingBlock();

            /*
             *  // When MyAmmoBase entity is closed to explosion it will explode
             *  if (entity is MyAmmoBase)
             *  {
             *      (entity as MyAmmoBase).ExplodeCascade(cascadeLevel + 1);
             *  }
             */

            //  Smut decals - must be called after the explosion, after voxels are cutted out

            /*if ((intersection.PhysObject is MyVoxelMap) == false)
             * {
             *  if (intersection.PhysObject is MyCockpitGlass)
             *  {
             *      //  Change phys object so rest of the code will think we hit the parent
             *      //  Same fix is in projectile too - because cockpit glass is only helper object, we don't use it for real rendering and stuff
             *      //  And if not changed, it can make problem in "phys object decals"
             *      intersection.PhysObject = intersection.PhysObject.Parent;
             *  }
             *
             *  //  Create explosion smut decal on model we hit by this missile
             *  MyDecals.Add(
             *      MyDecalTexturesEnum.ExplosionSmut,
             *      MyMwcUtils.GetRandomFloat(m_explosionSphere.Radius * 0.7f, m_explosionSphere.Radius * 1.3f),
             *      MyMwcUtils.GetRandomRadian(),
             *      GetSmutDecalRandomColor(),
             *      true,
             *      ref intersection);
             * }
             * else
             * {
             *  //  Creating explosion smut decal on voxel is more complicated than on voxel. We will project few lines
             *  //  from explosion epicentrum to the surounding world (random directions) and place decal where intersection detected.
             *  //if (knownMissileDirection != null)
             *  //{
             *  //    MyLine linePrologned = new MyLine(knownIntersection.Value.IntersectionPointInObjectSpace,
             *  //        knownIntersection.Value.IntersectionPointInObjectSpace + knownMissileDirection.Value * MyExplosionsConstants.EXPLOSION_RANDOM_RADIUS_MAX * 2,
             *  //        true);
             *  //    MyLineTriangleIntersectionResult intersectionForSmut = knownIntersection.Value.VoxelMap.GetIntersectionWithLine(ref linePrologned);
             *  //    if (intersectionForSmut.Found == true)
             *  //    {
             *  //        MyDecals.Add(
             *  //            MyDecalTexturesEnum.ExplosionSmut,
             *  //            MyMwcUtils.GetRandomFloat(m_explosionSphere.Radius * 0.5f, m_explosionSphere.Radius * 1.0f),
             *  //            MyMwcUtils.GetRandomRadian(),
             *  //            GetSmutDecalRandomColor(),
             *  //            false,
             *  //            ref intersectionForSmut);
             *  //    }
             *  //}
             * }*/

            //  Generate dust particles that will stay in place of the explosion
            //doesnt look good in final
            //GenerateStatisDustParticles(m_explosionSphere);
        }
Пример #4
0
        /// <summary>
        /// Generates explosion and debris.
        /// </summary>
        protected virtual void Explode()
        {
            //if (Physics.Enabled)
            //{
            //    Physics.Enabled = false;
            //    Physics.Clear();
            //}

            // only if prefab is big enough, make it explode and create debris))
            if (WorldVolumeHr.Radius > m_config.MinSizeForExplosion)
            {
                DestroyPrefabsInside();

                MyExplosion newExplosion = MyExplosions.AddExplosion();
                if (newExplosion != null)
                {
                    BoundingSphere explosionSphere = WorldVolumeHr;
                    explosionSphere.Radius *= m_config.ExplosionRadiusMultiplier;

                    float particleScale = 1;
                   /* if (explosionSphere.Radius > MyExplosionsConstants.EXPLOSION_RADIUS_MAX)
                    {
                        particleScale = explosionSphere.Radius / MyExplosionsConstants.EXPLOSION_RADIUS_MAX;
                        explosionSphere.Radius = MathHelper.Min(explosionSphere.Radius, MyExplosionsConstants.EXPLOSION_RADIUS_MAX);
                    }
                    else*/
                    if (m_config.ExplosionType == MyExplosionTypeEnum.BOMB_EXPLOSION)
                    {
                        particleScale = MathHelper.Max(1, WorldVolumeHr.Radius * 0.2f);
                    }
                    if (m_config.ExplosionType == MyExplosionTypeEnum.SMALL_SHIP_EXPLOSION)
                    {
                        //Scaled by smallship size
                        particleScale = MathHelper.Max(1, WorldVolumeHr.Radius / 20f);
                    }
                    if (m_config.ExplosionType == MyExplosionTypeEnum.LARGE_SHIP_EXPLOSION)
                    {
                        //Scaled by KAI size
                        particleScale = MathHelper.Max(1, WorldVolumeHr.Radius / 300f);
                    }

                    MyVoxelMap voxelMap = MyVoxelMaps.GetOverlappingWithSphere(ref explosionSphere);
                    MyExplosionDebrisModel.CreateExplosionDebris(ref explosionSphere, MyGroupMask.Empty, this, voxelMap);
                    float voxelCutoutScale = 0.6f; // Prefabs do smaller voxel cutout

                    MyExplosionInfo explosionInfo = new MyExplosionInfo()
                    {
                        PlayerDamage = 0,
                        Damage = m_config.ExplosionDamage,
                        EmpDamage = 0,
                        ExplosionType = m_config.ExplosionType,
                        ExplosionSphere = explosionSphere,
                        LifespanMiliseconds = MyExplosionsConstants.EXPLOSION_LIFESPAN,
                        VoxelCutoutScale = voxelCutoutScale,
                        ParticleScale = particleScale * m_config.ExplosionParticleEffectScale,
                        HitEntity = this,
                        CheckIntersections = false,
                        CreateDecals = false,
                        CreateDebris = false,
                        CreateParticleEffect = true,
                        PlaySound = true,
                    };

                    newExplosion.Start(ref explosionInfo);
                }
            }
            else
            {
                var effect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.Explosion_SmallPrefab);
                effect.WorldMatrix = Matrix.CreateWorld(WorldVolume.Center, WorldMatrix.Forward, WorldMatrix.Up);
                //effect.UserRadiusMultiplier = .1f * WorldVolumeHr.Radius;
                effect.UserScale = 0.05f * m_config.ExplosionRadiusMultiplier * m_config.ExplosionParticleEffectScale * WorldVolumeHr.Radius;
            }
        }
Пример #5
0
        public override void UpdateBeforeSimulation()
        {
            try
            {
                MyRender.GetRenderProfiler().StartProfilingBlock("MyCannonShot.UpdateBeforeSimulation");

                if (this.WorldMatrix.Translation != m_previousPosition)
                {
                    MyLine line = new MyLine(this.WorldMatrix.Translation, m_previousPosition);
                    MyDangerZones.Instance.Notify(line, OwnerEntity);
                }

                //  Kill this missile
                if (m_isExploded && !m_wasPenetration)
                {
                    //  Create explosion
                    MyExplosion newExplosion = MyExplosions.AddExplosion();
                    if (newExplosion != null)
                    {
                        float radius = MyMwcUtils.GetRandomFloat(m_ammoProperties.ExplosionRadius - 2, m_ammoProperties.ExplosionRadius + 2);
                        BoundingSphere explosionSphere = new BoundingSphere((m_collisionPoint.HasValue ? m_collisionPoint.Value : GetPosition()), radius);
                        MyExplosionInfo info = new MyExplosionInfo(m_ammoProperties.HealthDamage, m_ammoProperties.ShipDamage, m_ammoProperties.EMPDamage, explosionSphere, m_explosionType, true)
                        {
                            GroupMask = Physics.GroupMask,
                            CascadeLevel = CascadedExplosionLevel,
                            HitEntity = m_collidedEntity,
                            OwnerEntity = this.OwnerEntity,
                            Direction = WorldMatrix.Forward,
                            ParticleScale = 1.5f,
                            VoxelExplosionCenter = explosionSphere.Center + radius * WorldMatrix.Forward * 0.6f,
                        };
                        info.CreateParticleEffect = !m_hasExplosion;
                        newExplosion.Start(ref info);
                    }

                    if (m_collidedEntity != null && !m_collidedEntity.IsExploded())
                    {
                        m_collidedEntity.Physics.AddForce(
                            MyPhysicsForceType.APPLY_WORLD_IMPULSE_AND_WORLD_ANGULAR_IMPULSE,
                            WorldMatrix.Forward * MyMissileConstants.HIT_STRENGTH_IMPULSE,
                            GetPosition() + MyMwcUtils.GetRandomVector3Normalized() * 2,
                            MyMissileConstants.HIT_STRENGTH_IMPULSE * MyMwcUtils.GetRandomVector3Normalized());
                    }

                    MarkForClose();

                    return;
                }

                base.UpdateBeforeSimulation();

                //  Chech timeout and max distance
                if ((m_elapsedMiliseconds > MyCannonConstants.SHOT_TIMEOUT) || (Vector3.Distance(this.WorldMatrix.Translation, m_origin) >= m_ammoProperties.MaxTrajectory))
                {
                    MarkForClose();
                    return;
                }



                Matrix orientation = GetWorldRotation();

                //  Update thruster cue/sound
                MyAudio.UpdateCuePosition(m_thrusterCue, this.WorldMatrix.Translation, orientation.Forward, orientation.Up, this.Physics.LinearVelocity);

                Vector3 pos = this.WorldMatrix.Translation;

                if (m_penetratedVoxelMap == null)
                {
                    if (m_smokeEffect != null)
                        m_smokeEffect.WorldMatrix = WorldMatrix;
                }
                /*
          if (m_wasPenetration)
          {
              //  Create explosion
              MyExplosion newExplosion = MyExplosions.AddExplosion();
              if (newExplosion != null)
              {
                  float radius = MyMwcUtils.GetRandomFloat(1, 2);
                  float particleScale = 2.2f; // must be large enough to cover the hole
                  newExplosion.StartWithPositionOffset(m_ammoProperties.HealthDamage, m_ammoProperties.ShipDamage, m_ammoProperties.EMPDamage, m_explosionType, m_penetrationOrigin - WorldMatrix.Forward * 2, radius, MyExplosionsConstants.EXPLOSION_LIFESPAN, CascadedExplosionLevel, particleScale: particleScale, hitEntity: m_collidedEntity, ownerEntity: m_ownerEntity);
              }
              m_wasPenetration = false;
              m_hasExplosion = true;
          }        */

                if (m_usedAmmo.AmmoType == MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Proximity_Explosive)
                {
                    //  Look for small ships in shots's proximity
                    BoundingSphere boundingSphere = new BoundingSphere(GetPosition(), MyCannonShotConstants.PROXIMITY_DETECTION_RADIUS);
                    BoundingBox boundingBox = new BoundingBox();
                    BoundingBox.CreateFromSphere(ref boundingSphere, out boundingBox);

                    var elements = MyEntities.GetElementsInBox(ref boundingBox);
                    for (int i = 0; i < elements.Count; i++)
                    {
                        var rigidBody = (MyPhysicsBody)elements[i].GetRigidBody().m_UserData;
                        var entity = rigidBody.Entity;


                        if (!(entity is MinerWars.AppCode.Game.Entities.MySmallShip))
                            continue;
                        if (entity == OwnerEntity)
                            continue;
                        if (entity == this)
                            continue;

                        Explode(entity);
                        break;
                    }
                    elements.Clear();
                }

                /*
                if (m_usedAmmo.AmmoType == MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Tunnel_Buster)
                {
                    m_cuttingSphere.Center = GetPosition();

                    //  We found voxel so lets make tunel into it
                    MyPhysObjectBase collisionResult = MyEntities.GetIntersectionWithSphere(ref m_cuttingSphere, this, (MySmallShip)Parent);
                    if (collisionResult is MyVoxelMap)
                    {
                        MyVoxelMap voxelMap = collisionResult as MyVoxelMap;
                        if (m_penetratedVoxelMap == null)
                        {
                            m_penetratedVoxelMap = voxelMap;
                            m_penetrationOrigin = GetPosition();
                        }

                        Game.Voxels.MyVoxelGenerator.CutOutSphereFast(voxelMap, m_cuttingSphere);
                    }
                } */
                /*
          if (m_usedAmmo.AmmoType == MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Tunnel_Buster)
          {
              if (m_penetratedVoxelMap != null)
              {
                  //MyCannonShotConstants.BUSTER_PENETRATION_LENGTH
                  float busterPenetrationLength = m_ammoProperties.ExplosionRadius * 0.75f;
                  if (Vector3.Distance(m_penetrationOrigin, GetPosition()) >= busterPenetrationLength)
                  {
                      m_collisionPoint = GetPosition(); //We want to explode inside voxel, not on collision point
                      Explode(m_penetratedVoxelMap);
                  }
              }
          }    */
            }
            finally
            {
                MyRender.GetRenderProfiler().EndProfilingBlock();
            }
        }
Пример #6
0
        protected override void OnContactStart(MyContactEventInfo contactInfo)
        {
            var collidedEntity = contactInfo.GetOtherEntity(this);

            if (!(collidedEntity is MyMeteor))
            {
                MyParticleEffect pe = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.Explosion_Meteor);
                pe.WorldMatrix = this.WorldMatrix;
                pe.UserScale = this.m_size * 0.01f;


                MyExplosion newExplosion = MyExplosions.AddExplosion();
                MyExplosionInfo info = new MyExplosionInfo()
                {
                    PlayerDamage = 100,
                    Damage = 100,
                    EmpDamage = 0,
                    ExplosionType = MyExplosionTypeEnum.METEOR_EXPLOSION,
                    ExplosionSphere = new BoundingSphere(GetPosition(), m_size),
                    LifespanMiliseconds = MyExplosionsConstants.EXPLOSION_LIFESPAN,
                    ParticleScale = 1,
                    OwnerEntity = this,
                    HitEntity = collidedEntity,
                    ExplosionFlags = MyExplosionFlags.APPLY_FORCE_AND_DAMAGE | MyExplosionFlags.AFFECT_VOXELS | MyExplosionFlags.CREATE_DEBRIS /*| MyExplosionFlags.FORCE_DEBRIS*/,
                    PlaySound = true,
                    VoxelCutoutScale = 1,
                    VoxelExplosionCenter = GetPosition()
                };

                if (newExplosion != null)
                {
                    newExplosion.Start(ref info);
                }


                this.MarkForClose();
            }
        }
Пример #7
0
        private void DisableContainedDummyParticles(ref MyExplosionInfo explosionInfo)
        {
            BoundingBox aabb = BoundingBox.CreateFromSphere(explosionInfo.ExplosionSphere);
            MyRender.GetEntitiesFromPrunningStructure(ref aabb, m_destroyHelper);

            foreach (var elem in m_destroyHelper)
            {
                var entity = ((MyRenderObject)elem).Entity;

                var dummyPoint = entity as MyDummyPoint;
                if (dummyPoint != null && !dummyPoint.CanSurvivePrefabDestruction())
                {
                    var position = dummyPoint.GetPosition();
                    dummyPoint.DisableParticleEffect();
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Starts the explosion.
        /// </summary>
        /// <param name="damage"></param>
        /// <param name="type"></param>
        /// <param name="explosionSphere"></param>
        /// <param name="lifespanInMiliseconds"></param>
        /// <param name="explosionForceDirection"></param>
        /// <param name="groupMask"></param>
        /// <param name="createExplosionDebris"></param>
        /// <param name="cascadeLevel"></param>
        /// <param name="hitEntity"></param>
        /// <param name="particleScale"></param>
        /// <param name="ownerEntity"></param>
        /// <param name="affectVoxels"></param>
        /// <param name="applyForceAndDamage"></param>
        /// <param name="createDecals"></param>
        /// <param name="direction">If applicable, gives the direction of the explosion, e.g. when it was caused by a missile (with its moving direction).</param>
        public void Start(ref MyExplosionInfo explosionInfo)
        {
            //MyCommonDebugUtils.AssertDebug(explosionInfo.ExplosionSphere.Radius <= MyExplosionsConstants.EXPLOSION_RADIUS_MAX);
            MyCommonDebugUtils.AssertDebug(explosionInfo.ExplosionSphere.Radius > 0);

            MyRender.GetRenderProfiler().StartProfilingBlock("MyExplosion.Start");

            m_explosionSphere = explosionInfo.ExplosionSphere;
            m_elapsedMiliseconds = 0;
            m_lifespanInMiliseconds = explosionInfo.LifespanMiliseconds;

            if (explosionInfo.PlaySound)
            {
                MyRender.GetRenderProfiler().StartProfilingBlock("Sound");
                //  Play explosion sound            
                if (m_explosionCue != null && m_explosionCue.Value.IsPlaying)
                {
                    m_explosionCue.Value.Stop(SharpDX.XACT3.StopFlags.Immediate);
                }
                m_explosionCue = MyAudio.AddCue3D(GetCueEnumByExplosionType(explosionInfo.ExplosionType), m_explosionSphere.Center, Vector3.Zero, Vector3.Zero, Vector3.Zero);
                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            MyRender.GetRenderProfiler().StartProfilingBlock("Light");
            //  Light of explosion
            /*
            m_light = MyLights.AddLight();
            if (m_light != null)
            {
                m_light.Start(MyLight.LightTypeEnum.PointLight, m_explosionSphere.Center, MyExplosionsConstants.EXPLOSION_LIGHT_COLOR, 1, Math.Min(m_explosionSphere.Radius * 8.0f, MyLightsConstants.MAX_POINTLIGHT_RADIUS));
                m_light.Intensity = 2.0f;
            } */
            MyRender.GetRenderProfiler().EndProfilingBlock();

            // close explosion check
            bool close = IsExplosionClose(explosionInfo.ExplosionSphere);

            MyParticleEffectsIDEnum newParticlesType;

            switch (explosionInfo.ExplosionType)
            {
                case MyExplosionTypeEnum.SMALL_SHIP_EXPLOSION:
                    //  Create metal debris objects thrown from the explosion
                    //  This must be called before ApplyExplosionForceAndDamage (because there we apply impulses to the debris)
                    //  Throw a lot of debrises, more than only if some metalic object is hit (because this is destruction of a ship)
                    //MyPhysObjectExplosionDebrises.CreateExplosionDebris(m_explosionSphere.Center, 1);
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Smallship;
                    break;
                case MyExplosionTypeEnum.MISSILE_EXPLOSION:
                    newParticlesType =
                        // ? MyParticleEffectsIDEnum.Explosion_Missile_Close
                                          MyParticleEffectsIDEnum.Explosion_Missile;
                    break;

                case MyExplosionTypeEnum.BOMB_EXPLOSION:
                case MyExplosionTypeEnum.GRAVITY_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Bomb;
                    break;

                case MyExplosionTypeEnum.AMMO_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Ammo;
                    break;

                case MyExplosionTypeEnum.BLASTER_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Blaster;
                    break;

                case MyExplosionTypeEnum.BIOCHEM_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_BioChem;
                    break;

                case MyExplosionTypeEnum.EMP_EXPLOSION:
                case MyExplosionTypeEnum.FLASH_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_EMP;
                    break;
                case MyExplosionTypeEnum.METEOR_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Meteor;
                    break;
                case MyExplosionTypeEnum.NUCLEAR_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Nuclear;
                    break;
                case MyExplosionTypeEnum.PLASMA_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Plasma;
                    break;
                case MyExplosionTypeEnum.SMALL_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_SmallPrefab;
                    break;
                case MyExplosionTypeEnum.LARGE_SHIP_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Huge;
                    break;
                case MyExplosionTypeEnum.LARGE_PREFAB_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Large;
                    break;
                case MyExplosionTypeEnum.MEDIUM_PREFAB_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Medium;
                    break;
                case MyExplosionTypeEnum.ASTEROID_EXPLOSION:
                    newParticlesType = MyParticleEffectsIDEnum.Explosion_Asteroid;
                    break;

                default:
                    throw new System.NotImplementedException();
                    break;
            }


            if (explosionInfo.Damage > 0)
            {
                MyRender.GetRenderProfiler().StartProfilingBlock("Voxel or collision");

                //  If explosion sphere intersects a voxel map, we need to cut out a sphere, spawn debrises, etc
                MyVoxelMap voxelMap = explosionInfo.AffectVoxels && explosionInfo.EmpDamage == 0 ? MyVoxelMaps.GetOverlappingWithSphere(ref m_explosionSphere) : null;
                if (voxelMap != null)
                {
                    //  Dirty explosion with a lot of dust

                    MyMwcVoxelMaterialsEnum? voxelMaterial = null;
                    float voxelContentRemovedInPercent = 0;

                    bool createDebris = true; // We want to create debris

                    if (explosionInfo.HitEntity != null) // but not when we hit prefab
                    {
                        createDebris &= explosionInfo.HitEntity is MyVoxelMap;
                    }


                    //cut off 
                    BoundingSphere voxelExpSphere = new BoundingSphere(explosionInfo.VoxelExplosionCenter, m_explosionSphere.Radius * explosionInfo.VoxelCutoutScale);
                    if (MyVoxelGenerator.CutOutSphereFast(voxelMap, voxelExpSphere, out voxelContentRemovedInPercent, out voxelMaterial, (explosionInfo.OwnerEntity is MySmallShip && explosionInfo.OwnerEntity == Managers.Session.MySession.PlayerShip), MyFakes.VOXELS_REMOVE_RATIO))
                    {
                        if (explosionInfo.HitEntity is MyVoxelMap)
                        {
                            HUD.MyHud.ShowIndestructableAsteroidNotification();
                        }
                        createDebris = false; // and no debris when voxel is indestructible
                    }

                    //  Only if at least something was removed from voxel map
                    //  If voxelContentRemovedInPercent is more than zero than also voxelMaterial shouldn't be null, but I rather check both of them.
                    if ((voxelContentRemovedInPercent > 0) && (voxelMaterial != null))
                    {
                        //remove decals
                        MyDecals.HideTrianglesAfterExplosion(voxelMap, ref voxelExpSphere);

                        MyRender.GetRenderProfiler().StartProfilingBlock("CreateDebris");

                        if (explosionInfo.CreateDebris && (createDebris || explosionInfo.ForceDebris) && MyRenderConstants.RenderQualityProfile.ExplosionDebrisCountMultiplier > 0)
                        {
                            //  Create debris rocks thrown from the explosion
                            //  This must be called before ApplyExplosionForceAndDamage (because there we apply impulses to the debris)
                            MyExplosionDebrisVoxel.CreateExplosionDebris(ref voxelExpSphere, voxelContentRemovedInPercent, voxelMaterial.Value, explosionInfo.GroupMask, voxelMap);
                        }

                        MyRender.GetRenderProfiler().EndProfilingBlock();

                        MyRender.GetRenderProfiler().StartProfilingBlock("CreateParticleEffect");

                        MyParticleEffect explosionEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.MaterialExplosion_Destructible);
                        explosionEffect.WorldMatrix = Matrix.CreateTranslation(voxelExpSphere.Center);
                        explosionEffect.UserRadiusMultiplier = voxelExpSphere.Radius;

                        MyRender.GetRenderProfiler().EndProfilingBlock();
                    }

                }
                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            if (explosionInfo.Damage > 0)
            {
                //  Create dirt decals in player's cockpit glass
                MyRender.GetRenderProfiler().StartProfilingBlock("Cockpit Decals");
                CreateDirtDecalOnCockpitGlass(ref m_explosionSphere);
                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            if (DEBUG_EXPLOSIONS)
            {
                MyRender.GetRenderProfiler().EndProfilingBlock();
                return;
            }

            if (explosionInfo.Damage > 0)
            {
                BoundingSphere influenceExplosionSphere = m_explosionSphere;
                influenceExplosionSphere.Radius *= MyExplosionsConstants.EXPLOSION_RADIUS_MULTPLIER_FOR_IMPULSE;
                for (int i = 0; i < explosionInfo.CascadeLevel; i++)
                {
                    influenceExplosionSphere.Radius *= MyExplosionsConstants.EXPLOSION_CASCADE_FALLOFF;
                }

                //  Throws surrounding objects away from centre of the explosion.
                if (explosionInfo.ApplyForceAndDamage)
                {
                    if (explosionInfo.ExplosionType == MyExplosionTypeEnum.LARGE_PREFAB_EXPLOSION ||
                        explosionInfo.ExplosionType == MyExplosionTypeEnum.LARGE_SHIP_EXPLOSION ||
                        explosionInfo.ExplosionType == MyExplosionTypeEnum.MEDIUM_PREFAB_EXPLOSION)
                        DisableContainedDummyParticles(ref explosionInfo);

                    explosionInfo.StrengthImpulse = MyExplosionsConstants.EXPLOSION_STRENGTH_IMPULSE * m_explosionSphere.Radius / 20;
                    explosionInfo.StrengthAngularImpulse = MyExplosionsConstants.EXPLOSION_STRENGTH_ANGULAR_IMPULSE;
                    explosionInfo.HitEntity = explosionInfo.HitEntity != null ? explosionInfo.HitEntity.GetBaseEntity() : null;

                    MyRender.GetRenderProfiler().StartProfilingBlock("ApplyExplosionForceAndDamage");
                    MyEntities.ApplyExplosionForceAndDamage(ref explosionInfo);
                    MyRender.GetRenderProfiler().EndProfilingBlock();
                }

                //  Look for objects in explosion radius
                BoundingBox boundingBox;
                BoundingBox.CreateFromSphere(ref influenceExplosionSphere, out boundingBox);

                //if (explosionInfo.CreateDecals && explosionInfo.Direction.HasValue && explosionInfo.EmpDamage == 0)
                //{
                //    CreateDecals(explosionInfo.Direction.Value);
                //}
            }

            if (explosionInfo.CreateParticleEffect)
            {
                MyRender.GetRenderProfiler().StartProfilingBlock("Particles");

                if (explosionInfo.CustomEffect != null)
                {
                    if (explosionInfo.CustomEffect.ParticleID == 0)
                        explosionInfo.CustomEffect.ParticleID = (int)newParticlesType;
                    //Reload effect
                    explosionInfo.CustomEffect.Enabled = false;
                    explosionInfo.CustomEffect.Enabled = true;
                }
                else
                {
                    //  Explosion particles
                    GenerateExplosionParticles(newParticlesType, m_explosionSphere, explosionInfo.ParticleScale);
                }

                MyRender.GetRenderProfiler().EndProfilingBlock();
            }

            MyRender.GetRenderProfiler().EndProfilingBlock();

            /*
                // When MyAmmoBase entity is closed to explosion it will explode
                if (entity is MyAmmoBase)
                {
                    (entity as MyAmmoBase).ExplodeCascade(cascadeLevel + 1);
                }
                */

            //  Smut decals - must be called after the explosion, after voxels are cutted out
            /*if ((intersection.PhysObject is MyVoxelMap) == false)
            {
                if (intersection.PhysObject is MyCockpitGlass)
                {
                    //  Change phys object so rest of the code will think we hit the parent
                    //  Same fix is in projectile too - because cockpit glass is only helper object, we don't use it for real rendering and stuff
                    //  And if not changed, it can make problem in "phys object decals"
                    intersection.PhysObject = intersection.PhysObject.Parent;
                }

                //  Create explosion smut decal on model we hit by this missile                
                MyDecals.Add(
                    MyDecalTexturesEnum.ExplosionSmut,
                    MyMwcUtils.GetRandomFloat(m_explosionSphere.Radius * 0.7f, m_explosionSphere.Radius * 1.3f),
                    MyMwcUtils.GetRandomRadian(),
                    GetSmutDecalRandomColor(),
                    true,
                    ref intersection);
            }
            else
            {
                //  Creating explosion smut decal on voxel is more complicated than on voxel. We will project few lines
                //  from explosion epicentrum to the surounding world (random directions) and place decal where intersection detected.
                //if (knownMissileDirection != null)
                //{
                //    MyLine linePrologned = new MyLine(knownIntersection.Value.IntersectionPointInObjectSpace,
                //        knownIntersection.Value.IntersectionPointInObjectSpace + knownMissileDirection.Value * MyExplosionsConstants.EXPLOSION_RANDOM_RADIUS_MAX * 2,
                //        true);
                //    MyLineTriangleIntersectionResult intersectionForSmut = knownIntersection.Value.VoxelMap.GetIntersectionWithLine(ref linePrologned);
                //    if (intersectionForSmut.Found == true)
                //    {
                //        MyDecals.Add(
                //            MyDecalTexturesEnum.ExplosionSmut,
                //            MyMwcUtils.GetRandomFloat(m_explosionSphere.Radius * 0.5f, m_explosionSphere.Radius * 1.0f),
                //            MyMwcUtils.GetRandomRadian(),
                //            GetSmutDecalRandomColor(),
                //            false,
                //            ref intersectionForSmut);
                //    }
                //}
            }*/

            //  Generate dust particles that will stay in place of the explosion
            //doesnt look good in final 
            //GenerateStatisDustParticles(m_explosionSphere);
        }
Пример #9
0
 public void Start(float playerDamage, float damage, float empDamage, MyExplosionTypeEnum type, BoundingSphere explosionSphere, int lifespanInMiliseconds, MyExplosionForceDirection explosionForceDirection, MyGroupMask groupMask, bool createExplosionDebris, int cascadeLevel = 0, MyEntity hitEntity = null, float particleScale = 1.0f, MyEntity ownerEntity = null, bool affectVoxels = true, bool applyForceAndDamage = true, bool createDecals = true, Vector3? direction = null, bool forceDebris = false, bool playSound = false)
 {
     MyExplosionInfo info = new MyExplosionInfo(playerDamage, damage, empDamage, explosionSphere, type, playSound)
     {
         LifespanMiliseconds = lifespanInMiliseconds,
         ExplosionForceDirection = explosionForceDirection,
         GroupMask = groupMask,
         ExplosionFlags = MyExplosionFlags.CREATE_PARTICLE_EFFECT,
         CascadeLevel = cascadeLevel,
         HitEntity = hitEntity,
         ParticleScale = particleScale,
         OwnerEntity = ownerEntity,
         Direction = direction,
         VoxelCutoutScale = 1.0f,
     };
     info.AffectVoxels = affectVoxels;
     info.ApplyForceAndDamage = applyForceAndDamage;
     info.CreateDebris = createExplosionDebris;
     info.CreateDecals = createDecals;
     info.ForceDebris = forceDebris;
     info.VoxelExplosionCenter = explosionSphere.Center;
     Start(ref info);
 }
Пример #10
0
 //  Start explosion at specified position, with radius and lifespan.
 //      type - specifies what type of object exploded
 //      explosionSphere - position and radius
 //      lifespanInMiliseconds - explosion life span
 //  IMPORTANT: This class isn't realy inicialized by constructor, but by Start()
 public void Start(float playerDamage, float damage, float empDamage, MyExplosionTypeEnum type, BoundingSphere explosionSphere, int lifespanInMiliseconds, int cascadeLevel = 0, MyEntity hitEntity = null, float particleScale = 1.0f, MyEntity ownerEntity = null, bool forceDebris = false, bool createDecals = true, float voxelCutoutScale = 1.0f, bool playSound = true, bool checkIntersections = true)
 {
     //  Call main explosion starter
     MyExplosionInfo info = new MyExplosionInfo(playerDamage, damage, empDamage, explosionSphere, type, playSound)
     {
         LifespanMiliseconds = lifespanInMiliseconds,
         ExplosionForceDirection = MyExplosionForceDirection.EXPLOSION,
         GroupMask = MyGroupMask.Empty,
         ExplosionFlags = MyExplosionFlags.CREATE_DEBRIS | MyExplosionFlags.AFFECT_VOXELS | MyExplosionFlags.APPLY_FORCE_AND_DAMAGE | MyExplosionFlags.CREATE_PARTICLE_EFFECT,
         CascadeLevel = cascadeLevel,
         HitEntity = hitEntity,
         ParticleScale = particleScale,
         OwnerEntity = ownerEntity,
         Direction = null,
         VoxelCutoutScale = voxelCutoutScale,
         CheckIntersections = checkIntersections,
     };
     info.ForceDebris = forceDebris;
     info.CreateDecals = createDecals;
     info.VoxelExplosionCenter = explosionSphere.Center;
     Start(ref info);
 }