Пример #1
0
        public void Refresh(TestShellInfo testShell)
        {
            this.LogInfo("refresh");
            _tracerLines = new List <TracerLineVertex>();
            _tracerLines.Add(new TracerLineVertex()
            {
                Position = _tracerRay.Position, Penetration = 0
            });

            PenetrationState penetrationState = PenetrationState.NotApplicable;

            bool mayRicochet = true;

            float equivalentThickness  = 0.0f;
            float heatExplodedDistance = 0.0f;
            bool  heatExploded         = false;

            foreach (var hit in _orderedHits)
            {
                _hitMeshs.Add(hit.Mesh);

                if (!heatExploded)
                {
                    _tracerLines.Add(new TracerLineVertex()
                    {
                        Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness
                    });
                }

                var thisImpactAngle = DXUtils.ConvertRadiansToDegrees(Math.Acos(hit.InjectionCosine));

                if (hit.Armor.UseHitAngle && hit.Armor.Thickness != 0.0)
                {
                    mayRicochet = mayRicochet && hit.Armor.MayRicochet;

                    double thisNomarlizationAngle = testShell.ShellType.GetBaseNormalization();
                    if (testShell.Caliber >= hit.Armor.Thickness * 3.0)
                    {
                        mayRicochet             = false;
                        thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness;
                    }
                    else if (testShell.Caliber >= hit.Armor.Thickness * 2.0)
                    {
                        thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness;
                    }

                    if (mayRicochet && thisImpactAngle > testShell.ShellType.GetRicochetAngle())
                    {
                        penetrationState = PenetrationState.Richochet;
                        break;
                    }

                    if (testShell.ShellType.HasNormalizationEffect())
                    {
                        if (thisNomarlizationAngle > thisImpactAngle)
                        {
                            thisNomarlizationAngle = thisImpactAngle;
                        }

                        thisImpactAngle -= thisNomarlizationAngle;
                    }

                    if (!heatExploded)
                    {
                        equivalentThickness += (float)(hit.Armor.Thickness / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle)));
                    }
                    else
                    {
                        var distance = (hit.Distance - heatExplodedDistance);

                        var attenuation = 1 - distance * 0.5;
                        if (attenuation < 0)
                        {
                            _tracerLines.Add(new TracerLineVertex()
                            {
                                Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = 0
                            });
                            penetrationState = PenetrationState.Unpenetratable;
                            break;
                        }

                        equivalentThickness += (float)(hit.Armor.Thickness / attenuation / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle)));

                        _tracerLines.Add(new TracerLineVertex()
                        {
                            Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness
                        });
                    }
                }
                else
                {
                    if (!heatExploded)
                    {
                        equivalentThickness += (float)hit.Armor.Thickness;
                    }
                    else
                    {
                        var distance = (hit.Distance - heatExplodedDistance);

                        var attenuation = 1 - distance * 0.5;
                        if (attenuation < 0)
                        {
                            _tracerLines.Add(new TracerLineVertex()
                            {
                                Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = 0
                            });
                            penetrationState = PenetrationState.Unpenetratable;
                            break;
                        }

                        equivalentThickness += (float)(hit.Armor.Thickness / attenuation);

                        _tracerLines.Add(new TracerLineVertex()
                        {
                            Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness
                        });
                    }
                }



                if (!hit.Armor.IsSpacedArmor)
                {
                    penetrationState = PenetrationState.Penetratable;
                    break;
                }
                else
                {
                    if (testShell.ShellType == ShellType.HE || testShell.ShellType == ShellType.PremiumHE)
                    {
                        penetrationState = PenetrationState.Unpenetratable;
                        break;
                    }
                    else if (testShell.ShellType == ShellType.HEAT && !heatExploded)
                    {
                        heatExploded         = true;
                        heatExplodedDistance = hit.Distance;
                        mayRicochet          = false;
                    }
                }

                _tracerLines.Add(new TracerLineVertex()
                {
                    Position = _tracerRay.Position + hit.Distance * _tracerRay.Direction, Penetration = equivalentThickness
                });
            }


            if (penetrationState == PenetrationState.Penetratable)
            {
                for (int i = 0; i != _tracerLines.Count; ++i)
                {
                    _tracerLines[i] = new TracerLineVertex()
                    {
                        Position = _tracerLines[i].Position, Penetration = (equivalentThickness - _tracerLines[i].Penetration) * 0.5f
                    };
                }
            }
            else if (penetrationState == PenetrationState.Richochet ||
                     penetrationState == PenetrationState.Unpenetratable ||
                     penetrationState == PenetrationState.NotApplicable)
            {
                for (int i = 0; i != _tracerLines.Count; ++i)
                {
                    _tracerLines[i] = new TracerLineVertex()
                    {
                        Position = _tracerLines[i].Position, Penetration = -1.0f
                    };
                }
            }

            BuildCollision();
        }
        public ShootTestResult GetShootTestResult(TestShellInfo testShell)
        {
            PenetrationState penetrationState    = PenetrationState.NotApplicable;
            double           equivalentThickness = 0.0;
            double           impactAngle         = 0.0;
            double           nomarlizationAngle  = 0.0;
            bool             is2x        = false;
            bool             is3x        = false;
            bool             mayRicochet = true;

            bool   heatExploded         = false;
            double heatExplodedDistance = 0.0;

            bool isFirstHit  = true;
            var  orderedHits = Hits.OrderBy((h) => h.Distance);

            foreach (var hit in orderedHits)
            {
                var thisImpactAngle = DXUtils.ConvertRadiansToDegrees(Math.Acos(hit.InjectionCosine));

                if (isFirstHit)
                {
                    impactAngle = thisImpactAngle;
                }

                if (hit.Armor.UseHitAngle && hit.Armor.Thickness != 0.0)
                {
                    mayRicochet = mayRicochet && hit.Armor.MayRicochet;

                    double thisNomarlizationAngle = testShell.ShellType.GetBaseNormalization();

                    if (testShell.Caliber >= hit.Armor.Thickness * 3.0 && testShell.ShellType.HasNormalizationEffect())
                    {
                        is3x                    = true;
                        is2x                    = true;
                        mayRicochet             = false;
                        thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness;
                    }
                    else if (testShell.Caliber >= hit.Armor.Thickness * 2.0 && testShell.ShellType.HasNormalizationEffect())
                    {
                        is3x = false;
                        is2x = testShell.ShellType.HasNormalizationEffect();
                        thisNomarlizationAngle *= 1.4 * testShell.Caliber / hit.Armor.Thickness;
                    }

                    if (mayRicochet && thisImpactAngle > testShell.ShellType.GetRicochetAngle())
                    {
                        penetrationState = PenetrationState.Richochet;
                        break;
                    }

                    if (isFirstHit && testShell.ShellType.HasNormalizationEffect())
                    {
                        if (thisNomarlizationAngle > thisImpactAngle)
                        {
                            thisNomarlizationAngle = thisImpactAngle;
                        }

                        thisImpactAngle -= thisNomarlizationAngle;

                        nomarlizationAngle = thisNomarlizationAngle;
                    }

                    if (!heatExploded)
                    {
                        equivalentThickness += hit.Armor.Thickness / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle));
                    }
                    else
                    {
                        var distance = (hit.Distance - heatExplodedDistance);

                        var attenuation = 1 - distance * 0.5;
                        if (attenuation < 0)
                        {
                            penetrationState = PenetrationState.Unpenetratable;
                            break;
                        }

                        equivalentThickness += hit.Armor.Thickness / attenuation / Math.Cos(DXUtils.ConvertDegreesToRadians(thisImpactAngle));
                    }
                }
                else
                {
                    if (!heatExploded)
                    {
                        equivalentThickness += hit.Armor.Thickness;
                    }
                    else
                    {
                        var distance = (hit.Distance - heatExplodedDistance);

                        var attenuation = 1 - distance * 0.5;
                        if (attenuation < 0)
                        {
                            penetrationState = PenetrationState.Unpenetratable;
                            break;
                        }

                        equivalentThickness += hit.Armor.Thickness / attenuation;
                    }
                }

                if (!hit.Armor.IsSpacedArmor)
                {
                    if (equivalentThickness < 999.0)
                    {
                        penetrationState = PenetrationState.Penetratable;
                    }
                    else
                    {
                        penetrationState = PenetrationState.Unpenetratable;
                    }

                    break;
                }
                else
                {
                    if (testShell.ShellType == ShellType.HE || testShell.ShellType == ShellType.PremiumHE)
                    {
                        penetrationState = PenetrationState.Unpenetratable;
                        break;
                    }
                    else if (testShell.ShellType == ShellType.HEAT && isFirstHit)
                    {
                        heatExploded         = true;
                        heatExplodedDistance = hit.Distance;
                        mayRicochet          = false;
                    }
                }
                isFirstHit = false;
            }
            return(new ShootTestResult(penetrationState, equivalentThickness, impactAngle, nomarlizationAngle, is2x, is3x));
        }
Пример #3
0
        public ProjectileTracer(Device device, Ray hitRay, IOrderedEnumerable <CollisionModelHit> orderedHits, TestShellInfo testShell)
        {
            this.LogInfo("new projectile tracer");

            _tracerRay = hitRay;
            _hitMeshs  = new List <ModuleMesh>();

            _device            = device;
            _vertexDeclaration = new VertexDeclaration(_device, new[]
            {
                new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
                new VertexElement(0, 12, DeclarationType.Float1, DeclarationMethod.Default, DeclarationUsage.Color, 0),
                VertexElement.VertexDeclarationEnd,
            });

            _orderedHits = orderedHits;

            Refresh(testShell);
        }