Пример #1
0
        public ProjectileTracer(Device device, Ray hitRay, IOrderedEnumerable <CollisionModelHit> orderedHits, TestShellInfo testShell)
        {
            Log.Info("new projectile tracer");

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

            _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);
        }
Пример #2
0
        public void Refresh(TestShellInfo testShell)
        {
            Log.Info("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.Value != 0.0)
                {
                    mayRicochet = mayRicochet && hit.Armor.MayRicochet;

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

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

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

                        thisImpactAngle -= thisNomarlizationAngle;
                    }

                    if (!heatExploded)
                    {
                        equivalentThickness += (float)(hit.Armor.Value / 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.Value / 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.Value;
                    }
                    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.Value / attenuation);

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



                if (!hit.Armor.IsSpacingArmor)
                {
                    penetrationState = PenetrationState.Penetratable;
                    break;
                }
                if (testShell.ShellType == ShellType.HE || testShell.ShellType == ShellType.PremiumHE)
                {
                    penetrationState = PenetrationState.Unpenetratable;
                    break;
                }
                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();
        }
Пример #3
0
        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.Value != 0.0)
                {
                    mayRicochet = mayRicochet && hit.Armor.MayRicochet;

                    double thisNomarlizationAngle = testShell.ShellType.BasicNormalization();

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

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

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

                        thisImpactAngle -= thisNomarlizationAngle;

                        nomarlizationAngle = thisNomarlizationAngle;
                    }

                    if (!heatExploded)
                    {
                        equivalentThickness += hit.Armor.Value / 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.Value / attenuation / Math.Cos(DxUtils.ConvertDegreesToRadians(thisImpactAngle));
                    }
                }
                else
                {
                    if (!heatExploded)
                    {
                        equivalentThickness += hit.Armor.Value;
                    }
                    else
                    {
                        var distance = (hit.Distance - heatExplodedDistance);

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

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

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

                    break;
                }
                if (testShell.ShellType == ShellType.He || testShell.ShellType == ShellType.PremiumHe)
                {
                    penetrationState = PenetrationState.Unpenetratable;
                    break;
                }
                if (testShell.ShellType == ShellType.Heat && isFirstHit)
                {
                    heatExploded         = true;
                    heatExplodedDistance = hit.Distance;
                    mayRicochet          = false;
                }
                isFirstHit = false;
            }
            return(new ShootTestResult(penetrationState, equivalentThickness, impactAngle, nomarlizationAngle, is2X, is3X));
        }