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(); } }
/// <summary> /// Updates resource. /// </summary> public override void UpdateBeforeSimulation() { try { MyRender.GetRenderProfiler().StartProfilingBlock("MyMissile.UpdateBeforeSimulation"); //Large ship weapons wont make bots curious if ((!(OwnerEntity is MyLargeShipMissileLauncherBarrel)) && MyMwcUtils.HasValidLength(this.WorldMatrix.Translation - m_previousPosition)) { MyLine line = new MyLine(this.WorldMatrix.Translation, m_previousPosition); MyDangerZones.Instance.Notify(line, OwnerEntity); } if (m_isExploded) { // Create explosion MyExplosion newExplosion = MyExplosions.AddExplosion(); if (newExplosion != null) { float radius = m_ammoProperties.ExplosionRadius; // Explicitly on Marek's request (ticket 4740) bool amplifyRadius = m_collidedEntity != null?MyFactions.GetFactionsRelation(m_collidedEntity.Faction, Faction) != MyFactionRelationEnum.Friend : false; if (amplifyRadius) { radius *= 2; } BoundingSphere explosionSphere = new BoundingSphere(m_collisionPoint.HasValue ? m_collisionPoint.Value : GetPosition(), radius); // Call main explosion starter MyExplosionInfo info = new MyExplosionInfo() { PlayerDamage = m_ammoProperties.HealthDamage, Damage = m_ammoProperties.ShipDamage, EmpDamage = m_ammoProperties.EMPDamage, ExplosionType = m_explosionType, ExplosionSphere = explosionSphere, LifespanMiliseconds = MyExplosionsConstants.EXPLOSION_LIFESPAN, ExplosionForceDirection = MyExplosionForceDirection.EXPLOSION, GroupMask = Physics.GroupMask, CascadeLevel = CascadedExplosionLevel, HitEntity = m_collidedEntity, ParticleScale = 1.5f, OwnerEntity = this.OwnerEntity, Direction = WorldMatrix.Forward, VoxelExplosionCenter = explosionSphere.Center + m_ammoProperties.ExplosionRadius * WorldMatrix.Forward * 0.5f, ExplosionFlags = MyExplosionFlags.AFFECT_VOXELS | MyExplosionFlags.APPLY_FORCE_AND_DAMAGE | MyExplosionFlags.CREATE_DEBRIS | MyExplosionFlags.CREATE_DECALS | MyExplosionFlags.CREATE_PARTICLE_EFFECT, VoxelCutoutScale = amplifyRadius ? 0.5f : 1.0f, PlaySound = true, }; 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()); m_collidedEntity.OnClose -= m_collidedEntity_OnClose; } MarkForClose(); return; } bool firstTargetting = m_elapsedMiliseconds == 0; base.UpdateBeforeSimulation(); m_missileTargetUpdate += MyConstants.PHYSICS_STEP_SIZE_IN_MILLISECONDS; if (m_missileTargetUpdate >= MyGuidedMissileConstants.MISSILE_TARGET_UPDATE_INTERVAL_IN_MS || firstTargetting) { m_missileTargetUpdate = 0; switch (m_missileType) { case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Guided_Missile_Radar_Detection: { MySmallShip targetShip = m_targetEntity as MySmallShip; if (targetShip != null && targetShip.IsRadarJammed()) { m_targetEntity = null; } } break; case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Guided_Missile_Engine_Detection: { m_targetEntities.Clear(); Matrix proj = Matrix.CreateOrthographic(MyGuidedMissileConstants.ENGINE_GUIDED_MISSILE_RADIUS, MyGuidedMissileConstants.ENGINE_GUIDED_MISSILE_RADIUS, 0, 1000); Matrix view = Matrix.CreateLookAt(GetPosition(), GetPosition() + WorldMatrix.Forward, WorldMatrix.Up); m_visualFrustum.Matrix = view * proj; MyEntities.GetAllIntersectionWithBoundingFrustum(ref m_visualFrustum, m_targetEntities); if (m_targetEntities.Contains(m_targetEntity)) { break; } MyEntity target = null; float closestToMissileDirection = float.MaxValue; foreach (MyEntity entity in m_targetEntities) { if (CanTarget(entity)) { MySmallShip targetShip = entity as MySmallShip; if (targetShip != null) { if ((targetShip.IsEngineTurnedOff())) { continue; } } Vector3 targetPos = entity.GetPosition(); Vector3 missilePos = this.GetPosition(); Vector3 missilePosEnd = this.GetPosition() + this.WorldMatrix.Forward * 10000; Vector3 closestPos = MyUtils.GetClosestPointOnLine(ref missilePos, ref missilePosEnd, ref targetPos); float distance = Vector3.Distance(closestPos, targetPos); if (distance < closestToMissileDirection) { closestToMissileDirection = distance; target = entity; } } } UpdateTarget(target); } break; case MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Guided_Missile_Visual_Detection: { Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(MyGuidedMissileConstants.VISUAL_GUIDED_MISSILE_FOV), 1, 10, MyGuidedMissileConstants.VISUAL_GUIDED_MISSILE_RANGE); m_visualFrustum.Matrix = Matrix.Invert(WorldMatrix) * projectionMatrix; m_targetEntities.Clear(); MyEntities.GetAllIntersectionWithBoundingFrustum(ref m_visualFrustum, m_targetEntities); int testsLimit = 8; if (m_targetEntities.Contains(m_targetEntity)) { break; } MyEntity target = null; //looks better if missile gets "lost" float closestToMissileDirection = float.MaxValue; foreach (MyEntity entity in m_targetEntities) { if (!CanTarget(entity)) { continue; } if (testsLimit-- == 0) { break; } if (MyEnemyTargeting.CanSee(this, entity) == null) { Vector3 targetPos = entity.GetPosition(); Vector3 missilePos = this.GetPosition(); Vector3 missilePosEnd = this.GetPosition() + this.WorldMatrix.Forward * 10000; Vector3 closestPos = MyUtils.GetClosestPointOnLine(ref missilePos, ref missilePosEnd, ref targetPos); float distance = Vector3.Distance(closestPos, targetPos); if (distance < closestToMissileDirection) { closestToMissileDirection = distance; target = entity; } } } UpdateTarget(target); } break; } } if ((m_initTime - m_elapsedMiliseconds) > 0) { //simulating missile launch and engine ignition MyEntity owner = OwnerEntity; if (owner != null) { Vector3 transformedInitDir = Vector3.TransformNormal(m_initDir, owner.WorldMatrix); // Vector3 initialVelocity = Vector3.Zero; if (owner.Physics != null) { initialVelocity = owner.Physics.LinearVelocity; } Physics.LinearVelocity = transformedInitDir * m_ammoProperties.InitialSpeed + initialVelocity; } } else { // This will help blend "initial velocity" and "thrust velocity" so at the beginning missile is powered by initiatal velocity only, but later float velocityBlend = MathHelper.Clamp((float)(m_elapsedMiliseconds - m_initTime) / m_blendVelocities, 0, 1); if (velocityBlend == 1.0f) { m_actualSpeed = m_ammoProperties.DesiredSpeed; } else { float initialSpeed = 0.0f; MyEntity owner = OwnerEntity; if (owner != null) { if (owner.Physics != null) { initialSpeed = owner.Physics.LinearVelocity.Length(); } } m_actualSpeed = velocityBlend * m_ammoProperties.DesiredSpeed + ((1.0f - velocityBlend) * (m_ammoProperties.InitialSpeed + initialSpeed)); if (m_missileType != MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Missile_Basic && m_smokeEffect == null) { // if (MyCamera.GetDistanceWithFOV(GetPosition()) < 150) { /* * MyParticleEffect startEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.Smoke_MissileStart); * startEffect.WorldMatrix = WorldMatrix; */ m_smokeEffect = MyParticlesManager.CreateParticleEffect((int)MyParticleEffectsIDEnum.Smoke_Missile); m_smokeEffect.WorldMatrix = WorldMatrix; m_smokeEffect.AutoDelete = false; } } } m_desiredVelocity = GetDesiredVelocity(m_targetEntity); Physics.LinearVelocity = m_desiredVelocity * m_actualSpeed * 1.0f; } Physics.AngularVelocity = Vector3.Zero; if ((m_elapsedMiliseconds > m_missileTimeout) || (Vector3.Distance(GetPosition(), m_origin) >= m_maxTrajectory)) { Explode(); return; } if (m_smokeEffect != null) { Matrix smokeMatrix = Matrix.CreateWorld(WorldMatrix.Translation - 0.5f * WorldMatrix.Forward, WorldMatrix.Forward, WorldMatrix.Up); m_smokeEffect.WorldMatrix = smokeMatrix; } if (m_targetEntity != null) { if (m_targetEntity.Physics != null) { m_targetVelocity = m_targetEntity.Physics.LinearVelocity; } else { m_targetVelocity = Vector3.Zero; } } } finally { MyRender.GetRenderProfiler().EndProfilingBlock(); } }