public static void Draw() { if (m_Enabled && IsAnyEditorActive()) { VoxelHandShape.Draw(); if (MyVoxelConstants.VOXEL_HAND_DRAW_CONE && !MyFakes.MWBUILDER) { VoxelHandShape.DrawCone(m_conePosition); } if (MyEditor.DisplayVoxelBounding) { foreach (MyEntity voxelMapEntity in MyVoxelMaps.GetVoxelMaps()) { MyVoxelMap voxelMap = voxelMapEntity as MyVoxelMap; voxelMap.DrawBounding(); } } if (MyFakes.MWBUILDER) { Matrix wm = VoxelHandShape.WorldMatrix; Vector4 clr = Vector4.One; MySimpleObjectDraw.DrawTransparentSphere(ref wm, 10, ref clr, false, 8); MyDebugDraw.TextBatch.AddText(wm.Translation, new System.Text.StringBuilder(MyUtils.GetFormatedVector3(wm.Translation, 0)), Color.White, 0.8f); } } }
/// <summary> /// DrawSelectedBounding /// </summary> private void DrawSelectedBounding() { if (MyConfig.EditorDisplayUnselectedBounding) { Vector4 color = new Vector4(0.6f, 0.6f, 0.6f, 0.2f); foreach (MyEntity entity in MyEntities.GetEntities()) { entity.DebugDrawBox(color, false); } foreach (MyVoxelMap voxelMap in MyVoxelMaps.GetVoxelMaps()) { MyDebugDraw.DrawHiresBoxWireframe(Matrix.CreateScale(voxelMap.GetSize()) * voxelMap.WorldMatrix, new Vector3(0, 0.4f, 0), 0.3f); } } if (IsEditingPrefabContainer()) { m_activePrefabContainer.DebugDrawBox(new Vector4(1, 1, 0, 0.4f)); } foreach (MyEntity entity in MyEditorGizmo.SelectedEntities) { if (entity is MyPrefabContainer) { MyPrefabContainer container = (MyPrefabContainer)entity; container.DebugDrawBox(new Vector4(0, 1, 0, 0.4f)); } } }
/// <summary> /// Removes all entities - TODO - this will have to be unified in MyEntities.cs /// </summary> void RemoveAllEntities() { //MyEditor.Static.DeleteAllFromCollidingList(); MyEditor.Static.CollidingElements.Clear(); MyEntities.CollisionsElements.Clear(); MyEditorGizmo.ClearSelection(); MyEntities.CloseAll(false); MyVoxelMaps.RemoveAll(); }
/// <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); }
//public static event OnVoxelShapeSizeChanged OnVoxelShapeSize; //public static event OnVoxelShapeDistanceChanged OnVoxelShapeDistance; public static void HandleInput(MyGuiInput input) { // exit voxel hand using this key if (input.IsEditorControlNewPressed(MyEditorControlEnums.VOXEL_HAND)) { SwitchEnabled(); } if (m_Enabled == false || !IsAnyEditorActive()) { return; } m_applyToVoxelMap = null; //here possible change if ((input.IsEditorControlNewPressed(MyEditorControlEnums.PRIMARY_ACTION_KEY) || input.IsAnyShiftKeyPressed() && input.IsEditorControlPressed(MyEditorControlEnums.PRIMARY_ACTION_KEY)) && (m_timeFromLastShaping >= MyVoxelConstants.VOXEL_HAND_SHAPING_INTERVAL || MyFakes.RAPID_VOXEL_HAND_SHAPING_ENABLED || MyFakes.MWBUILDER)) { m_timeFromLastShaping = 0; if (DetachedVoxelHand != null && !input.IsKeyPress(Keys.Space)) { return; } MyVoxelMap voxelMap = null; if (VoxelHandShape is MyVoxelHandSphere) { MyVoxelHandSphere sphere = (MyVoxelHandSphere)VoxelHandShape; BoundingSphere vol = sphere.WorldVolume; voxelMap = MyVoxelMaps.GetIntersectionWithSphere(ref vol, SelectedVoxelMap); } else if (VoxelHandShape is MyVoxelHandBox) { MyVoxelHandBox box = (MyVoxelHandBox)VoxelHandShape; BoundingBox localBoundingBox = box.GetLocalBoundingBox(); Vector3 boxWorldPosition = box.GetPosition(); voxelMap = MyVoxelMaps.GetIntersectionWithBox(ref localBoundingBox, ref boxWorldPosition, SelectedVoxelMap); } else if (VoxelHandShape is MyVoxelHandCuboid) { MyVoxelHandCuboid cuboid = (MyVoxelHandCuboid)VoxelHandShape; BoundingBox localBoundingBox = cuboid.GetLocalBoundingBox(); Vector3 boxWorldPosition = cuboid.GetPosition(); voxelMap = MyVoxelMaps.GetIntersectionWithBox(ref localBoundingBox, ref boxWorldPosition, SelectedVoxelMap); } else if (VoxelHandShape is MyVoxelHandCylinder) { MyVoxelHandCylinder cylinder = (MyVoxelHandCylinder)VoxelHandShape; BoundingBox localBoundingBox = cylinder.GetLocalBoundingBox(); Vector3 boxWorldPosition = cylinder.GetPosition(); voxelMap = MyVoxelMaps.GetIntersectionWithBox(ref localBoundingBox, ref boxWorldPosition, SelectedVoxelMap); } else { System.Diagnostics.Debug.Assert(false); } if (voxelMap != null) { m_applyToVoxelMap = voxelMap; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////// // Change size of asteroid tool from camera //////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * if (input.IsAnyShiftKeyPressed()) * { * if (input.PreviousMouseScrollWheelValue() > input.MouseScrollWheelValue()) * { * SetVoxelSize(MyEditorVoxelHand.VoxelHandShape.GetShapeSize() - MyVoxelConstants.VOXEL_HAND_SIZE_STEP); * } * else if (input.PreviousMouseScrollWheelValue() < input.MouseScrollWheelValue()) * { * SetVoxelSize(MyEditorVoxelHand.VoxelHandShape.GetShapeSize() + MyVoxelConstants.VOXEL_HAND_SIZE_STEP); * } * * } * * //////////////////////////////////////////////////////////////////////////////////////////////////////////// * // Change distance of asteroid tool from camera * //////////////////////////////////////////////////////////////////////////////////////////////////////////// * * if (input.IsAnyControlPress()) * { * if (input.PreviousMouseScrollWheelValue() > input.MouseScrollWheelValue()) * { * SetShapeDistance(GetShapeDistance() - MyVoxelConstants.VOXEL_HAND_DISTANCE_STEP); * * } * else if (input.PreviousMouseScrollWheelValue() < input.MouseScrollWheelValue()) * { * SetShapeDistance(GetShapeDistance() + MyVoxelConstants.VOXEL_HAND_DISTANCE_STEP); * } * } */ }
protected override void Drill() { // Sphere which is used to make tunnel to voxel and sphere for testing collision with voxel m_fakeCollisionSphere = new BoundingSphere(m_fakeSpherePositionTransformed, m_radius); // Check for collision with drill and world //MyEntity collisionResult = MyEntities.GetIntersectionWithSphere(ref m_fakeCollisionSphere, this, Parent, false, true); // bSphere collision doesn't work - the sphere is tested against LOD0 model, but it is hidden inside the COL model and the bSphere is too small to reach it - so I use line instead MyEntity collisionResult = null; MyLine line; if (MySession.Is25DSector) { line = new MyLine(m_positionMuzzleInWorldSpace - 10 * WorldMatrix.Forward, m_positionMuzzleInWorldSpace + 20 * WorldMatrix.Forward, true); } else { line = new MyLine(m_positionMuzzleInWorldSpace - 10 * WorldMatrix.Forward, m_positionMuzzleInWorldSpace + 5 * WorldMatrix.Forward, true); } MyIntersectionResultLineTriangleEx?intersection = MyEntities.GetIntersectionWithLine(ref line, Parent, this, true, true); if (intersection != null && intersection.Value.Entity.Physics != null) { collisionResult = intersection.Value.Entity; } if (!(collisionResult is MyVoxelMap)) { m_lastTimeDrillNotCollidedWithVoxelMapInMiliseconds = MyMinerGame.TotalGamePlayTimeInMilliseconds; if (!MySession.Is25DSector) { ((MySmallShip)Parent).IncreaseHeadShake(MyDrillDeviceConstants.SHAKE_DURING_ROTATION); } StopDustEffect(); if (collisionResult != null) { var effect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.MaterialHit_Autocannon_Metal); effect.WorldMatrix = Matrix.CreateTranslation(m_fakeCollisionSphere.Center); collisionResult.DoDamage(0, m_damage * MyConstants.PHYSICS_STEP_SIZE_IN_SECONDS, 0, MyDamageType.Drill, MyAmmoType.Basic, Parent); } } // Display particles when we are in contact with voxel else { if (m_dustEffect == null) { m_dustEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.Smoke_DrillDust); } m_dustEffect.WorldMatrix = Matrix.CreateTranslation(m_fakeSpherePositionTransformed); m_dustEffect.UserScale = MySession.Is25DSector ? 3 : 1; ((MySmallShip)Parent).IncreaseHeadShake(MyDrillDeviceConstants.SHAKE_DURING_IN_VOXELS); } // Play sound if there is collision with voxel if (collisionResult != null) { if (collisionResult is MyStaticAsteroid) { if (!collisionResult.IsDestructible) { MinerWars.AppCode.Game.HUD.MyHud.ShowIndestructableAsteroidNotification(); } } StartDrillingCue(collisionResult is MyVoxelMap); StopMovingCue(); } else { StartMovingCue(); StopDrillingCue(); } // We found voxel so lets make tunel into it using (var voxelMapsFound = PoolList <MyVoxelMap> .Get()) { bool drilled = false; bool drilledSomeDestructibleContent = false; MyVoxelMaps.GetListOfVoxelMapsWhoseBoundingSphereIntersectsSphere(ref m_fakeCollisionSphere, voxelMapsFound, null); int drillInterval = MySession.Is25DSector ? 100 : (int)MyDrillDeviceConstants.DRILL_INTERVAL_IN_MILISECONDS; int timerToDrillInterval = MySession.Is25DSector ? 100 : (int)MyDrillDeviceConstants.TIME_TO_DRILL_VOXEL_IN_MILISECONDS; foreach (MyVoxelMap voxelMap in voxelMapsFound) { if ((collisionResult is MyVoxelMap) && ((MyMinerGame.TotalGamePlayTimeInMilliseconds - m_lastTimeDrilled) > drillInterval) && (MyMinerGame.TotalGamePlayTimeInMilliseconds - m_lastTimeDrillNotCollidedWithVoxelMapInMiliseconds) > timerToDrillInterval) { drilled = true; float rangeStep = 0; float radius = GetRadiusNeededForTunel(); BoundingSphere bigSphereForTunnel = new BoundingSphere(m_fakeCollisionSphere.Center, radius); while (rangeStep < m_range) { MyMwcVector3Int exactCenterOfDrilling = voxelMap.GetVoxelCoordinateFromMeters(bigSphereForTunnel.Center); // we don't want to drill indestructible voxels or empty space if (voxelMap.IsVoxelInVoxelMap(ref exactCenterOfDrilling) && voxelMap.GetVoxelMaterialIndestructibleContent(ref exactCenterOfDrilling) == MyVoxelConstants.VOXEL_CONTENT_FULL) { break; } else { drilledSomeDestructibleContent = true; } CutOutFromVoxel(voxelMap, ref bigSphereForTunnel); bigSphereForTunnel.Center += 2 * WorldMatrix.Forward; rangeStep += 1; } } } if (drilled) { m_lastTimeDrilled = MyMinerGame.TotalGamePlayTimeInMilliseconds; if (!drilledSomeDestructibleContent) { HUD.MyHud.ShowIndestructableAsteroidNotification(); } } } }
protected override bool Interact(bool staticCollision) { if (staticCollision) { //MyCommonDebugUtils.AssertDebug(false, "Sphere-voxel static interaction called! And that's wrong."); } else { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("SphereVoxelInteraction"); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("Transformations"); if (RBElement1.GetElementType() != MyRBElementType.ET_SPHERE) { SwapElements(); } Matrix matrix0 = RBElement1.GetGlobalTransformation(); Matrix matrix1 = RBElement2.GetGlobalTransformation(); float sphereRadius = ((MyRBSphereElement)RBElement1).Radius; Vector3 body0Pos = matrix0.Translation; // sphere pos Vector3 body1Pos = matrix1.Translation; float dt = MyPhysics.physicsSystem.GetRigidBodyModule().CurrentTimeStep; float epsylon = MyPhysics.physicsSystem.GetRigidBodyModule().CollisionEpsilon; Vector3 newBody0Pos = matrix0.Translation + GetRigidBody1().LinearVelocity *dt; float sphereTolR = epsylon + sphereRadius; float sphereTolR2 = sphereTolR * sphereTolR; MySmallCollPointInfo[] collPtArray = MyContactInfoCache.SCPIStackAlloc(); int numCollPts = 0; Vector3 collNormal = Vector3.Zero; //var colDetThroughVoxels = MyConstants.SPHERE_VOXELMAP_COLDET_THROUGH_VOXELS; var colDetThroughVoxels = !GetRigidBody1().ReadFlag(RigidBodyFlag.RBF_COLDET_THROUGH_VOXEL_TRIANGLES); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); if (colDetThroughVoxels) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("colDetThroughVoxels"); BoundingSphere newSphere; newSphere.Center = newBody0Pos; newSphere.Radius = sphereRadius; MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("PoolList.Get"); using (var voxelMapsFounded = PoolList <MyVoxelMap> .Get()) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("GetListOfVoxelMapsWhoseBoundingSphereIntersectsSphere"); MyVoxelMaps.GetListOfVoxelMapsWhoseBoundingSphereIntersectsSphere(ref newSphere, voxelMapsFounded, null); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartNextBlock("foreach (MyVoxelMap voxelMap in voxelMapsFounded)"); foreach (MyVoxelMap voxelMap in voxelMapsFounded) { if (voxelMap != null) { // We will iterate only voxels contained in the bounding box of new sphere, so here we get min/max corned in voxel units MyMwcVector3Int minCorner = voxelMap.GetVoxelCoordinateFromMeters(new Vector3( newSphere.Center.X - newSphere.Radius, newSphere.Center.Y - newSphere.Radius, newSphere.Center.Z - newSphere.Radius)); MyMwcVector3Int maxCorner = voxelMap.GetVoxelCoordinateFromMeters(new Vector3( newSphere.Center.X + newSphere.Radius, newSphere.Center.Y + newSphere.Radius, newSphere.Center.Z + newSphere.Radius)); voxelMap.FixVoxelCoord(ref minCorner); voxelMap.FixVoxelCoord(ref maxCorner); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("for loop"); MyMwcVector3Int tempVoxelCoord; for (tempVoxelCoord.X = minCorner.X; tempVoxelCoord.X <= maxCorner.X; tempVoxelCoord.X++) { for (tempVoxelCoord.Y = minCorner.Y; tempVoxelCoord.Y <= maxCorner.Y; tempVoxelCoord.Y++) { for (tempVoxelCoord.Z = minCorner.Z; tempVoxelCoord.Z <= maxCorner.Z; tempVoxelCoord.Z++) { byte voxelContent = voxelMap.GetVoxelContent(ref tempVoxelCoord); // Ignore voxels bellow the ISO value (empty, partialy empty...) if (voxelContent < MyVoxelConstants.VOXEL_ISO_LEVEL) { continue; } Vector3 voxelPosition = voxelMap.GetVoxelCenterPositionAbsolute(ref tempVoxelCoord); //float voxelSize = MyVoxelMaps.GetVoxelContentAsFloat(voxelContent) * MyVoxelConstants.VOXEL_SIZE_IN_METRES_HALF; float voxelSize = MyVoxelMaps.GetVoxelContentAsFloat(voxelContent) * MyVoxelConstants.VOXEL_RADIUS; // If distance to voxel border is less than sphere radius, we have a collision // So now we calculate normal vector and penetration depth but on OLD sphere float newDistanceToVoxel = Vector3.Distance(voxelPosition, newSphere.Center) - voxelSize; if (newDistanceToVoxel < (epsylon + newSphere.Radius)) { Vector3 collisionN = MyMwcUtils.Normalize(voxelPosition - body0Pos); if (numCollPts < MyPhysicsConfig.MaxContactPoints) { // Calculate penetration depth, but from old sphere (not new) float oldDistanceToVoxel = Vector3.Distance(voxelPosition, newSphere.Center) - voxelSize; float oldPenetrationDepth = oldDistanceToVoxel - sphereRadius; // Vector3 pt = body0Pos + sphereRadius * collisionN; Vector3 pt = voxelPosition - collisionN * (voxelSize - epsylon); collPtArray[numCollPts++] = new MySmallCollPointInfo(pt - body0Pos, pt - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, oldPenetrationDepth, pt); } collNormal -= collisionN; } } } } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } else //if (colDetThroughVoxels) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("ColDet triangles"); int optimalIterationCount = (int)(GetRigidBody1().LinearVelocity.Length() * dt / sphereRadius); int maxIndex = (int)MathHelper.Min(MathHelper.Max(optimalIterationCount, 1), 16); for (int i = 0; i < maxIndex; i++) { float velocityAdd = GetRigidBody1().LinearVelocity.Length() * dt / (float)maxIndex; Vector3 interpolatedPosition = body0Pos + GetRigidBody1().LinearVelocity *dt *i / (float)maxIndex; BoundingSphere newSphere; newSphere.Center = interpolatedPosition; newSphere.Radius = sphereRadius; int numTriangles; BoundingBox bb = BoundingBox.CreateFromSphere(newSphere); MyVoxelMaps.GetPotentialTrianglesForColDet(out numTriangles, ref bb); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { MyColDetVoxelTriangle meshTriangle = MyVoxelMaps.PotentialColDetTriangles[iTriangle]; // mesh.GetTriangle(potentialTriangles[iTriangle]); MyTriangle_Vertex_Normal triangle = new MyTriangle_Vertex_Normal(); triangle.Vertexes.Vertex0 = meshTriangle.Vertex0; triangle.Vertexes.Vertex1 = meshTriangle.Vertex1; triangle.Vertexes.Vertex2 = meshTriangle.Vertex2; // skip too narrow triangles causing instability if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex1).LengthSquared() < MyPhysicsConfig.TriangleEpsilon) { continue; } if ((triangle.Vertexes.Vertex1 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon) { continue; } if ((triangle.Vertexes.Vertex0 - triangle.Vertexes.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon) { continue; } MyPlane plane = new MyPlane(ref triangle.Vertexes); Vector3?pt = MyUtils.GetSphereTriangleIntersection(ref newSphere, ref plane, ref triangle.Vertexes); if (pt == null) { continue; } Vector3 collisionN = plane.Normal; // skip triangle in case the normal is in wrong dir (narrow walls) Vector3 tempV = (newBody0Pos - pt.Value); if (Vector3.Dot(collisionN, tempV) >= 0.8f * tempV.Length()) // equivalent to dot(collisionN, normalize(tempV)) > 0.8f, but works for zero vectors { continue; } float depth = Vector3.Distance(pt.Value, body0Pos) - sphereRadius; if (numCollPts < MyPhysicsConfig.MaxContactPoints) { // since impulse get applied at the old position Vector3 p2 = pt.Value; collPtArray[numCollPts++] = new MySmallCollPointInfo(p2 - body0Pos, p2 - body1Pos, GetRigidBody1().LinearVelocity, GetRigidBody2().LinearVelocity, collisionN, depth, p2); } collNormal += collisionN; } } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } if (numCollPts > 0) { MyPhysics.physicsSystem.GetContactConstraintModule().AddContactConstraint(this, collPtArray, numCollPts); } MyContactInfoCache.FreeStackAlloc(collPtArray); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } return(false); }
protected override bool Interact(bool staticCollision) { if (RBElement1.GetElementType() != MyRBElementType.ET_BOX) { SwapElements(); } if (!staticCollision) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("BoxVoxelInteraction"); } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("Transformations"); MyRBBoxElement rbbox0 = (MyRBBoxElement)RBElement1; Matrix matrix0 = RBElement1.GetGlobalTransformation(); MyBox box = tempBox; box.Transform.Orientation = matrix0; box.Transform.Orientation.Translation = Vector3.Zero; box.Transform.Position = matrix0.Translation - Vector3.TransformNormal(rbbox0.Size * 0.5f, matrix0); box.SideLengths = rbbox0.Size; float boxRadius = box.GetBoundingRadiusAroundCentre(); #region boxCentre Vector3 boxCentre; box.GetCentre(out boxCentre); // Deano need to trasnform the box center into mesh space //Matrix invTransformMatrix = mesh.InverseTransformMatrix; //Vector3.Transform(ref boxCentre, ref invTransformMatrix, out boxCentre); #endregion BoundingBox bb = RBElement1.GetWorldSpaceAABB(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("GetPotentialTrianglesForColDet"); // extent bb for the movement int numTriangles; MyVoxelMaps.GetPotentialTrianglesForColDet(out numTriangles, ref bb); MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); if (staticCollision) { for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { MyColDetVoxelTriangle triangle = MyVoxelMaps.PotentialColDetTriangles[iTriangle]; // quick early test is done in mesh space float dist = triangle.Plane.DotCoordinate(boxCentre); if (dist > boxRadius) { continue; } // skip too narrow triangles causing destability if ((triangle.Vertex0 - triangle.Vertex1).LengthSquared() < MyPhysicsConfig.TriangleEpsilon || (triangle.Vertex1 - triangle.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon || (triangle.Vertex0 - triangle.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon ) { continue; } if (DoOverlapBoxTriangleStaticTest(box, ref triangle)) { return(true); } } } else { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("for DoOverlapBoxTriangleTest"); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { MyColDetVoxelTriangle triangle = MyVoxelMaps.PotentialColDetTriangles[iTriangle]; // skip too narrow triangles causing destability if ((triangle.Vertex0 - triangle.Vertex1).LengthSquared() < MyPhysicsConfig.TriangleEpsilon || (triangle.Vertex1 - triangle.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon || (triangle.Vertex0 - triangle.Vertex2).LengthSquared() < MyPhysicsConfig.TriangleEpsilon ) { continue; } DoOverlapBoxTriangleTest(box, ref triangle); } MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } if (!staticCollision) { MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock(); } return(false); }