예제 #1
0
        //  If explosion was with voxels, crease dirt decals in player's cockpit glass
        //  We don't throw random number of debris lines from explosion (because it will be waste). Instead we get intersection line from explosion center to player head,
        //  which should intersect the cockpit glass. Plus we move player head by random vector.
        void CreateDirtDecalOnCockpitGlass(ref BoundingSphere explosionSphere)
        {
            MySmallShip player      = MySession.PlayerShip;
            float       maxDistance = m_explosionSphere.Radius * MyExplosionsConstants.EXPLOSION_RADIUS_MULTPLIER_FOR_DIRT_GLASS_DECALS;
            float       distance    = Vector3.Distance(player.GetPosition(), explosionSphere.Center) - player.ModelLod0.BoundingSphere.Radius;

            //  Decal interpolator - based on distance to explosion, range <0..1>
            //  But then increased because we aren't able to reach max distance so we need to help it little bit
            float interpolator = 1 - MathHelper.Clamp(distance / maxDistance, 0, 1);

            interpolator = (float)Math.Pow(interpolator, 3f);

            //  Don't create dirt decal if we are too far
            if (interpolator <= 0.0f)
            {
                return;
            }

            //  Chech intersection between explosion and player's head. BUT move the line in player's head direction, because we don't want to make intersection with object which caused the explosion
            //MyLine line = new MyLine(intersection.IntersectionPointInWorldSpace, player.GetPosition(), true);
            //MyLine line = new MyLine(intersection.IntersectionPointInWorldSpace, MyCamera.m_initialSunWindPosition, true);
            //Vector3 playerHeadPositionWorld = MyUtils.GetTransform(MyFakes.PLAYER_HEAD_FOR_COCKPIT_INTERIOR_FAKE_TRANSLATION * -1, ref player.WorldMatrix);
            Vector3 playerHeadPositionWorld = player.GetPlayerHeadForCockpitInterior();
            MyLine  line = new MyLine(explosionSphere.Center, playerHeadPositionWorld, true);

            line.From += line.Direction * MyExplosionsConstants.OFFSET_LINE_FOR_DIRT_DECAL;

            MyIntersectionResultLineTriangleEx?glassIntersection = MyEntities.GetIntersectionWithLine_IgnoreOtherThanSpecifiedClass(ref line, new Type[] { typeof(MySmallShip) });

            if ((glassIntersection != null) && (glassIntersection.Value.Entity is MyCockpitGlassEntity))
            {
                //  Decal alpha (never is 1.0f, because we want to see through the dirt)
                float alpha = MathHelper.Clamp(MathHelper.Lerp(0.2f, 1.0f, interpolator) - 0.1f, 0, 1);
                //const float ALPHA_INCREASE = 0.4f;
                //float alpha = 1 - (float)Math.Pow(MathHelper.Clamp(distance / maxDistance, 0, 1), 5);
                //float alpha = (float)MathHelper.SmoothStep(0, 1, 1 - MathHelper.Clamp(distance / maxDistance, 0, 1));
                //float alpha = MathHelper.Clamp(1 - MathHelper.Clamp(distance / maxDistance, 0, 1) + ALPHA_INCREASE, ALPHA_INCREASE, 1);

                //  Decal size
                float size = MathHelper.Lerp(2.5f, 4f, interpolator);

                MyIntersectionResultLineTriangleEx glassIntersection2 = glassIntersection.Value;

                MyCockpitGlassDecals.Add(MyCockpitGlassDecalTexturesEnum.DirtOnGlass, size, MyMwcUtils.GetRandomRadian(), alpha, ref glassIntersection2, true);
            }
        }
예제 #2
0
        //  Update position, check collisions, etc.
        //  Return false if projectile dies/timeouts in this tick.
        public bool Update()
        {
            //  Projectile was killed , but still not last time drawn, so we don't need to do update (we are waiting for last draw)
            if (m_state == MyProjectileStateEnum.KILLED)
            {
                return(true);
            }

            //  Projectile was killed and last time drawn, so we can finally remove it from buffer
            if (m_state == MyProjectileStateEnum.KILLED_AND_DRAWN)
            {
                if (m_trailEffect != null)
                {
                    // stop the trail effect
                    m_trailEffect.Stop();
                    m_trailEffect = null;
                }

                return(false);
            }

            Vector3 position = m_position;

            m_position += m_velocity * MyConstants.PHYSICS_STEP_SIZE_IN_SECONDS;
            m_velocity  = m_externalVelocity * m_externalAddition + m_directionNormalized * m_speed;
            if (m_externalAddition < 1.0f)
            {
                m_externalAddition *= 0.5f;
            }

            //  Distance timeout
            float trajectoryLength = Vector3.Distance(m_position, m_origin);

            if (trajectoryLength >= m_maxTrajectory)
            {
                if (m_trailEffect != null)
                {
                    // stop the trail effect
                    m_trailEffect.Stop();
                    m_trailEffect = null;
                }

                m_state = MyProjectileStateEnum.KILLED;
                return(true);
            }

            if (m_trailEffect != null)
            {
                m_trailEffect.WorldMatrix = Matrix.CreateTranslation(m_position);
            }

            m_checkIntersectionIndex++;
            m_checkIntersectionIndex = m_checkIntersectionIndex % CHECK_INTERSECTION_INTERVAL;

            //check only each n-th intersection
            if (m_checkIntersectionIndex != 0)
            {
                return(true);
            }

            //  Calculate hit point, create decal and throw debris particles
            Vector3 lineEndPosition = position + CHECK_INTERSECTION_INTERVAL * (m_velocity * MyConstants.PHYSICS_STEP_SIZE_IN_SECONDS);

            MyLine line = new MyLine(m_positionChecked ? position : m_origin, lineEndPosition, true);

            m_positionChecked = true;

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("MyEntities.GetIntersectionWithLine()");
            MyIntersectionResultLineTriangleEx?intersection = MyEntities.GetIntersectionWithLine(ref line, m_ignorePhysObject, null, false);

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

            MyEntity physObject = intersection != null ? intersection.Value.Entity : null;

            if (physObject != null)
            {
                while (physObject.Physics == null && physObject.Parent != null)
                {
                    physObject = physObject.Parent;
                }
            }

            if ((intersection != null) && (physObject != null) && (physObject.Physics.CollisionLayer != MyConstants.COLLISION_LAYER_UNCOLLIDABLE) && m_ignorePhysObject != physObject)
            {
                MyIntersectionResultLineTriangleEx intersectionValue = intersection.Value;

                bool isPlayerShip = MySession.PlayerShip == physObject;

                MyMaterialType materialType = isPlayerShip ? MyMaterialType.PLAYERSHIP : physObject.Physics.MaterialType;

                //material properties
                MyMaterialTypeProperties materialProperties = MyMaterialsConstants.GetMaterialProperties(materialType);

                bool isProjectileGroupKilled = false;

                if (m_sharedGroup != null)
                {
                    isProjectileGroupKilled = m_sharedGroup.Killed;
                    m_sharedGroup.Killed    = true;
                }

                if (!isProjectileGroupKilled)
                {
                    //  Play bullet hit cue
                    MyAudio.AddCue3D(m_ammoProperties.IsExplosive ? materialProperties.ExpBulletHitCue : materialProperties.BulletHitCue, intersectionValue.IntersectionPointInWorldSpace, Vector3.Zero, Vector3.Zero, Vector3.Zero);
                }

                float decalAngle = MyMwcUtils.GetRandomRadian();

                //  If we hit the glass of a miner ship, we need to create special bullet hole decals
                //  drawn from inside the cockpit and change phys object so rest of the code will think we hit the parent
                //  IMPORTANT: Intersection between projectile and glass is calculated only for mining ship in which player sits. So for enemies this will be never calculated.
                if (intersection.Value.Entity is MyCockpitGlassEntity)
                {
                    if (!isProjectileGroupKilled)
                    {
                        MyCockpitGlassDecalTexturesEnum bulletHoleDecalTexture;
                        float bulletHoleDecalSize;

                        if (MyMwcUtils.GetRandomBool(3))
                        {
                            bulletHoleDecalTexture = MyCockpitGlassDecalTexturesEnum.BulletHoleOnGlass;
                            bulletHoleDecalSize    = 0.25f;
                        }
                        else
                        {
                            bulletHoleDecalTexture = MyCockpitGlassDecalTexturesEnum.BulletHoleSmallOnGlass;
                            bulletHoleDecalSize    = 0.1f;
                        }

                        //  Place bullet hole decal on player's cockpit glass (seen from inside the ship)
                        MyCockpitGlassDecals.Add(bulletHoleDecalTexture, bulletHoleDecalSize, decalAngle, 1.0f, ref intersectionValue, false);

                        //  Create hit particles throwed into the cockpit (it's simulation of broken glass particles)
                        //  IMPORTANT: This particles will be relative to miner ship, so we create them in object space coordinates and update them by object WorldMatrix every time we draw them
                        //MyParticleEffects.CreateHitParticlesGlass(ref intersectionValue.IntersectionPointInObjectSpace, ref intersectionValue.NormalInWorldSpace, ref line.Direction, physObject.Parent);
                    }
                }

                //  If this was "mine", it must explode
                else if (physObject is MyMineBase)
                {
                    m_state = MyProjectileStateEnum.KILLED;
                    if (!IsDummy)
                    {
                        (physObject as MyAmmoBase).Explode();
                    }
                    return(true);
                }

                //  If this was missile, cannon shot, it must explode if it is not mine missile
                else if (physObject is MyAmmoBase)
                {
                    if (((MyAmmoBase)physObject).OwnerEntity == m_ignorePhysObject)
                    {
                        m_state = MyProjectileStateEnum.KILLED;
                        if (!IsDummy)
                        {
                            (physObject as MyAmmoBase).Explode();
                        }
                        return(true);
                    }
                }

                else if (this.OwnerEntity is MySmallShip && (MySmallShip)this.OwnerEntity == MySession.PlayerShip && physObject is MyStaticAsteroid && !physObject.IsDestructible)
                {
                    if (this.m_ammoProperties.IsExplosive || (this.m_ammoProperties.AmmoType == MyAmmoType.Explosive && this.m_weapon is Weapons.MyShotGun))
                    {
                        HUD.MyHud.ShowIndestructableAsteroidNotification();
                    }
                }

                else if (!isProjectileGroupKilled && !isPlayerShip)
                {
                    //  Create smoke and debris particle at the place of voxel/model hit
                    m_ammoProperties.OnHitParticles(ref intersectionValue.IntersectionPointInWorldSpace, ref intersectionValue.Triangle.InputTriangleNormal, ref line.Direction, physObject, m_weapon, OwnerEntity);

                    MySurfaceImpactEnum surfaceImpact;
                    if (intersectionValue.Entity is MyVoxelMap)
                    {
                        var voxelMap   = intersectionValue.Entity as MyVoxelMap;
                        var voxelCoord = voxelMap.GetVoxelCenterCoordinateFromMeters(ref intersectionValue.IntersectionPointInWorldSpace);
                        var material   = voxelMap.GetVoxelMaterial(ref voxelCoord);
                        if (material == MyMwcVoxelMaterialsEnum.Indestructible_01 ||
                            material == MyMwcVoxelMaterialsEnum.Indestructible_02 ||
                            material == MyMwcVoxelMaterialsEnum.Indestructible_03 ||
                            material == MyMwcVoxelMaterialsEnum.Indestructible_04 ||
                            material == MyMwcVoxelMaterialsEnum.Indestructible_05_Craters_01)
                        {
                            surfaceImpact = MySurfaceImpactEnum.INDESTRUCTIBLE;
                        }
                        else
                        {
                            surfaceImpact = MySurfaceImpactEnum.DESTRUCTIBLE;
                        }
                    }
                    else if (intersectionValue.Entity is MyStaticAsteroid)
                    {
                        surfaceImpact = MySurfaceImpactEnum.INDESTRUCTIBLE;
                    }
                    else
                    {
                        surfaceImpact = MySurfaceImpactEnum.METAL;
                    }

                    m_ammoProperties.OnHitMaterialSpecificParticles(ref intersectionValue.IntersectionPointInWorldSpace, ref intersectionValue.Triangle.InputTriangleNormal, ref line.Direction, physObject, surfaceImpact, m_weapon);
                }

                if (!(physObject is MyExplosionDebrisBase) && physObject != MySession.PlayerShip)
                {
                    //  Decal size depends on material. But for mining ship create smaller decal as original size looks to large on the ship.
                    float decalSize = MyMwcUtils.GetRandomFloat(materialProperties.BulletHoleSizeMin,
                                                                materialProperties.BulletHoleSizeMax);

                    //  Place bullet hole decal
                    float randomColor = MyMwcUtils.GetRandomFloat(0.5f, 1.0f);

                    MyDecals.Add(
                        materialProperties.BulletHoleDecal,
                        decalSize,
                        decalAngle,
                        new Vector4(randomColor, randomColor, randomColor, 1),
                        false,
                        ref intersectionValue,
                        0.0f,
                        m_ammoProperties.DecalEmissivity, MyDecalsConstants.DECAL_OFFSET_BY_NORMAL);
                }

                if (!(physObject is MyVoxelMap) && !IsDummy)
                {
                    ApplyProjectileForce(physObject, intersectionValue.IntersectionPointInWorldSpace, m_directionNormalized, isPlayerShip);
                }


                //  If this object is miner ship, then shake his head little bit
                if (physObject is MySmallShip && !IsDummy)
                {
                    MySmallShip minerShip = (MySmallShip)physObject;
                    minerShip.IncreaseHeadShake(MyHeadShakeConstants.HEAD_SHAKE_AMOUNT_AFTER_PROJECTILE_HIT);
                }



                //Handle damage

                MyEntity damagedObject = intersectionValue.Entity;

                // not a very nice way to damage actual prefab associated with the large ship weapon (if MyPrefabLargeWeapon is reworked, it might change)
                if (damagedObject is MyLargeShipBarrelBase)
                {
                    damagedObject = damagedObject.Parent;
                }
                if (damagedObject is MyLargeShipGunBase)
                {
                    MyLargeShipGunBase physObj = damagedObject as MyLargeShipGunBase;
                    if (physObj.PrefabParent != null)
                    {
                        damagedObject = physObj.PrefabParent;
                    }
                }

                //  Decrease health of stricken object
                if (!IsDummy)
                {
                    damagedObject.DoDamage(m_ammoProperties.HealthDamage, m_ammoProperties.ShipDamage, m_ammoProperties.EMPDamage, m_ammoProperties.DamageType, m_ammoProperties.AmmoType, m_ignorePhysObject);
                    if (MyMultiplayerGameplay.IsRunning)
                    {
                        var ammo = MyAmmoConstants.FindAmmo(m_ammoProperties);
                        MyMultiplayerGameplay.Static.ProjectileHit(damagedObject, intersectionValue.IntersectionPointInWorldSpace, this.m_directionNormalized, ammo, this.OwnerEntity);
                    }
                }

                if (m_trailEffect != null)
                {
                    // stop the trail effect
                    m_trailEffect.Stop();
                    m_trailEffect = null;
                }

                //  Kill this projectile (set the position to intersection point, so we draw trail polyline only up to this point)
                m_position = intersectionValue.IntersectionPointInWorldSpace;
                m_state    = MyProjectileStateEnum.KILLED;

                return(true);
            }

            return(true);
        }