// Mineral public AsteroidOrMineralDefinition(PartSeparator_Part part, MineralDNA mineralDefinition) { this.IsAsteroid = false; this.Part = part; this.MineralDefinition = mineralDefinition; this.AsteroidTriangles = null; this.AsteroidRadius = 0; }
public Inventory(MineralDNA mineral) { this.Ship = null; this.Part = null; this.Mineral = mineral; this.Count = 1; this.Volume = mineral.Volume; this.Mass = mineral.Density * mineral.Volume; this.Token = TokenGenerator.NextToken(); }
private ChangeInstruction(Point3D add_Position, Vector3D add_Velocity, Vector3D add_AngVel, AsteroidDNA asteroid, MineralDNA mineral, Asteroid[] remove_Asteroids, Mineral[] remove_Minerals) { this.InstructionType = MapPopulationManager.InstructionType.Merge; this.Add_Position = add_Position; this.Add_Velocity = add_Velocity; this.Add_AngVel = add_AngVel; this.Asteroid = asteroid; this.Mineral = mineral; this.Remove_Asteroids = remove_Asteroids; this.Remove_Minerals = remove_Minerals; }
public ChangeInstruction(Point3D add_Position, Vector3D add_Velocity, Vector3D add_AngVel, MineralDNA mineral, Mineral[] remove_Minerals) : this(add_Position, add_Velocity, add_AngVel, null, mineral, null, remove_Minerals) { }
private static Tuple<int, MineralDNA[]>[] DistributeMinerals(MineralDNA[] mineralDefinitions, int[] destroyedIndicies) { // I was going to keep track of burdens, and assign each mineral to the least burdened shard, with some // randomness. But that would be a lot of sorting and divisions and resorting // // There won't be enough minerals or destroyed shards to make all that effort worthwhile // // So instead, just randomly assigning them Random rand = StaticRandom.GetRandomForThread(); List<MineralDNA>[] building = Enumerable.Range(0, destroyedIndicies.Length). Select(o => new List<MineralDNA>()). ToArray(); foreach (MineralDNA mineral in mineralDefinitions) { building[rand.Next(building.Length)].Add(mineral); } return Enumerable.Range(0, building.Length). Select(o => Tuple.Create(destroyedIndicies[o], building[o].ToArray())). Where(o => o.Item2.Length > 0). ToArray(); }
/// <summary> /// This will convert to real minerals, pull them apart, and place them on the map /// NOTE: If these are replacing an asteroid, be sure the asteroid is removed before calling this /// </summary> public void PlaceMinerals(MineralDNA[] minerals, Point3D position, Vector3D velocity, double? maxRandomVelocity = null) { //TODO: Angular velocity AsteroidOrMineralDefinition[] positioned = PositionMinerals(minerals, maxRandomVelocity); IMapObject[] mapObjects = ConvertToMapObjects(positioned, position, velocity, Quaternion.Identity); AddToMap(mapObjects); }
// Mineral public AsteroidOrMineralDefinition(PartSeparator_Part part, MineralDNA mineralDefinition, Vector3D velocity) { this.IsAsteroid = false; this.Part = part; this.MineralDefinition = mineralDefinition; this.Velocity = velocity; this.AsteroidTriangles = null; this.AsteroidRadius = 0; this.ShouldAsteroidSelfDestruct = false; }
// Asteroid public AsteroidOrMineralDefinition(PartSeparator_Part part, ITriangleIndexed[] asteroidTriangles, double asteroidRadius, Vector3D velocity, bool shouldSelfDestruct, MineralDNA[] mineralsAfterSelfDestruct) { this.IsAsteroid = true; this.Part = part; this.AsteroidTriangles = asteroidTriangles; this.AsteroidRadius = asteroidRadius; this.ShouldAsteroidSelfDestruct = shouldSelfDestruct; this.MineralsAfterSelfDestruct = mineralsAfterSelfDestruct; this.Velocity = velocity; this.MineralDefinition = null; }
/// <summary> /// Defines the child asteroid shapes, then finds positions/orientations for all child asteroids and minerals (makes /// sure nothing overlaps) /// </summary> private AsteroidOrMineralDefinition[] PositionChildAsteroidsAndMinerals(double[] asteroidVolumes, MineralDNA[] mineralDefinitions) { const double FOURTHIRDSPI = 4d / 3d * Math.PI; const double ONETHRID = 1d / 3d; double positionRange = _radiusMin * .05; #region Asteroids PartSeparator_Part[] asteroidParts = new PartSeparator_Part[asteroidVolumes.Length]; ITriangleIndexed[][] asteroidTriangles = new ITriangleIndexed[asteroidVolumes.Length][]; double[] asteroidRadii = new double[asteroidVolumes.Length]; for (int cntr = 0; cntr < asteroidVolumes.Length; cntr++) { // r^3=v/(4/3pi) asteroidRadii[cntr] = Math.Pow(asteroidVolumes[cntr] / FOURTHIRDSPI, ONETHRID); asteroidTriangles[cntr] = GetHullTriangles_Initial(asteroidRadii[cntr]); double currentMass = _getMassByRadius(asteroidRadii[cntr], asteroidTriangles[cntr]); asteroidParts[cntr] = new PartSeparator_Part(asteroidTriangles[cntr][0].AllPoints, currentMass, Math3D.GetRandomVector_Spherical(positionRange).ToPoint(), Math3D.GetRandomRotation()); } #endregion #region Minerals PartSeparator_Part[] mineralParts = new PartSeparator_Part[mineralDefinitions.Length]; for (int cntr = 0; cntr < mineralDefinitions.Length; cntr++) { //NOTE: Copied logic from Mineral that gets collision points and mass // Points Point3D[] mineralPoints = UtilityWPF.GetPointsFromMesh((MeshGeometry3D)_sharedVisuals.Value.GetMineralMesh(mineralDefinitions[cntr].MineralType)); // Mass double mass = mineralDefinitions[cntr].Density * mineralDefinitions[cntr].Volume; // Store it mineralParts[cntr] = new PartSeparator_Part(mineralPoints, mass, Math3D.GetRandomVector_Spherical(positionRange).ToPoint(), Math3D.GetRandomRotation()); } #endregion #region Pull Apart if (asteroidParts.Length + mineralParts.Length > 1) { PartSeparator_Part[] allParts = UtilityCore.ArrayAdd(asteroidParts, mineralParts); bool dummy; CollisionHull[] hulls = PartSeparator.Separate(out dummy, allParts, _world); foreach (CollisionHull hull in hulls) { hull.Dispose(); } } #endregion #region Build Return List<AsteroidOrMineralDefinition> retVal = new List<AsteroidOrMineralDefinition>(); for (int cntr = 0; cntr < asteroidParts.Length; cntr++) { retVal.Add(new AsteroidOrMineralDefinition(asteroidParts[cntr], asteroidTriangles[cntr], asteroidRadii[cntr])); } for (int cntr = 0; cntr < mineralParts.Length; cntr++) { retVal.Add(new AsteroidOrMineralDefinition(mineralParts[cntr], mineralDefinitions[cntr])); } #endregion return retVal.ToArray(); }
// This also creates minerals private IMapObject[] GetChildAsteroids(double overDamage, Point3D parentPos, Vector3D parentVel) { 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 const int MAXCHILDREN = 5; #region Child asteroid sizes // Figure out the radius of the child asteroids double radius = GetTotalChildRadius(_radius, overDamage, MAXOVERDMG); // Get the volumes of the child asteroids double[] asteroidVolumes = null; if (radius > _minChildRadius) { double totalVolume = 4d / 3d * Math.PI * radius * radius * radius; double minVolume = 4d / 3d * Math.PI * _minChildRadius * _minChildRadius * _minChildRadius; int numChildren = GetNumChildren(radius, MAXCHILDREN, totalVolume, minVolume, overDamage, MAXOVERDMG); asteroidVolumes = GetChildVolumes(numChildren, totalVolume, minVolume); } else { // Not enough left, don't create any child asteroids radius = 0; asteroidVolumes = new double[0]; } #endregion #region Mineral sizes MineralDNA[] mineralDefinitions = null; if (_getMineralsByDestroyedMass != null) { //double destroyedMass = GetDestroyedMass(Math3D.Avg(_radius.X, _radius.Y, _radius.Z), radius, _getMassByRadius); // using avg had too many cases where the returned mass was negative double destroyedMass = GetDestroyedMass(Math1D.Max(_radius.X, _radius.Y, _radius.Z), radius, _getMassByRadius); if (destroyedMass > 0) // child radius is calculated using max of _radius, but avg was passed to the getmass method. So there's a chance that getmass returns negative { mineralDefinitions = _getMineralsByDestroyedMass(destroyedMass); } } if (mineralDefinitions == null) { mineralDefinitions = new MineralDNA[0]; } #endregion if (asteroidVolumes.Length == 0 && mineralDefinitions.Length == 0) { // Nothing to spawn return null; } // Figure out positions AsteroidOrMineralDefinition[] children = PositionChildAsteroidsAndMinerals(asteroidVolumes, mineralDefinitions); #region Create IMapObjects IMapObject[] retVal = new IMapObject[children.Length]; for (int cntr = 0; cntr < retVal.Length; cntr++) { Point3D position = parentPos + children[cntr].Part.Position.ToVector(); if (children[cntr].IsAsteroid) { // Asteroid AsteroidExtra extra = new AsteroidExtra() { Triangles = children[cntr].AsteroidTriangles, GetMineralsByDestroyedMass = _getMineralsByDestroyedMass, MineralMaterialID = _mineralMaterialID, MinChildRadius = _minChildRadius, }; retVal[cntr] = new Asteroid(children[cntr].AsteroidRadius, _getMassByRadius, position, _world, _map, _materialID, extra); } else { // Mineral MineralDNA mindef = children[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.Rotation = children[cntr].Part.Orientation; Vector3D velFromCenter = children[cntr].Part.Position.ToVector().ToUnit(false); velFromCenter *= UtilityCore.GetScaledValue(1, 4, 1, MAXOVERDMG, overDamage); retVal[cntr].PhysicsBody.Velocity = parentVel + velFromCenter; retVal[cntr].PhysicsBody.AngularVelocity = Math3D.GetRandomVector_Spherical(UtilityCore.GetScaledValue(.5, 8, 1, MAXOVERDMG, overDamage)); } #endregion return retVal; }
private AsteroidOrMineralDefinition[] PositionMinerals(MineralDNA[] minerals, double? maxRandomVelocity) { double positionRange = _radiusMin * .05; #region build parts PartSeparator_Part[] parts = new PartSeparator_Part[minerals.Length]; for (int cntr = 0; cntr < minerals.Length; cntr++) { //NOTE: Copied logic from Mineral that gets collision points and mass // Points Point3D[] mineralPoints = UtilityWPF.GetPointsFromMesh((MeshGeometry3D)_sharedVisuals.Value.GetMineralMesh(minerals[cntr].MineralType)); // Mass double mass = minerals[cntr].Density * minerals[cntr].Volume; // Store it parts[cntr] = new PartSeparator_Part(mineralPoints, mass, Math3D.GetRandomVector_Spherical(positionRange).ToPoint(), Math3D.GetRandomRotation()); } #endregion #region pull apart if (parts.Length > 1) { bool dummy; CollisionHull[] hulls = PartSeparator.Separate(out dummy, parts, _world); foreach (CollisionHull hull in hulls) { hull.Dispose(); } } #endregion #region build return List<AsteroidOrMineralDefinition> retVal = new List<AsteroidOrMineralDefinition>(); for (int cntr = 0; cntr < parts.Length; cntr++) { Vector3D velocity = new Vector3D(0, 0, 0); if (maxRandomVelocity != null) { velocity = Math3D.GetRandomVector_Spherical(maxRandomVelocity.Value); } retVal.Add(new AsteroidOrMineralDefinition(parts[cntr], minerals[cntr], velocity)); } #endregion return retVal.ToArray(); }