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); }
// 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; }
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); }
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; }