diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 80f65c722e..c756c29886 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -165,6 +165,7 @@ public class Vars implements Loadable{ public static Schematics schematics = new Schematics(); public static BeControl becontrol; + public static Universe universe; public static World world; public static Maps maps; public static WaveSpawner spawner; @@ -217,6 +218,7 @@ public class Vars implements Loadable{ defaultWaves = new DefaultWaves(); collisions = new EntityCollisions(); world = new World(); + universe = new Universe(); becontrol = new BeControl(); maps = new Maps(); diff --git a/core/src/mindustry/content/Planets.java b/core/src/mindustry/content/Planets.java index cd6677d142..5a91bf0eab 100644 --- a/core/src/mindustry/content/Planets.java +++ b/core/src/mindustry/content/Planets.java @@ -5,12 +5,18 @@ import mindustry.maps.planet.*; import mindustry.type.*; public class Planets implements ContentList{ - //TODO make all names - public static Planet starter; + public static Planet + sun, + starter; @Override public void load(){ - starter = new Planet("TODO", 3){{ + sun = new Planet("sun", null, 3, 1){{ + detail = 6; + generator = new TestPlanetGenerator(); + }}; + + starter = new Planet("TODO", sun, 3, 1){{ detail = 6; generator = new TestPlanetGenerator(); }}; diff --git a/core/src/mindustry/core/ContentLoader.java b/core/src/mindustry/core/ContentLoader.java index 282b06fe49..30360315bc 100644 --- a/core/src/mindustry/core/ContentLoader.java +++ b/core/src/mindustry/core/ContentLoader.java @@ -267,4 +267,8 @@ public class ContentLoader{ public Array units(){ return getBy(ContentType.unit); } + + public Array planets(){ + return getBy(ContentType.planet); + } } diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 5ef4bad8f3..206248d0f4 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -270,6 +270,8 @@ public class Control implements ApplicationListener, Loadable{ logic.reset(); world.loadSector(sector); state.rules.sector = sector; + //TODO enable for lighting + //state.rules.lighting = true; logic.play(); control.saves.saveSector(sector); //TODO uncomment for efffect diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 9b66b050c8..9ca3244c8a 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -211,6 +211,7 @@ public class Logic implements ApplicationListener{ } if(!state.isPaused()){ + universe.update(); Time.update(); if(state.rules.waves && state.rules.waveTimer && !state.gameOver){ diff --git a/core/src/mindustry/game/Universe.java b/core/src/mindustry/game/Universe.java new file mode 100644 index 0000000000..0347124d35 --- /dev/null +++ b/core/src/mindustry/game/Universe.java @@ -0,0 +1,48 @@ +package mindustry.game; + +import arc.*; +import arc.util.*; + +public class Universe{ + private long seconds; + private float secondCounter; + + public Universe(){ + load(); + } + + public void update(){ + secondCounter += Time.delta() / 60f; + if(secondCounter >= 1){ + seconds += (int)secondCounter; + secondCounter %= 1f; + + //save every few seconds + if(seconds % 10 == 1){ + save(); + } + } + } + + public float secondsMod(float mod, float scale){ + return (seconds / scale) % mod; + } + + public long seconds(){ + return seconds; + } + + public float secondsf(){ + return seconds + secondCounter; + } + + private void save(){ + Core.settings.put("utime", seconds); + Core.settings.save(); + } + + private void load(){ + seconds = Core.settings.getLong("utime"); + } + +} diff --git a/core/src/mindustry/graphics/LightRenderer.java b/core/src/mindustry/graphics/LightRenderer.java index 9777e4f9ed..58c91b4f30 100644 --- a/core/src/mindustry/graphics/LightRenderer.java +++ b/core/src/mindustry/graphics/LightRenderer.java @@ -201,4 +201,4 @@ public class LightRenderer{ lights.clear(); } -} +} \ No newline at end of file diff --git a/core/src/mindustry/type/Planet.java b/core/src/mindustry/type/Planet.java index e030b85ec0..20e1a048d0 100644 --- a/core/src/mindustry/type/Planet.java +++ b/core/src/mindustry/type/Planet.java @@ -1,6 +1,7 @@ package mindustry.type; import arc.files.*; +import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; import arc.struct.*; @@ -14,9 +15,13 @@ import mindustry.graphics.g3d.PlanetGrid.*; import mindustry.maps.generators.*; import mindustry.type.Sector.*; +import static mindustry.Vars.universe; + public class Planet extends UnlockableContent{ + /** Default spacing between planet orbits in world units. */ + private static final float orbitSpacing = 6f; /** Mesh used for rendering. Created on load() - will be null on the server! */ - public PlanetMesh mesh; + public GenericMesh mesh; /** Grid used for the sectors on the planet. */ public @NonNull PlanetGrid grid; /** Generator that will make the planet. */ @@ -25,15 +30,28 @@ public class Planet extends UnlockableContent{ public @NonNull Array sectors; /** Detail in divisions. Must be between 1 and 10. 6 is a good number for this.*/ public int detail = 3; - /** Size in terms of divisions. This only controls the amount of sectors on the planet, not the visuals. */ - public int size; - /** Radius of the mesh/sphere. */ - public float radius = 1f; + /** Radius of this planet's sphere. Does not take into account sattelites. */ + public float radius; + /** Orbital radius around the sun. Do not change unless you know exactly what you are doing.*/ + public float orbitRadius; + /** Total radius of this planet and all its children. */ + public float totalRadius; + /** Time for the planet to orbit around the sun once, in seconds. One year. */ + public float orbitTime; + /** Time for the planet to perform a full revolution, in seconds. One day. */ + public float rotateTime = 24f * 60f; + /** Whether this planet is tidally locked relative to its parent - see https://en.wikipedia.org/wiki/Tidal_locking */ + public boolean tidalLock = false; + /** Parent body that this planet orbits around. If null, this planet is considered to be in the middle of the solar system.*/ + public @Nullable Planet parent; + /** All planets orbiting this one, in ascending order of radius. */ + public Array children = new Array<>(); - public Planet(String name, int size){ + public Planet(String name, Planet parent, int size, float radius){ super(name); - this.size = 3; + this.radius = radius; + this.parent = parent; grid = PlanetGrid.create(size); @@ -42,6 +60,18 @@ public class Planet extends UnlockableContent{ sectors.add(new Sector(this, grid.tiles[i], new SectorData())); } + //get orbit radius by extending past the parent's total radius + orbitRadius = parent == null ? 0f : (parent.totalRadius + orbitSpacing + radius); + + //orbit time is based on radius [kepler's third law] + orbitTime = Mathf.pow(orbitRadius, 1.5f) * 1000; + + //add this planet to list of children and update parent's radius + if(parent != null){ + parent.children.add(this); + parent.updateTotalRadius(); + } + //read data Fi data = Vars.tree.get("planets/" + name + ".dat"); if(data.exists()){ @@ -57,6 +87,52 @@ public class Planet extends UnlockableContent{ } } + public void updateTotalRadius(){ + totalRadius = radius; + for(Planet planet : children){ + //max with highest outer bound planet + totalRadius = Math.max(totalRadius, planet.orbitRadius + planet.totalRadius); + } + } + + /** Calculates orbital rotation based on universe time.*/ + public float getOrbitAngle(){ + //applies random offset to prevent planets from starting out in a line + float offset = Mathf.randomSeed(id, 360); + return (offset + universe.seconds() / (orbitTime / 360f)) % 360f; + } + + /** Calulates rotation on own axis based on universe time.*/ + public float getRotation(){ + //tidally locked planets always face toward parents + if(tidalLock){ + return getOrbitAngle(); + } + //random offset for more variability + float offset = Mathf.randomSeed(id+1, 360); + return (offset + universe.seconds() / (rotateTime / 360f)) % 360f; + } + + /** Adds this planet's offset relative to its parent to the vector. Used for calculating world positions. */ + public Vec3 addParentOffset(Vec3 in){ + //planets with no parents are at the center, so they appear at 0,0 + if(parent == null || Mathf.zero(orbitRadius)){ + return in; + } + + float angle = getOrbitAngle(); + return in.add(Angles.trnsx(angle, orbitRadius), Angles.trnsy(angle, orbitRadius), 0f); + } + + /** Gets the absolute world position of this planet, taking into account all parents. O(n) complexity.*/ + public Vec3 getWorldPosition(Vec3 in){ + in.setZero(); + for(Planet current = this; current != null; current = current.parent){ + current.addParentOffset(in); + } + return in; + } + @Override public void load(){ mesh = new PlanetMesh(detail, generator); diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index 1610cdb818..4485939205 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -31,10 +31,15 @@ public class PlanetDialog extends FloatingDialog{ private static final float camLength = 4f; float outlineRad = 1.15f; + //the base planet that's being rendered + private final Planet solarSystem = Planets.sun; + private final PlanetMesh[] outlines = new PlanetMesh[10]; private final Camera3D cam = new Camera3D(); private final VertexBatch3D batch = new VertexBatch3D(false, true, 0); private final PlaneBatch3D projector = new PlaneBatch3D(); + private final Mat3D mat = new Mat3D(); + private final SphereMesh sun = new SphereMesh(3, 1.2f); private final Bloom bloom = new Bloom(false){{ @@ -57,7 +62,7 @@ public class PlanetDialog extends FloatingDialog{ projector.setScaling(1f / 300f); update(() -> { - Ptile tile = outline(planet.size).getTile(cam.getPickRay(Core.input.mouseX(), Core.input.mouseY())); + Ptile tile = outline(planet.grid.size).getTile(cam.getPickRay(Core.input.mouseX(), Core.input.mouseY())); hovered = tile == null ? null : planet.getSector(tile); Vec3 v = Tmp.v33.set(Core.input.mouseX(), Core.input.mouseY(), 0); @@ -150,9 +155,10 @@ public class PlanetDialog extends FloatingDialog{ projector.proj(cam.combined()); batch.proj(cam.combined()); - renderSun(); - renderPlanet(); + renderPlanet(solarSystem); + //renderSun(); + //renderPlanet(); for(Sector sec : planet.sectors){ if(sec.save == null){ @@ -198,11 +204,33 @@ public class PlanetDialog extends FloatingDialog{ } } + private void renderPlanet(Planet planet){ + //render planet at offsetted position in the world + Vec3 position = planet.getWorldPosition(Tmp.v33); + mat.set(cam.combined()).trn(position); //TODO this probably won't give the desired result + planet.mesh.render(mat); + + renderOrbit(planet); + + for(Planet child : planet.children){ + renderPlanet(child); + } + } + + private void renderOrbit(Planet planet){ + if(planet.parent == null) return; + + Vec3 center = planet.parent.getWorldPosition(Tmp.v31); + float radius = planet.radius; + int points = (int)(radius * 10); + Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray)); + batch.flush(Gl.lineLoop); + } + private void renderPlanet(){ - PlanetMesh outline = outline(planet.size); + PlanetMesh outline = outline(planet.grid.size); Vec3 tile = outline.intersect(cam.getPickRay(Core.input.mouseX(), Core.input.mouseY())); Shaders.planetGrid.mouse.lerp(tile == null ? Vec3.Zero : tile, 0.2f); - Shaders.planet.lightDir.set(Shaders.sun.center).nor(); planet.mesh.render(cam.combined()); diff --git a/gradle.properties b/gradle.properties index 2b800f4165..c20f31f7e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=7b20f312c317d571738e8f2e53501ae00d48f0d0 +archash=bff072e2d671c74a32b41353125c2aa6ba8c0314