void deleteChunks(WorldPos curChunk) { //the list that will gather chunks to be deleted List <WorldPos> chunksToDelete = new List <WorldPos>(); foreach (WorldPos pos in requestedChunks) { //NOTE: make 100 a definied variable later and change it to not 100 //if the distance between the current chunk and one chunk still in the requestedchunks list is greater than an arbitrary value, request its destruction if (Vector3.Distance(curChunk.toVector3(), pos.toVector3()) > 120) { chunksToDelete.Add(pos); } } //now deleta all the chunks that were added to the list foreach (WorldPos pos in chunksToDelete) { requestedChunks.Remove(pos); //convert the worldpos to a surface pos SurfacePos surfp = UnitConverter.getSP(pos.toVector3(), UniverseSystem.curPlanet.surface.sideLength); //convert the surfacepos to a surface unit then request its deletion UniverseSystem.curPlanet.surface.deleteSurface(surfp.toUnit()); } }
//converts the surface position of a system with certain side length(sideLength1) //to the surface position of a system with a different side length(sideLength2) //for example, convert the position of the SurfaceSystem to a position in a TransportSystem (actually, this is probably the only use) //banana time public static SurfacePos SPtoSP(SurfacePos pos, int sideLength1, int sideLength2) { //straightforward, divide each coordinate by the first sidelength and multiply it by the second pos.u = (pos.u / sideLength1) * sideLength2; pos.v = (pos.v / sideLength1) * sideLength2; return(pos); }
void deleteSurface(WorldPos pos) { //convert the worldpos to a surface pos SurfacePos surfp = UnitConverter.getSP(pos.toVector3(), UniverseSystem.curPlanet.surface.sideLength); //convert the surfacepos to a surface unit then request its creation ////UniverseSystem.curPlanet.surface.deleteSurface(surfp.toUnit()); }
//this requests the generation of a surface unit that is at the center of the chunk void requestSurface(WorldPos pos) { //convert the worldpos to a surface pos SurfacePos surfp = UnitConverter.getSP(pos.toVector3(), UniverseSystem.curPlanet.surface.sideLength); //Debug.Log (pos); //convert the surfacepos to a surface unit then request its creation UniverseSystem.curPlanet.surface.CreateSurfaceObjects(surfp.toUnit()); }
//builds the surface units from a chunk void buildSurfFromChunk(WorldPos chunk) { //convert the worldpos to a surface pos SurfacePos surfp = UnitConverter.getSP(chunk.toVector3(), UniverseSystem.curPlanet.surface.sideLength); //convert the surfacepos to a surface unit then request its creation UniverseSystem.curPlanet.surface.CreateSurfaceObjects(surfp.toUnit()); requestedChunks.Add(chunk); //add it to the already requested chunks list }
//converts a surface position to a world position given a surfacepos and radius //this converts the surfacepos to a point on a unit cube, which is then converted to a point on a unit sphere //sideLength is the length of the side of a face public static Vector3 getWP(SurfacePos sp, float radius, int sideLength) { float halfSide = sideLength / 2; //halfside is used more often than side //point on a unit cube Vector3 cubePos; //converts surface position to a world position on a cube(not on a sphere yet) //NOTE: the u v axes on the front, bottom, and left are inverted, so one of the values is made negative to flip it switch (sp.side) { case PSide.TOP: cubePos = new Vector3(sp.u, halfSide, sp.v); //halfside in the y component means this point is on the top of the cube break; case PSide.BOTTOM: cubePos = new Vector3(sp.u, -halfSide, -sp.v); //negative sp.v because on the bottom the z/v axis is reversed so the coordinate system for this side is not backwards break; case PSide.RIGHT: cubePos = new Vector3(halfSide, sp.v, sp.u); break; case PSide.LEFT: cubePos = new Vector3(-halfSide, sp.v, -sp.u); //negative sp.u for same reason as the bottom break; case PSide.FRONT: cubePos = new Vector3(-sp.u, sp.v, halfSide); //negative sp.u for same reason as the left and bottom break; case PSide.BACK: cubePos = new Vector3(sp.u, sp.v, -halfSide); break; case PSide.NONE: //used to catch any errors return(new Vector3(0, 0, 0)); default: //won't ever happen cubePos = new Vector3(); break; } //shrinks the cube down to having a side length of 2 cubePos /= halfSide; //point on a unit sphere Vector3 spherePos = new Vector3(); //this formula maps the coordinates on a cube to coordinates on a sphere //found here: http://mathproofs.blogspot.co.uk/2005/07/mapping-cube-to-sphere.html //for use in the formula float xsq = cubePos.x * cubePos.x; float ysq = cubePos.y * cubePos.y; float zsq = cubePos.z * cubePos.z; spherePos.x = cubePos.x * Mathf.Sqrt(1.0f - ysq * 0.5f - zsq * 0.5f + ysq * zsq / 3.0f); spherePos.y = cubePos.y * Mathf.Sqrt(1.0f - xsq * 0.5f - zsq * 0.5f + xsq * zsq / 3.0f); spherePos.z = cubePos.z * Mathf.Sqrt(1.0f - ysq * 0.5f - xsq * 0.5f + ysq * xsq / 3.0f); //resulting vector is 1 unit long, so multiply by some specified radius return(spherePos * radius); }
//returns the surface Position (side, x, and y) given a world xyz position //inverse of getWP public static SurfacePos getSP(Vector3 pos, int sideLength) { pos.Normalize(); //normalize the pos to get a point on the unit sphere //will later be returned after infoed(new word i just made up) SurfacePos sp = new SurfacePos(); //absolute values of each component float absx = Mathf.Abs(pos.x); float absy = Mathf.Abs(pos.y); float absz = Mathf.Abs(pos.z); //the position of a point on a cube with side length 2 in world space //one of the values will always be 1 or -1 Vector3 cubePos = new Vector3(); //determines the side and assigns x and y values //basically, the direction that is farthes from the center determines the side you are on if (absy > absx && absy > absz) //if the y value is the farthest it will be the top or bottom { //pos.y == -1 or 1 (bottom or top) //calculate the remaining cube components cubify(pos.x, pos.z, out sp.u, out sp.v); //Debug.Log (sp.u + " " + sp.v); if (pos.y >= 0) { sp.side = PSide.TOP; //if positive y value, it is the top } else { sp.side = PSide.BOTTOM; sp.v *= -1; //take opposite of sp.v because the uv axes on the bottom are reversed, so this flips the v axis back } } else if (absx > absy && absx > absz) //if the x value is the farthest it will be the Right or left { //calculate the remaining cube components cubify(pos.z, pos.y, out sp.u, out sp.v); if (pos.x >= 0) { sp.side = PSide.RIGHT; //if positive x value, it is the right } else { sp.side = PSide.LEFT; sp.u *= -1; //uv axes on the left are reversed, so this flips the u axis back } } else if (absz > absy && absz > absx) //if the z value is the farthest it will be the front or back { //calculate the remaining cube components cubify(pos.x, pos.y, out sp.u, out sp.v); //NOTE: the front is pretty much the back in terms of where right and left are if (pos.z >= 0) { sp.side = PSide.FRONT; //if positive z value, it is the front sp.u *= -1; //uv axes on the 'front' are reversed, so this flips the u axis back } else { sp.side = PSide.BACK; } } else //shouldn't happen, actually it could happen { sp.x = 0; sp.y = 0; sp.side = PSide.NONE; } float halfSide = sideLength / 2; //halfside is used more often than side //these values have a range of 2 [-1,1], so multiply them by half the side length sp.u *= halfSide; sp.v *= halfSide; //Debug.Log (pos); //Debug.Log (sp); return(sp); }
//a working name //builds all the objects in a certain surface unit //or if it already exists, increase its wuCount public void CreateSurfaceObjects(SurfaceUnit su) { //creates an empty surface holder SurfaceHolder sh = null; //Debug.Log (su); //only make the objects in this unit if it has not already been generated //and add it to the list so it is not generated again if (!surfList.TryGetValue(su, out sh)) { sh = new SurfaceHolder(); curSH = sh; //connect class wide reference surfList.Add(su, sh); //instance a random number generator with seed based on the su position sent through a hash function //NOTE: the last 1 parameter is used as a kind of planet identifier, but this may not be needed //System.Random rand = new System.Random((int)WorldManager.hash.GetHash(su.u, su.v, (int)su.side, 1)); System.Random rand = RandomHandler.surfaceRandom(su); //NOTE: all objects that are in the rect list are always in the radial list //create a list of radial collisions //(x,y,radius) List <RadialCol> radCols = new List <RadialCol>(); //create a list of rectangular collisions //List<Vector4> rectCols = new List<Vector4>(); //first add all roads, then buildings, then natural things //build all transportation segments and add them to the collision lists //buildTransport(su); //create a list of samples List <Sub> samples = new List <Sub>(); for (int i = 0; i < numSamples; i++) { SurfacePos surfPos = new SurfacePos(su.side, su.u + (float)rand.NextDouble(), su.v + (float)rand.NextDouble()); //convert the surface position to world position Vector3 worldPos = UnitConverter.getWP(surfPos, radius, sideLength); //TODO: make function to only retrieve the substance and not vox val float val; Sub sub; planet.noise.getVoxData(worldPos, out val, out sub); //Debug.Log(sub); samples.Add(sub); } foreach (Blueprint bp in blueprints) { int amount = bp.getAmount(samples, new WorldPos(), rand.NextDouble()); for (int i = 0; i < amount; i++) { //possibly later method to build all object in this su within the blueprint class and return a list //WorldObject wo = bp.buildObject(rand); Mesh mesh = bp.buildObject(rand.Next()); //choose random x and y position within the su float u = (float)rand.NextDouble(); float v = (float)rand.NextDouble(); //choose random rotation(will not be random for things like buildings later) Quaternion surfRot = Quaternion.Euler((float)rand.NextDouble() * 360, (float)rand.NextDouble() * 360, (float)rand.NextDouble() * 360); //the global surfaceposition of the object SurfacePos surfPos = new SurfacePos(su.side, su.u + u, su.v + v); //convert the surface position and rotation to world position and rotation Vector3 worldPos = UnitConverter.getWP(surfPos, radius, sideLength); Quaternion worldRot = getWorldRot(worldPos, surfRot, su.side); //adjust from point on sphere to correct altitude worldPos = planet.noise.altitudePos(worldPos); //build(intantiate) the actual gameobject MobileObjects wo = Build.buildObject <Rock>(worldPos, worldRot); //wo.setReferences(); wo.Render(); wo.setMesh(mesh); sh.objects.Add(wo); //add it to the surface holder list } } /*int count = rand.Next(30); * * * // MyDebug.placeMarker(UnitConverter.getWP(new SurfacePos(su.side, su.u, su.v), radius, sideLength)); * for(int i = 0; i<count; i++) * { * //Vector3 pos = new Vector3( * //choose random x and y position within the su * //Vector2 surfPos = new Vector2((float)rand.NextDouble(), (float)rand.NextDouble()); * float u = (float)rand.NextDouble(); * float v = (float)rand.NextDouble(); * * //choose random rotation(will not be random for things like buildings later) * Quaternion surfRot = Quaternion.Euler(0, (float)rand.NextDouble()*360, 0); * //Debug.Log(surfRot.eulerAngles); * //temp radius of tree used for testing * float wuRadius = 2; * //radius in world units/length of a surface unit = radius in surface units(less than 1) * float suRadius = wuRadius/suLength; * //Debug.Log("suRadius is " + suRadius); * * bool isColliding = false; * foreach(RadialCol oth in radCols) * { * //distance formula(move to struct later) * //if the distance between the two centers - their radii is less than zero, they are colliding * if(Mathf.Sqrt((oth.u-u)*(oth.u-u)+(oth.v-v)*(oth.v-v))-suRadius-oth.radius<0) * { * isColliding = true; * //Debug.Log("samwell"); * break; * } * } * //for the time being, if something is colliding, just discard it * //later it may be moved slightly or completely repositioned * if(isColliding) * { * continue; * } * * //add this obect to the radial collision list * //later, create the RadialCol object initially(replace x y and suRadius) * radCols.Add(new RadialCol(u,v,suRadius)); * * //surfacepos of the tree * SurfacePos treeSurf = new SurfacePos(su.side, su.u + u, su.v + v); * //Debug.Log (u + " " + v + " " + su.u + " " + su.v); * //convert to world unit and rotation * Vector3 worldPos = UnitConverter.getWP(treeSurf, radius, sideLength); * Quaternion worldRot = getWorldRot(worldPos, surfRot, su.side); * //Debug.Log (treeSurf+ " " + worldPos + " " + surfRot.eulerAngles + " " + worldRot); * * //adjust the pos to the correct altitude, later move to function * //worldPos = worldPos.normalized*planet.noise.getAltitude(worldPos); * worldPos = planet.noise.altitudePos(worldPos); * * //GameObject.Instantiate(tree, treeWorld, Quaternion.identity); * //build the tree object(adds it to builtobjects list and maybe eventually add it to the render list * //buildObject<TestTree>(worldPos, worldRot, sh).init(); * * //build(intantiate) the object * WorldObject wo = Build.buildObject<TestTree>(worldPos, worldRot); * wo.Render(); * sh.objects.Add(wo);//add it to the surface holder list * //wo.init();//initailize it (normally has parameters) * * }*/ /*GameObject go = Resources.Load("Test things/rottest") as GameObject; * Vector3 pos = UnitConverter.getWP(new SurfacePos(su.side, su.u+0.5f, su.v+0.5f), radius, sideLength); * Quaternion rot = getWorldRot(pos, Quaternion.identity, su.side); * * GameObject.Instantiate(go, pos, rot);*/ curSH = null; //disconnect reference to avoid possible confusion later/catch errors } //increase the worldunit count of the surface holder sh.wuCount++; }