/// <summary> /// Initializes a new instance of <see cref="SurfaceRegion"/>. /// </summary> /// <param name="planet">The planet on which this region is found.</param> /// <param name="position">The normalized position vector of this region.</param> /// <param name="latitudeRange"> /// <para> /// The range of latitudes encompassed by this region, as an angle (in radians). /// </para> /// <para> /// Maximum value is π (a full hemisphere, which produces the full globe). /// </para> /// </param> public SurfaceRegion(Planetoid planet, Vector3 <HugeNumber> position, HugeNumber latitudeRange) : base(planet.Id, new Frustum <HugeNumber>(2, position * (planet.Shape.ContainingRadius + planet.Atmosphere.AtmosphericHeight), HugeNumber.Min(latitudeRange, HugeNumber.Pi), 0)) { }
// ------------------------------------------------------------------------------- private void OnPlanetoidChange(Planetoid newPlanetoid) { mGameManager.ChangeGameplayState(GameplayStates.RidingSunbeams); FinishAction(); }
internal Atmosphere( Planetoid planet, double pressure, params (ISubstanceReference substance, decimal proportion)[] constituents) : this(pressure)
// returns null if nothing was sliced // even when hit by the laser nothing might get sliced // this is because I limit the minimum size of a new // planetoid for performance reasons. // public Planetoid Slice(Ray2D laser, float laserPower, PlanetoidsManager manager) { if (_fading) { return(null); } try { Vector2 start = transform.InverseTransformPoint(laser.origin); Vector2 end = transform.InverseTransformPoint(laser.origin + laser.direction * Laser.LASER_DISTANCE); SlicePoint[] slicePoints = new SlicePoint[2]; Vector2[] vertices = _collider.points; int foundPoints = 0; for (int i = 0; i < vertices.Length && foundPoints <= 2; ++i) { //Calculate intersectionPoint //For formula see http://en.wikipedia.org/wiki/Line-line_intersection //I'm using x1, x2, ... since that's easier to write. float x1 = start.x, x2 = end.x, x3 = vertices[i].x, x4 = vertices[(i + 1) % vertices.Length].x; float y1 = start.y, y2 = end.y, y3 = vertices[i].y, y4 = vertices[(i + 1) % vertices.Length].y; Vector2 intersectionPoint = new Vector2( (((x1 * y2 - y1 * x2) * (x3 - x4)) - ((x1 - x2) * (x3 * y4 - y3 * x4))) / (((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4))), (((x1 * y2 - y1 * x2) * (y3 - y4)) - ((y1 - y2) * (x3 * y4 - y3 * x4))) / (((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4))) ); //See if the point is is actually on the side & laser. float startx = Mathf.Min(vertices[i].x, vertices[(i + 1) % vertices.Length].x); //side float endx = Mathf.Max(vertices[i].x, vertices[(i + 1) % vertices.Length].x); float starty = Mathf.Min(vertices[i].y, vertices[(i + 1) % vertices.Length].y); float endy = Mathf.Max(vertices[i].y, vertices[(i + 1) % vertices.Length].y); float start2x = Mathf.Min(start.x, end.x); //laser float end2x = Mathf.Max(start.x, end.x); float start2y = Mathf.Min(start.y, end.y); float end2y = Mathf.Max(start.y, end.y); if (intersectionPoint.x >= startx && intersectionPoint.x < endx && intersectionPoint.y >= starty && intersectionPoint.y < endy && intersectionPoint.x >= start2x && intersectionPoint.x < end2x && intersectionPoint.y >= start2y && intersectionPoint.y < end2y) { //Add to the slicePoints vector if you find anything // throws when too many points were found slicePoints[foundPoints] = new SlicePoint(intersectionPoint, i); ++foundPoints; } } if (foundPoints != 2) { throw new UnityException("Wrong number of points found while slicing: " + foundPoints); } //Calculate the number of sides each part of the rock will have int numberOfPoints1 = Mathf.Abs(slicePoints[0].side - slicePoints[1].side); int numberOfPoints2 = vertices.Length - numberOfPoints1; //numberOfPoints1 = min(numberOfPoints1, b2_maxPolygonVertices-2); //Make sure there aren't too many vertexes (Box2D 'limitation') //numberOfPoints2 = min(numberOfPoints2, b2_maxPolygonVertices-2); //I raised the max Polygon verts to 16 (default 8) so it will almost never happen, though when it does it's almost invisible //Create vectors to save the sides of each new rock Vector2[] sides1 = new Vector2[numberOfPoints1 + 2]; Vector2[] sides2 = new Vector2[numberOfPoints2 + 2]; //Filling in the first vector int counter = slicePoints[0].side + 1; for (var i = 0; i < numberOfPoints1; ++i) { if (counter >= vertices.Length) { throw new UnityException("Whoops, something wrong with the slicing. Should never happen, please report this."); //Should never go over 0 } sides1[i] = vertices[counter]; ++counter; } //Lastly add the intersection points to the sides1. sides1[numberOfPoints1 + 0] = slicePoints[1].point; //Since I add them to the back the second one found will always be the first one here. sides1[numberOfPoints1 + 1] = slicePoints[0].point; //Filling in the second one for (var i = 0; i < numberOfPoints2; ++i) { counter = counter % vertices.Length; sides2[i] = vertices[counter]; ++counter; } sides2[numberOfPoints2 + 0] = slicePoints[0].point; sides2[numberOfPoints2 + 1] = slicePoints[1].point; //Check if both new polygons are valid. Their size & winding will be checked, also they have to be convex. if (GetArea(sides1) < MINIMUM_AREA || GetArea(sides2) < MINIMUM_AREA) { throw new UnityException("At least one of the new planetoids is too small, not slicing for performance reasons."); } //Get some values needed to set later. Vector2 linVel = _rigidbody.velocity; float angleVel = _rigidbody.angularVelocity; Vector2 dir = laser.direction; Vector2 lr = new Vector2(-dir.y, dir.x); lr.Normalize(); lr *= laserPower; //Change this rock. Initialize(sides1, manager); //Make the other part. Planetoid newRock = manager.GetNewOrCashedPlanetoid(); newRock.Initialize(sides2, manager); newRock.transform.position = transform.position; newRock.transform.rotation = transform.rotation; newRock._rigidbody.velocity = linVel; newRock._rigidbody.angularVelocity = angleVel; newRock._density = _density; //Set Velocities. _rigidbody.AddForce(lr, ForceMode2D.Impulse); newRock._rigidbody.AddForce(-lr, ForceMode2D.Impulse); return(newRock); } catch (UnityException ex) { Debug.Log("Failed slicing: " + ex.Message); return(null); } catch { Debug.Log("Failed slicing for an unknown reason"); return(null); } }
/// <summary> /// Initializes a new instance of <see cref="PlanetChildDefinition"/>. /// </summary> /// <param name="density"> /// The density of this type of child within the containing parent region. /// </param> /// <param name="planemoType"> /// The type of <see cref="Planetoid"/>. /// </param> public PlanetChildDefinition(HugeNumber density, PlanetType planemoType = PlanetType.Dwarf) : base(Planetoid.GetSpaceForType(planemoType), density) => PlanetType = planemoType;
private static void AddPrecipitationString( StringBuilder sb, Planetoid planet, Image <L16> elevationMap, Image <L16> precipitationMap, double normalizedSeaLevel, int landCoords, WeatherMaps maps) { sb.Append("Max precip: ") .Append(Math.Round(planet.Atmosphere.MaxPrecipitation, 3)) .AppendLine("mm/hr"); sb.AppendLine("Precipitation (average, land):"); if (landCoords == 0) { sb.AppendLine(" No land."); return; } var n = 0; var temperate = 0.0; var list = new List <double>(); for (var x = 0; x < maps.XLength; x++) { for (var y = 0; y < maps.YLength; y++) { if (((double)elevationMap[x, y].PackedValue / ushort.MaxValue) - normalizedSeaLevel < 0) { continue; } var precipitation = (double)precipitationMap[x, y].PackedValue / ushort.MaxValue * planet.Atmosphere.MaxPrecipitation; list.Add(precipitation); if (maps.ClimateMap[x][y] is ClimateType.CoolTemperate or ClimateType.WarmTemperate) { temperate += precipitation; n++; } } } list.Sort(); if (n == 0) { temperate = 0; } else { temperate /= n; } var avg = list.Average(); sb.AppendFormat(" Avg: {0}mm/hr ({1:+0.##;-0.##;on-targ\\et})", Math.Round(avg, 3), Math.Round(avg - 0.11293634496919917864476386036961, 3)); sb.AppendLine(); var avg90 = list.Take((int)Math.Floor(list.Count * 0.9)).Average(); sb.AppendFormat(" Avg (<=P90): {0}mm/hr ({1:+0.##;-0.##;on-targ\\et})", Math.Round(avg90, 3), Math.Round(avg90 - 0.11293634496919917864476386036961, 3)); sb.AppendLine(); var avgList = planet.Atmosphere.AveragePrecipitation; sb.AppendFormat(" Avg (listed): {0}mm/hr ({1:+0.##;-0.##;on-targ\\et})", Math.Round(avgList, 3), Math.Round(avgList - 0.11293634496919917864476386036961, 3)); sb.AppendLine(); sb.AppendFormat(" Avg (Temperate): {0}mm/hr ({1:+0.##;-0.##;on-targ\\et})", Math.Round(temperate, 3), Math.Round(temperate - 0.12548482774355464293862651152179, 3)); sb.AppendLine(); sb.AppendFormat(" Min: {0}mm/hr", Math.Round(list[0], 3)); sb.AppendLine(); sb.AppendFormat(" P10: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.1)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P20: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.2)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P30: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.3)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P40: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.4)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P50: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.5)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P60: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.6)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P70: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.7)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P80: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.8)).First(), 3)); sb.AppendLine(); sb.AppendFormat(" P90: {0}mm/hr", Math.Round(list.Skip((int)Math.Floor(list.Count * 0.9)).First(), 3)); sb.AppendLine(); var max = list.Last(); sb.AppendFormat(" Max: {0}mm/hr ({1:+0.##;-0.##;on-targ\\et})", Math.Round(max), Math.Round(max - 1.3542094455852156057494866529774, 3)); sb.AppendLine(); }
public static Planetoid GenerateRandomMoon(Planetoid parent, string name) { return(new Planetoid(parent.System, name, parent)); }
/// <summary> /// Produces an elevation map projection of this region. /// </summary> /// <param name="region">The mapped region.</param> /// <param name="planet">The planet being mapped.</param> /// <param name="resolution">The vertical resolution of the projection.</param> /// <param name="equalArea"> /// If <see langword="true"/> the projection will be a cylindrical equal-area projection. /// Otherwise, an equirectangular projection will be used. /// </param> /// <returns> /// A projected map of elevation. Pixel luminosity indicates elevation relative to <see /// cref="Planetoid.MaxElevation"/>, with values below the midpoint indicating elevations /// below the mean surface. /// </returns> public static Image <L16> GetElevationMap( this SurfaceRegion region, Planetoid planet, int resolution, bool equalArea = false) => planet.GetElevationMap(resolution, region.GetProjection(planet, equalArea));
public void EarthlikePlanet() { // First run to ensure timed runs do not include any one-time initialization costs. _ = Planetoid.GetPlanetForSunlikeStar(out _); var stopwatch = new Stopwatch(); stopwatch.Start(); var planet = Planetoid.GetPlanetForSunlikeStar(out _); stopwatch.Stop(); Assert.IsNotNull(planet); Console.WriteLine($"Planet generation time: {stopwatch.Elapsed:s'.'FFF} s"); Console.WriteLine($"Radius: {planet!.Shape.ContainingRadius / 1000:N0} km"); Console.WriteLine($"Surface area: {planet!.Shape.ContainingRadius.Square() * HugeNumberConstants.FourPi / 1000000:N0} km²"); stopwatch.Restart(); using (var elevationMap = planet.GetElevationMap(MapResolution)) { var(winterTemperatureMap, summerTemperatureMap) = planet.GetTemperatureMaps(elevationMap, MapResolution); var(precipitationMaps, snowfallMaps) = planet .GetPrecipitationAndSnowfallMaps(winterTemperatureMap, summerTemperatureMap, MapResolution, Seasons); for (var i = 0; i < snowfallMaps.Length; i++) { snowfallMaps[i].Dispose(); } using var precipitationMap = SurfaceMapImage.AverageImages(precipitationMaps); for (var i = 0; i < precipitationMaps.Length; i++) { precipitationMaps[i].Dispose(); } _ = new WeatherMaps( planet, elevationMap, winterTemperatureMap, summerTemperatureMap, precipitationMap, MapResolution, MapProjectionOptions.Default); winterTemperatureMap.Dispose(); summerTemperatureMap.Dispose(); } stopwatch.Stop(); Console.WriteLine($"Equirectangular surface map generation time: {stopwatch.Elapsed:s'.'FFF} s"); var projection = new MapProjectionOptions(equalArea: true); stopwatch.Restart(); using var elevationMapEA = planet.GetElevationMap(MapResolution, projection); var(winterTemperatureMapEA, summerTemperatureMapEA) = planet.GetTemperatureMaps(elevationMapEA, MapResolution, projection, projection); using var temperatureMapEA = SurfaceMapImage.AverageImages(winterTemperatureMapEA, summerTemperatureMapEA); var(precipitationMapsEA, snowfallMapsEA) = planet .GetPrecipitationAndSnowfallMaps(winterTemperatureMapEA, summerTemperatureMapEA, MapResolution, Seasons, projection, projection); for (var i = 0; i < snowfallMapsEA.Length; i++) { snowfallMapsEA[i].Dispose(); } using var precipitationMapEA = SurfaceMapImage.AverageImages(precipitationMapsEA); for (var i = 0; i < precipitationMapsEA.Length; i++) { precipitationMapsEA[i].Dispose(); } var climateMapsEA = new WeatherMaps( planet, elevationMapEA, winterTemperatureMapEA, summerTemperatureMapEA, precipitationMapEA, MapResolution, projection); winterTemperatureMapEA.Dispose(); summerTemperatureMapEA.Dispose(); stopwatch.Stop(); Console.WriteLine($"Cylindrical equal-area surface map generation time: {stopwatch.Elapsed:s'.'FFF} s"); var normalizedSeaLevel = planet.SeaLevel / planet.MaxElevation; var elevationRange = planet.GetElevationRange(elevationMapEA); var landCoords = 0; if (planet.Hydrosphere?.IsEmpty == false) { for (var x = 0; x < elevationMapEA.Width; x++) { for (var y = 0; y < elevationMapEA.Height; y++) { var value = (2.0 * elevationMapEA[x, y].PackedValue / ushort.MaxValue) - 1; if (value - normalizedSeaLevel > 0) { landCoords++; } } } } var sb = new StringBuilder(); AddTempString(sb, temperatureMapEA); sb.AppendLine(); AddTerrainString(sb, planet, elevationMapEA, landCoords); sb.AppendLine(); AddClimateString(sb, elevationMapEA, normalizedSeaLevel, landCoords, climateMapsEA); sb.AppendLine(); AddPrecipitationString(sb, planet, elevationMapEA, precipitationMapEA, normalizedSeaLevel, landCoords, climateMapsEA); Console.WriteLine(sb.ToString()); }
public void InitializeSystem() { //Clear old data if (generateName) { name = (new Spaceworks.PhenomicNameGenerator()).Generate(4, 8); } DestorySystem(); //Make the floating origin if it does not exist FloatingOrigin.Make(); //Create the sun's reference (0,0,0) in the model (view not made) this.sun = new KeplerBody(this.SolarMass, null); //Create the initial states of all planetoids this.planetStates = new PlanetoidState[this.planetoids.Length]; for (int i = 0; i < this.planetoids.Length; i++) { try { //Init references Planetoid planet = this.planetoids[i]; GameObject planetGO = new GameObject(string.IsNullOrEmpty(planet.planetData.name) ? this.name + " - " + i : planet.planetData.name); PlanetoidState state = new PlanetoidState(); this.planetStates[i] = state; //Init orbit model state.orbit = new KeplerOrbit(this.sun, planet.orbit); state.body = new KeplerBody(planet.mass, state.orbit); state.gameobject = planetGO; //Configure components FloatingTransform transform = planetGO.AddComponent <FloatingTransform>(); transform.worldPosition = new WorldPosition(state.orbit.GetCurrentPosition()); state.transform = transform; CubemapMeshGenerator meshService = planetGO.AddComponent <CubemapMeshGenerator>(); meshService.range = planet.mountains; meshService.useSkirts = true; meshService.heights = planet.heights; meshService.Init(); CubemapTextureService textureService = planetGO.AddComponent <CubemapTextureService>(); textureService.top = planet.baseMaterial; textureService.top.SetTexture("_MainTex", planet.textures.top); textureService.bottom = planet.baseMaterial; textureService.bottom.SetTexture("_MainTex", planet.textures.bottom); textureService.left = planet.baseMaterial; textureService.left.SetTexture("_MainTex", planet.textures.left); textureService.right = planet.baseMaterial; textureService.right.SetTexture("_MainTex", planet.textures.right); textureService.front = planet.baseMaterial; textureService.front.SetTexture("_MainTex", planet.textures.front); textureService.back = planet.baseMaterial; textureService.back.SetTexture("_MainTex", planet.textures.back); PlanetConfig pcc = new PlanetConfig(planet.planetData); pcc.generationService = meshService; pcc.textureService = textureService; Planet p = new Planet(pcc); p.RenderOn(planetGO); if (Camera.main) { p.ForceUpdateLODs(Camera.main.transform.position); } state.planet = p; } catch (Exception e) { Debug.Log("Failed to fully instanciate planetoid: " + i + " because"); Debug.Log(e.Message); Debug.Log(e.StackTrace); } } }
public void InitSetPlanetoidUniforms(Planetoid planetoid) { InitPlanetoidUniforms(planetoid); SetPlanetoidUniforms(planetoid); }
/// <summary> /// Determines whether the given <paramref name="moment"/> falls within the range indicated. /// </summary> /// <param name="planet">The mapped planet.</param> /// <param name="range">The range being interpolated.</param> /// <param name="moment">The time at which the determination is to be performed.</param> /// <returns><see langword="true"/> if the range indicates a positive result for the given /// <paramref name="moment"/>; otherwise <see langword="false"/>.</returns> public static bool GetAnnualRangeIsPositiveAtTime( this Planetoid planet, FloatRange range, Instant moment) => SurfaceMap.GetAnnualRangeIsPositiveAtTime(range, (float)planet.GetProportionOfYearAtTime(moment));
// ------------------------------------------------------------------------------- public void OnSpawned(Vector3 groundNormal, PlantData plantData, GameObject dirtDecal, Planetoid planetoidOwner, bool spawnedByPlayer) { if (!Animator) { Animator = GetComponent <Animator>(); } mWilteredShaderPopertyId = Shader.PropertyToID("_Wilted"); mPlanetoidOwner = planetoidOwner; mPlantManager = PlantManager.Instance; PlantData = plantData; mMainGrowth = (1.0f - PlantData.InitialGrowth); mBeingHarvested = false; mNormalisedGrowth = 0.0f; mGrowthTime = 0.0f; mDirtDecalRenderer = dirtDecal.GetComponent <Renderer>(); if (spawnedByPlayer) { LeanTween.scale(mDirtDecalRenderer.gameObject, mDirtDecalRenderer.transform.localScale, 1.0f); mDirtDecalRenderer.transform.localScale = Vector3.zero; AudioManager.Instance.PlayRandomSfx(MyAudioSource, 0f, "Drop1", "Drop2", "Drop3"); } mDirtDecalRenderer.material.color = Color.Lerp(mPlantManager.DirtDecalUnwateredColor, mPlantManager.DirtDecalWateredColor, Mathf.Clamp01(WaterCharge)); mSkinnedMeshRenderer = GetComponentInChildren <SkinnedMeshRenderer>(); PlantType = plantData.PlantType; mNumGrowAnims = plantData.NumGrowthAnims; Animator.SetInteger("GrowIndex", Random.Range(0, mNumGrowAnims)); transform.up = GroundNormal = groundNormal; mSkinnedMeshRenderer.material.SetFloat(mWilteredShaderPopertyId, mWilted); }
void GeneratePlanetoid() { current_planetoid = new Planetoid(); current_planetoid.terrain_colors = possible_terrain_colors[Random.Range(0, possible_terrain_colors.Length)]; }