private void PhysicsAsteroids_ORIG(Tuple<int, ITriangleIndexed[]>[] asteroidShards, Tuple<Point3D, Vector3D, double>[] shots, double asteroidRadius)
        {
            const double ONETHIRD = 1d / 3d;
            const double DENSITY = 10;

            var subAsteroidProps = asteroidShards.
                Select(o =>
                {
                    #region examine shard

                    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
                    {
                        Index = o.Item1,
                        Triangles = shiftedTriangles,
                        Radius = radius,
                        Center = center,
                    };

                    #endregion
                }).
                ToArray();


            //TODO: When the asteroid shards are resmoothed, the velocities are very small
            //
            //Maybe add more orth velocity
            //
            //Maybe pull the hit source slightly into the asteroid
            //
            //Maybe add some random velocity (size proportional to the velocity)

            Vector3D[] veclocites = CalculateVelocites(subAsteroidProps.Select(o => o.Center).ToArray(), shots, asteroidRadius);

            veclocites = veclocites.
                Select(o => o + Math3D.GetRandomVector_Spherical(o.Length * .25)).
                ToArray();



            var getMass = new Func<double, ITriangleIndexed[], double>((rad, tris) =>
            {
                double volume = 4d * ONETHIRD * Math.PI * rad * rad * rad;
                return DENSITY * volume;
            });

            _asteroidShards = new Asteroid[asteroidShards.Length];

            for (int cntr = 0; cntr < asteroidShards.Length; cntr++)
            {
                AsteroidExtra extra = new AsteroidExtra()
                {
                    Triangles = subAsteroidProps[cntr].Triangles,
                    RandomRotation = false,
                    GetVisual = GetAsteroid,
                };

                _asteroidShards[cntr] = new Asteroid(subAsteroidProps[cntr].Radius, getMass, subAsteroidProps[cntr].Center, _world, _map, _material_Asteroid, extra);

                _asteroidShards[cntr].PhysicsBody.Velocity = veclocites[cntr];

                _map.AddItem(_asteroidShards[cntr]);
            }
        }
        private void PhysicsAsteroids()
        {
            const double ONETHIRD = 1d / 3d;
            const double DENSITY = 10;

            if (_explosion == null || _explosion.Shards == null)
            {
                return;
            }

            var getMass = new Func<double, ITriangleIndexed[], double>((rad, tris) =>
            {
                double volume = 4d * ONETHIRD * Math.PI * rad * rad * rad;
                return DENSITY * volume;
            });

            _asteroidShards = new Asteroid[_explosion.Shards.Length];

            for (int cntr = 0; cntr < _explosion.Shards.Length; cntr++)
            {
                AsteroidExtra extra = new AsteroidExtra()
                {
                    Triangles = _explosion.Shards[cntr].Hull_Centered,
                    RandomRotation = false,
                    GetVisual = GetAsteroid,
                };

                _asteroidShards[cntr] = new Asteroid(_explosion.Shards[cntr].Radius, getMass, _explosion.Shards[cntr].Center_ParentCoords, _world, _map, _material_Asteroid, extra);

                if (_explosion.Velocities != null && _explosion.Velocities.Length == _explosion.Shards.Length)
                {
                    _asteroidShards[cntr].PhysicsBody.Velocity = _explosion.Velocities[cntr];
                }

                _map.AddItem(_asteroidShards[cntr]);
            }
        }
        private void CreateAsteroids_Build(double radius, Point3D position)
        {
            AsteroidExtra extra = new AsteroidExtra()
            {
                GetMineralsByDestroyedMass = GetMineralsFromDestroyedAsteroid,
                MineralMaterialID = _material_Mineral,
                MinChildRadius = ItemOptionsAstMin2D.MINASTEROIDRADIUS,
            };

            Asteroid asteroid = new Asteroid(radius, GetAsteroidMassByRadius, position, _world, _map, _material_Asteroid, extra);

            asteroid.PhysicsBody.AngularVelocity = Math3D.GetRandomVector_Spherical(1d);
            asteroid.PhysicsBody.Velocity = Math3D.GetRandomVector_Circular(6d);
            //asteroid.PhysicsBody.Velocity = asteroid.PhysicsBody.Position.ToVector().ToUnit() * -10d;		// makes all the asteroids come toward the origin (this is just here for testing)
            //asteroid.PhysicsBody.Velocity = asteroid.PhysicsBody.Position.ToVector().ToUnit().GetRotatedVector(new Vector3D(0, 0, 1), -90) * (StaticRandom.NextDouble() * 10d);


            //asteroid.PhysicsBody.ApplyForceAndTorque += new EventHandler<BodyApplyForceAndTorqueArgs>(Asteroid_ApplyForceAndTorque);


            _map.AddItem(asteroid);

            // This works, but the asteroids end up being added after the space stations, and the transparency makes them invisible
            #region Multithread

            //// Come up with the hull on a separate thread (this should speed up the perceived load time a bit)
            //var task = Task.Factory.StartNew(() =>
            //{
            //    return Asteroid.GetHullTriangles(radius);
            //});

            //// Run this on the UI thread once the hull is built
            ////NOTE: This is not the same as a wait.  Execution will go out of this method, and this code will fire like an event later
            //task.ContinueWith(resultTask =>
            //    {
            //        double mass = 10d + (radius * 100d);		// this isn't as realistic as 4/3 pi r^3, but is more fun and stable

            //        Asteroid asteroid = new Asteroid(radius, mass, position, _world, _material_Asteroid, task.Result);

            //        asteroid.PhysicsBody.AngularVelocity = Math3D.GetRandomVectorSpherical(1d);
            //        asteroid.PhysicsBody.Velocity = Math3D.GetRandomVectorSpherical(6d);
            //        //asteroid.PhysicsBody.Velocity = asteroid.PhysicsBody.Position.ToVector().ToUnit() * -10d;		// makes all the asteroids come toward the origin (this is just here for testing)

            //        asteroid.PhysicsBody.ApplyForceAndTorque += new EventHandler<BodyApplyForceAndTorqueArgs>(Body_ApplyForceAndTorque);

            //        _map.AddItem(asteroid);
            //    }, TaskScheduler.FromCurrentSynchronizationContext());

            #endregion
        }
        private void AddAsteroid(ChangeInstruction instr)
        {
            //NOTE: The dna only holds radius, no triangles
            AsteroidExtra extra = new AsteroidExtra()
            {
                GetMineralsByDestroyedMass = _getMineralsByDestroyedMass,
                MineralMaterialID = _material_Mineral,
                MinChildRadius = _minChildAsteroidRadius,
            };

            Asteroid asteroid = new Asteroid(instr.Asteroid.Radius, _getAsteroidMassByRadius, instr.Add_Position, _world, _map, _material_Asteroid, extra);

            asteroid.PhysicsBody.AngularVelocity = instr.Add_AngVel;
            asteroid.PhysicsBody.Velocity = instr.Add_Velocity;

            _map.AddItem(asteroid);
        }
Esempio n. 5
0
            // 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;
            }
Esempio n. 6
0
        public Asteroid(double radius, Func<double, ITriangleIndexed[], double> getMassByRadius, Point3D position, World world, Map map, int materialID, AsteroidExtra extra = null)
        {
            extra = extra ?? new AsteroidExtra();

            _map = map;
            _triangles = extra.Triangles ?? GetHullTriangles(radius);

            _selfDestructAfterElapse = extra.SelfDestructAfterElapse;
            _mineralsWhenSelfDestruct = extra.MineralsWhenSelfDestruct;
            if (_selfDestructAfterElapse != null)
            {
                // Don't bother taking damage
                _isDestroying = true;
            }

            _pierceSpeed100Percent = extra.PierceSpeed100Percent;

            // The asteroid is roughly an ellipse, so get the radius of that ellipse
            Point3D[] points = _triangles.SelectMany(o => o.PointArray).ToArray();
            this.RadiusVect = new Vector3D(
                points.Max(o => Math.Abs(o.X)),
                points.Max(o => Math.Abs(o.Y)),
                points.Max(o => Math.Abs(o.Z)));

            this.Radius = radius;
            double mass = getMassByRadius(radius, _triangles);

            #region WPF Model

            Tuple<Model3D, Visual3D[]> visuals;
            if (extra.GetVisual == null)
            {
                // Material
                MaterialGroup materials = new MaterialGroup();
                materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(WorldColors.AsteroidColor)));
                materials.Children.Add(WorldColors.AsteroidSpecular);

                // Geometry Model
                GeometryModel3D geometry = new GeometryModel3D();
                geometry.Material = materials;
                geometry.BackMaterial = materials;
                geometry.Geometry = UtilityWPF.GetMeshFromTriangles(_triangles);

                // Model Visual
                ModelVisual3D visual = new ModelVisual3D();
                visual.Content = geometry;

                visuals = new Tuple<Model3D, Visual3D[]>(geometry, new[] { visual });
            }
            else
            {
                visuals = extra.GetVisual(_triangles);
            }

            this.Model = visuals.Item1;

            #endregion

            #region Physics Body

            Transform3DGroup transform = new Transform3DGroup();
            if (extra.RandomRotation)
            {
                transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(Math3D.GetRandomRotation())));
            }
            transform.Children.Add(new TranslateTransform3D(position.ToVector()));

            using (CollisionHull hull = CollisionHull.CreateConvexHull(world, 0, _triangles[0].AllPoints))
            {
                this.PhysicsBody = new Body(hull, transform.Value, mass, visuals.Item2);
                //this.PhysicsBody.IsContinuousCollision = true;
                this.PhysicsBody.MaterialGroupID = materialID;
                this.PhysicsBody.LinearDamping = .01d;
                this.PhysicsBody.AngularDamping = new Vector3D(.01d, .01d, .01d);

                //this.PhysicsBody.ApplyForceAndTorque += new EventHandler<BodyApplyForceAndTorqueArgs>(Body_ApplyForceAndTorque);
            }

            #endregion

            this.CreationTime = DateTime.UtcNow;

            _hitTracker = new HitTracker2(world, map, materialID, this, this.RadiusVect, extra.MinChildRadius, getMassByRadius, extra.GetMineralsByDestroyedMass, extra.MineralMaterialID);
        }
Esempio n. 7
0
            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;
            }