コード例 #1
0
ファイル: Asteroid.cs プロジェクト: charlierix/AsteroidMiner
            private AsteroidOrMineralDefinition[] DetermineDestroyedChildrenMinerals(HullVoronoiExploder_Response shards, double overDamage, Vector3D parentRadius, double minChildRadius, Func<double, ITriangleIndexed[], double> getMassByRadius, Func<double, MineralDNA[]> getMineralsByDestroyedMass)
            {
                const double MAXOVERDMG = 13;       // overdamage of 1 is the smallest value (the asteroid was barely destroyed).  Larger values are overkill, and the asteroid becomes more fully destroyed

                if (shards == null || shards.Shards == null || shards.Shards.Length == 0)
                {
                    // There was problem, so just pop out some minerals
                    return DetermineDestroyedChildrenMinerals_Minerals(parentRadius, getMassByRadius, getMineralsByDestroyedMass);
                }

                Random rand = StaticRandom.GetRandomForThread();

                #region calculate volumes

                var shardVolumes = shards.Shards.
                    Select(o =>
                        {
                            Vector3D radius = GetEllipsoidRadius(o.Hull_Centered);
                            return new { Radius = radius, Volume = GetEllipsoidVolume(radius) };
                        }).
                    ToArray();

                // Figure out how much volume should permanently be destroyed
                double parentVolume = GetEllipsoidVolume(parentRadius);
                double volumeToDestroy = GetVolumeToDestroy(parentVolume, overDamage, MAXOVERDMG);

                #endregion

                double destroyedVolume = 0;
                bool[] shouldSelfDestruct = new bool[shards.Shards.Length];

                #region detect too small

                // Get rid of any that are too small
                //TODO: Also get rid of any that are too thin
                for (int cntr = 0; cntr < shards.Shards.Length; cntr++)
                {
                    if (shards.Shards[cntr].Radius < minChildRadius)
                    {
                        shouldSelfDestruct[cntr] = true;
                        destroyedVolume += shardVolumes[cntr].Volume;
                    }
                }

                #endregion

                if (destroyedVolume < volumeToDestroy)
                {
                    #region remove more

                    // Find the shards that could be removed
                    var candidates = Enumerable.Range(0, shards.Shards.Length).
                        Select(o => new
                        {
                            Index = o,
                            Shard = shards.Shards[o],
                            Volume = shardVolumes[o]
                        }).
                        Where(o => !shouldSelfDestruct[o.Index] && o.Volume.Volume < volumeToDestroy - destroyedVolume).
                        OrderBy(o => o.Volume.Volume).
                        ToList();

                    while (candidates.Count > 0 && destroyedVolume < volumeToDestroy)
                    {
                        // Figure out which to self destruct (the rand power will favor inicies closer to zero)
                        int index = UtilityCore.GetIndexIntoList(rand.NextPow(2), candidates.Count);

                        // Remove it
                        shouldSelfDestruct[candidates[index].Index] = true;
                        destroyedVolume += candidates[index].Volume.Volume;
                        candidates.RemoveAt(index);

                        // Remove the items at the end that are now too large
                        index = candidates.Count - 1;
                        while (index >= 0)
                        {
                            if (candidates[index].Volume.Volume < volumeToDestroy - destroyedVolume)
                            {
                                break;      // it's sorted, so the rest will also be under
                            }
                            else
                            {
                                candidates.RemoveAt(index);
                                index--;
                            }
                        }
                    }

                    #endregion
                }

                #region distribute minerals

                // Figure out the mineral value of the destroyed volume
                MineralDNA[] mineralDefinitions = null;
                if (destroyedVolume > 0 && getMineralsByDestroyedMass != null)
                {
                    double inferredRadius = GetEllipsoidRadius(destroyedVolume);
                    double destroyedMass = getMassByRadius(inferredRadius, null);

                    if (destroyedMass > 0)
                    {
                        mineralDefinitions = getMineralsByDestroyedMass(destroyedMass);
                    }
                }

                // Figure out which of the temp asteroids should contain minerals
                var packedMinerals = new Tuple<int, MineralDNA[]>[0];

                if (mineralDefinitions != null && mineralDefinitions.Length > 0)
                {
                    int[] destroyedIndicies = Enumerable.Range(0, shouldSelfDestruct.Length).
                        Where(o => shouldSelfDestruct[o]).
                        ToArray();

                    packedMinerals = DistributeMinerals(mineralDefinitions, destroyedIndicies);
                }

                #endregion

                #region final array

                AsteroidOrMineralDefinition[] retVal = new AsteroidOrMineralDefinition[shards.Shards.Length];

                for (int cntr = 0; cntr < retVal.Length; cntr++)
                {
                    Vector3D velocity = new Vector3D(0, 0, 0);
                    if (shards.Velocities != null && shards.Velocities.Length == shards.Shards.Length)
                    {
                        velocity = shards.Velocities[cntr];
                    }

                    //NOTE: Only position is needed (The first attempt created random asteroids and pulled them apart.  This second attempt
                    //doesn't need to pull them apart)
                    PartSeparator_Part part = new PartSeparator_Part(new[] { new Point3D() }, 0, shards.Shards[cntr].Center_ParentCoords, Quaternion.Identity);

                    //MineralDNA[] mineralsAfter = packedMinerals?.FirstOrDefault(o => o.Item1 == cntr)?.Item2;
                    MineralDNA[] mineralsAfter = null;
                    if (packedMinerals != null)
                    {
                        var found = packedMinerals.FirstOrDefault(o => o.Item1 == cntr);
                        if (found != null)
                        {
                            mineralsAfter = found.Item2;
                        }
                    }

                    retVal[cntr] = new AsteroidOrMineralDefinition(part, shards.Shards[cntr].Hull_Centered, shards.Shards[cntr].Radius, velocity, shouldSelfDestruct[cntr], mineralsAfter);
                }

                #endregion

                return retVal;
            }
コード例 #2
0
ファイル: Asteroid.cs プロジェクト: charlierix/AsteroidMiner
            private IMapObject[] ConvertToMapObjects(AsteroidOrMineralDefinition[] items, Point3D parentPos, Vector3D parentVel, Quaternion parentRot)
            {
                IMapObject[] retVal = new IMapObject[items.Length];

                RotateTransform3D rotate = new RotateTransform3D(new QuaternionRotation3D(parentRot));

                for (int cntr = 0; cntr < retVal.Length; cntr++)
                {
                    Point3D position = parentPos + rotate.Transform(items[cntr].Part.Position.ToVector());

                    if (items[cntr].IsAsteroid)
                    {
                        // Asteroid
                        AsteroidExtra extra = new AsteroidExtra()
                        {
                            Triangles = TriangleIndexed.Clone_Transformed(items[cntr].AsteroidTriangles, rotate),
                            GetMineralsByDestroyedMass = _getMineralsByDestroyedMass,
                            MineralMaterialID = _mineralMaterialID,
                            MinChildRadius = _minChildRadius,
                            RandomRotation = false,
                            SelfDestructAfterElapse = items[cntr].ShouldAsteroidSelfDestruct ? StaticRandom.NextPercent(SELFDESTRUCTTIME, .5) : (double?)null,
                            MineralsWhenSelfDestruct = items[cntr].MineralsAfterSelfDestruct,
                        };

                        retVal[cntr] = new Asteroid(items[cntr].AsteroidRadius, _getMassByRadius, position, _world, _map, _materialID, extra);
                    }
                    else
                    {
                        // Mineral
                        MineralDNA mindef = items[cntr].MineralDefinition;
                        double densityMult = mindef.Density / Mineral.GetSettingsForMineralType(mindef.MineralType).Density;
                        retVal[cntr] = new Mineral(mindef.MineralType, position, mindef.Volume, _world, _mineralMaterialID, _sharedVisuals.Value, densityMult, mindef.Scale);
                    }

                    retVal[cntr].PhysicsBody.Velocity = parentVel + rotate.Transform(items[cntr].Velocity);

                    // Need to be careful if setting this.  Too much, and it will come apart unnaturally
                    //retVal[cntr].PhysicsBody.AngularVelocity = ;
                }

                return retVal;
            }