Пример #1
0
            /// <summary>
            /// This will figure how much velocity to apply to each bodyCenter
            /// TODO: Also calculate angular velocities
            /// </summary>
            /// <param name="bodyCenters">The bodies to apply velocity to</param>
            /// <param name="hitStart">The point of impact</param>
            /// <param name="hitDirection">The direction and force of the impact</param>
            /// <param name="mainBodyRadius">The avg radius of the body that is getting blown apart</param>
            private static Vector3D[] DistributeForces(Point3D[] bodyCenters, Point3D hitStart, Vector3D hitDirection, double mainBodyRadius, ExplosionForceOptions options)
            {
                Vector3D hitDirectionUnit = hitDirection.ToUnit();
                double hitForceBase = hitDirection.Length / mainBodyRadius;

                var vectors = bodyCenters.
                    Select(o =>
                    {
                        Vector3D direction = o - hitStart;
                        Vector3D directionUnit = direction.ToUnit();

                        double distance = direction.Length;
                        double scaledDistance = distance;
                        if (options.DistanceDot_Power != null)
                        {
                            double linearDot = Math3D.GetLinearDotProduct(hitDirectionUnit, directionUnit);     // making it linear so the power function is more predictable

                            // Exaggerate the distance based on dot product.  That way, points in line with the hit will get more of the impact
                            double scale = (1 - Math.Abs(linearDot));
                            scale = Math.Pow(scale, options.DistanceDot_Power.Value);
                            scaledDistance = scale * distance;
                        }

                        return new
                        {
                            ForcePoint = o,
                            Distance = distance,
                            ScaledDistance = scaledDistance,
                            DirectionUnit = directionUnit,
                        };
                    }).
                    ToArray();

                double[] percents = GetPercentOfProjForce(vectors.Select(o => o.ScaledDistance).ToArray());

                Vector3D[] retVal = new Vector3D[vectors.Length];

                for (int cntr = 0; cntr < vectors.Length; cntr++)
                {
                    retVal[cntr] = vectors[cntr].DirectionUnit * (hitForceBase * percents[cntr]);
                }

                return retVal;
            }
Пример #2
0
            private static Vector3D[] CalculateVelocites(Point3D[] centers, ShotHit[] hits, double hullRadius, ExplosionForceOptions options)
            {
                Vector3D[] retVal = new Vector3D[centers.Length];

                foreach (var hit in hits)
                {
                    Point3D shotStart = hit.Hit.Item1;
                    if (options.InteriorVelocityCenterPercent != null)
                    {
                        shotStart += ((hit.Hit.Item2 - hit.Hit.Item1) * options.InteriorVelocityCenterPercent.Value);
                    }

                    Vector3D[] velocities = DistributeForces(centers, shotStart, hit.Shot.Item2 * (hit.Shot.Item3 * options.ShotMultiplier), hullRadius, options);

                    for (int cntr = 0; cntr < retVal.Length; cntr++)
                    {
                        retVal[cntr] += velocities[cntr];
                    }
                }

                return retVal;
            }
Пример #3
0
            private static Tuple<ExplosionForceResponse, bool> SplitHull(ITriangleIndexed[] convexHull, Tuple<Point3D, Vector3D, double>[] shots, ExplosionForceOptions options)
            {
                #region intersect with the hull

                var hits = shots.
                    Select(o => new ShotHit()
                    {
                        Shot = o,
                        Hit = GetHit(convexHull, o.Item1, o.Item2, o.Item3),
                    }).
                    Where(o => o.Hit != null).
                    ToArray();

                if (hits.Length == 0)
                {
                    return null;
                }

                #endregion

                #region voronoi

                Point3D[] controlPoints = GetVoronoiCtrlPoints(hits, convexHull);

                VoronoiResult3D voronoi = Math3D.GetVoronoi(controlPoints, true);
                if (voronoi == null)
                {
                    return null;
                }

                #endregion

                // There is enough to start populating the response
                ExplosionForceResponse retVal = new ExplosionForceResponse()
                {
                    Hits = hits,
                    ControlPoints = controlPoints,
                    Voronoi = voronoi,
                };

                #region intersect voronoi and hull

                // Intersect
                Tuple<int, ITriangleIndexed[]>[] shards = null;
                try
                {
                    shards = Math3D.GetIntersection_Hull_Voronoi_full(convexHull, voronoi);
                }
                catch (Exception)
                {
                    return Tuple.Create(retVal, false);
                }

                if (shards == null)
                {
                    return Tuple.Create(retVal, false);
                }

                // Smooth
                if (options.ShouldSmoothShards)
                {
                    shards = shards.
                        Select(o => Tuple.Create(o.Item1, Asteroid.SmoothTriangles(o.Item2))).
                        ToArray();
                }

                // Validate
                shards = shards.
                        Where(o => o.Item2 != null && o.Item2.Length >= 3).
                        Where(o =>
                        {
                            Vector3D firstNormal = o.Item2[0].NormalUnit;
                            return o.Item2.Skip(1).Any(p => !Math.Abs(Vector3D.DotProduct(firstNormal, p.NormalUnit)).IsNearValue(1));
                        }).
                        ToArray();

                if (shards.Length == 0)
                {
                    return Tuple.Create(retVal, false);
                }

                #endregion

                #region populate shards

                retVal.Shards = shards.
                    Select(o =>
                        {
                            var aabb = Math3D.GetAABB(o.Item2);

                            double radius = Math.Sqrt((aabb.Item2 - aabb.Item1).Length / 2);

                            Point3D center = Math3D.GetCenter(TriangleIndexed.GetUsedPoints(o.Item2));
                            Vector3D centerVect = center.ToVector();

                            Point3D[] allPoints = o.Item2[0].AllPoints.
                                Select(p => p - centerVect).
                                ToArray();

                            TriangleIndexed[] shiftedTriangles = o.Item2.
                                Select(p => new TriangleIndexed(p.Index0, p.Index1, p.Index2, allPoints)).
                                ToArray();

                            return new ExplosionForceShard()
                           {
                               VoronoiControlPointIndex = o.Item1,
                               Hull_ParentCoords = o.Item2,
                               Hull_Centered = shiftedTriangles,
                               Radius = radius,
                               Center_ParentCoords = center,
                           };
                        }).
                    ToArray();

                #endregion

                return Tuple.Create(retVal, true);
            }
Пример #4
0
            private static Vector3D[] GetVelocities(ExplosionForceShard[] hullShards, ShotHit[] hits, double hullRadius, ExplosionForceOptions options)
            {
                //TODO: When the asteroid shards aren't resmoothed, the velocities are very small
                //
                //Maybe add more orth velocity
                //
                //Maybe pull the hit source slightly into the asteroid --- done
                //
                //Maybe add some random velocity (size proportional to the velocity) --- done

                Vector3D[] retVal = CalculateVelocites(hullShards.Select(o => o.Center_ParentCoords).ToArray(), hits, hullRadius, options);

                if (options.RandomVelocityPercent != null)
                {
                    retVal = retVal.
                        Select(o => o + Math3D.GetRandomVector_Spherical(o.Length * options.RandomVelocityPercent.Value)).
                        ToArray();
                }

                return retVal;
            }
Пример #5
0
            public static ExplosionForceResponse ShootHull(ITriangleIndexed[] convexHull, Tuple<Point3D, Vector3D, double>[] shots, ExplosionForceOptions options = null)
            {
                options = options ?? new ExplosionForceOptions();

                // Create a voronoi, and intersect with the hull
                var retVal = SplitHull(convexHull, shots, options);
                if (retVal == null) return null;
                else if (!retVal.Item2) return retVal.Item1;

                // Figure out velocities
                var aabb = Math3D.GetAABB(convexHull);
                retVal.Item1.Velocities = GetVelocities(retVal.Item1.Shards, retVal.Item1.Hits, Math.Sqrt((aabb.Item2 - aabb.Item1).Length / 2), options);

                return retVal.Item1;
            }