//returns the large unit at a specified su, creates one if it does not exist(every large unit will exist) public TULarge getLarge(SurfaceUnit su) { //quick hopefully temporary check, see getMid for details if (su.u < -halfgtuw || su.u >= halfgtuw || su.v < -halfgtuw || su.v >= halfgtuw) { return(null); } TULarge lu = null; //if it is in the list, return it if (largeTUs.TryGetValue(su, out lu)) { return(lu); } //if not, build one and return it TULarge tu = new TULarge(); //get this large unit's rng tu.rng = RandomHandler.transportRandom(su, TLev.LARGE); tu.conPoint = new Vector2((su.u + (float)tu.rng.NextDouble()) * sideLengthLarge, (su.v + (float)tu.rng.NextDouble()) * sideLengthLarge); tu.conUp = true; tu.conRight = true; tu.indexI = su.u; tu.indexJ = su.v; largeTUs.Add(su, tu); return(tu); }
//returns the mid unit at the specified su or null if one does not exist public TransportUnit getMid(SurfaceUnit su) { //quick check to see if this mid is out of range on the side //later it will be transformed into a unit of other side in order to connect sides if (su.u < -halfmidperglob || su.u >= halfmidperglob || su.v < -halfmidperglob || su.v >= halfmidperglob) { return(null); } TransportUnit mu = null; //if it is in the mid list, return it if (midTUs.TryGetValue(su, out mu)) { return(mu); } //if it's not in the mid list, check if a large unit will contain it //the coordinates of the proposed large unit SurfaceUnit lus = getLargeSU(su); //retrieve the large unit TULarge lu = getLarge(lus); //Debug.Log("proposed " + lus); //if the lu has already been populated, the mu will never exist, so return null if (lu.populated) { return(null); } else { populateLarge(lu, lus); //populate it with mid units(later will be moved to a separate function) /* int startu = lus.u*largeTUWidth; * int startv = lus.v*largeTUWidth; * //loop through all mid units in the large unit and create them * for(int i = startu; i<startu+largeTUWidth; i++) * { * for(int j = startv; j<startv+largeTUWidth; j++) * { * //create a new base unit, set its properties, and add it to the base list * TransportUnit newTU = new TransportUnit(); * newTU.conUp = true;//Random.value>0.5f; * newTU.conRight = true;//Random.value>0.5f; * newTU.indexI = i; * newTU.indexJ = j; * newTU.conPoint = new Vector2((i+0.5f)*midTUWidth + Random.value-0.5f,(j+0.5f)*midTUWidth + Random.value-0.5f); * //newTU.conPoint = new Vector2((i+0.5f)*midTUWidth,(j+0.5f)*midTUWidth); * //newTU.conPoint = new Vector2((i+Random.value)*midTUWidth,(j+Random.value)*midTUWidth); * midTUs.Add(new SurfaceUnit(su.side, i, j), newTU); * } * }*/ lu.populated = true; //use recursion to return to the top of the function and return the newly created(or not) mid unit return(getMid(su)); } }
//builds a street from the center of a large unit to the edge in the given direction private void buildMidCurve(TULarge lu, Vector2 outsideConPoint, Dir dir, TransportUnit powMid, PSide side) //powmid is the mid unit that contains the large's conpoint { int gix = 0, giy = 0; //goal index x and y of the goal mid unit float outSlope = GridMath.findSlope(lu.conPoint, outsideConPoint); //find the average slope from this conPoint to the outsideConPoint Debug.DrawLine(UnitConverter.getWP(new SurfacePos(PSide.TOP, lu.conPoint.x, lu.conPoint.y), 10000, sideLength), UnitConverter.getWP(new SurfacePos(PSide.TOP, outsideConPoint.x, outsideConPoint.y), 10000, sideLength), Color.blue, Mathf.Infinity); //determine the goal mid unit if (dir == Dir.RIGHT) { //find the index of the goal mid unit float goalPosX = (lu.indexI + 1) * sideLengthLarge; //the x value of the very right side of the large unit in mid units float goalPosY = GridMath.findY(goalPosX, lu.conPoint, outSlope); //the y value on the line between teh two conpoints GridMath.findMidIndexfromPoint(new Vector2(goalPosX - 0.5f, goalPosY), midTUWidth, out gix, out giy); TransportUnit goalMid = buildMid(gix, giy, side); goalMid.conRight = true; goalMid.RightLev = 1; //Debug.DrawLine(UnitConverter.getWP(new SurfacePos(PSide.TOP, lu.conPoint.x, lu.conPoint.y), 10000, 1024), // UnitConverter.getWP(new SurfacePos(PSide.TOP, goalPosX, goalPosY), 10000, 1024), Color.blue, Mathf.Infinity); } else if (dir == Dir.LEFT) { //find the index of the goal mid unit float goalPosX = (lu.indexI) * sideLengthLarge; //the x value of the very right side of the large unit in mid units float goalPosY = GridMath.findY(goalPosX, lu.conPoint, outSlope); //the y value on the line between teh two conpoints GridMath.findMidIndexfromPoint(new Vector2(goalPosX + 0.5f, goalPosY), midTUWidth, out gix, out giy); //buildMid(gix, giy, side).conLeft=true; } else if (dir == Dir.UP) { //find the index of the goal mid unit float goalPosY = (lu.indexJ + 1) * sideLengthLarge; //the x value of the very right side of the large unit in mid units float goalPosX = GridMath.findX(goalPosY, lu.conPoint, outSlope); //the y value on the line between teh two conpoints GridMath.findMidIndexfromPoint(new Vector2(goalPosX, goalPosY - 0.5f), midTUWidth, out gix, out giy); TransportUnit goalMid = buildMid(gix, giy, side); goalMid.conUp = true; goalMid.UpLev = 1; } else if (dir == Dir.DOWN) { //find the index of the goal mid unit float goalPosY = (lu.indexJ) * sideLengthLarge; //the x value of the very right side of the large unit in mid units float goalPosX = GridMath.findX(goalPosY, lu.conPoint, outSlope); //the y value on the line between teh two conpoints GridMath.findMidIndexfromPoint(new Vector2(goalPosX, goalPosY + 0.5f), midTUWidth, out gix, out giy); } //the x and y index of the mid unit last created in the loop(starts as if pows were last created) //int lastix = powIndexX, lastiy = powIndexY; TransportUnit lastMid = powMid; while (true) { //the difference in indexes between the current and goal mid units int xdif = gix - lastMid.indexI; int ydif = giy - lastMid.indexJ; //the direction to move in this loop iteration(1=x 2=y) int movedir; //if they are both not on the goal index, pick a random one to change if (xdif != 0 && ydif != 0) { movedir = lu.rng.NextDouble() > 0.5 ? 1:2; } else if (xdif != 0) { movedir = 1; } else if (ydif != 0) { movedir = 2; } else //if they are both zero we are done maybe? { break; //? } //the index of the mid unit to be created int curix = lastMid.indexI, curiy = lastMid.indexJ; //if moving in the x direction if (movedir == 1) { if (xdif > 0) { curix++; } else { curix--; } } else //movedir==2 { if (ydif > 0) { curiy++; } else { curiy--; } } //create or retrieve the new mid unit TransportUnit curMid = buildMid(curix, curiy, side); //set its conpoint if it has not already been set curMid.setConPoint(new Vector2((curix + (float)lu.rng.NextDouble()) * midTUWidth, (curiy + (float)lu.rng.NextDouble()) * midTUWidth)); //MyDebug.placeMarker(UnitConverter.getWP(new SurfacePos(PSide.TOP, curMid.conPoint.x, curMid.conPoint.y), 10000, 1024), 5); connectUnits(curMid, lastMid, 1); lastMid = curMid; } }
//builds a level 2 street of length from startMid within curLarge transport unit private void buildLev2(TULarge curLarge, TransportUnit startMid, int length, PSide side) { //the max and min indexes that the street can be built to(stay within the large unit) //move out of this function so it is not recalculated every time int maxI = (curLarge.indexI + 1) * largeTUWidth - 1; int minI = (curLarge.indexI) * largeTUWidth; int maxJ = (curLarge.indexJ + 1) * largeTUWidth - 1; int minJ = (curLarge.indexJ) * largeTUWidth; //the last mid unit to build away from TransportUnit lastMid = startMid; Dir lastDir; for (int i = 0; i < length; i++) { //the direction to build //NOTE: modify later to not build back from the same direction Dir dir = (Dir)(curLarge.rng.Next(1, 5)); //the index of the new mid unit to modify int curix = lastMid.indexI; int curiy = lastMid.indexJ; if (dir == Dir.RIGHT) { curix++; if (curix > maxI) { lastMid.conRight = true; lastMid.RightLev = 2; break; } } if (dir == Dir.LEFT) { curix--; if (curix < minI) { break; } } if (dir == Dir.UP) { curiy++; if (curiy > maxJ) { lastMid.conUp = true; lastMid.UpLev = 2; break; } } if (dir == Dir.DOWN) { curiy--; if (curiy < minJ) { break; } } //build (or just retrieve) the mid unit at the new indexes TransportUnit curMid = buildMid(curix, curiy, side); //set its conpoint if it has not already been set curMid.setConPoint(new Vector2((curix + (float)curLarge.rng.NextDouble()) * midTUWidth, (curiy + (float)curLarge.rng.NextDouble()) * midTUWidth)); //MyDebug.placeMarker(UnitConverter.getWP(new SurfacePos(PSide.TOP, curMid.conPoint.x, curMid.conPoint.y), 10000, 1024), 10); //connect on level 2 connectUnits(curMid, lastMid, 2); lastMid = curMid; } }
//populates a large unit with mid units private void populateLarge(TULarge lu, SurfaceUnit lus) { //Debug.Log("built " + lus); //clear the index list indexList.Clear(); //find the mid unit that the large unit's conpoint falls in int powIndexX, powIndexY; GridMath.findMidIndexfromPoint(lu.conPoint, midTUWidth, out powIndexX, out powIndexY); TransportUnit powMid = buildMid(powIndexX, powIndexY, lus.side); powMid.conPoint = lu.conPoint; //same conpoint, or could change to not be, doesn't really matter powMid.conSet = true; TULarge rightLU = getLarge(new SurfaceUnit(lus.side, lus.u + 1, lus.v)); TULarge leftLU = getLarge(new SurfaceUnit(lus.side, lus.u - 1, lus.v)); TULarge upLU = getLarge(new SurfaceUnit(lus.side, lus.u, lus.v + 1)); TULarge downLU = getLarge(new SurfaceUnit(lus.side, lus.u, lus.v - 1)); //Vector2 conPointRight = rightLU.conPoint; //determine in which direction the streets should be built bool conRight = lu.conRight; bool conLeft = false; bool conUp = lu.conUp; bool conDown = false; //check for null large units if (leftLU != null) { conLeft = leftLU.conRight; } if (downLU != null) { conDown = downLU.conUp; } //list of the index of all the mid transport units that are connected in some way if (conRight) { buildMidCurve(lu, rightLU.conPoint, Dir.RIGHT, powMid, lus.side); } if (conLeft) { buildMidCurve(lu, leftLU.conPoint, Dir.LEFT, powMid, lus.side); } if (conUp) { buildMidCurve(lu, upLU.conPoint, Dir.UP, powMid, lus.side); } if (conDown) { buildMidCurve(lu, downLU.conPoint, Dir.DOWN, powMid, lus.side); } //build some level 2 streets coming off the level 1 streets or other level 2 streets int numStreets = 80; //(int)(Random.value*5); for (int i = 0; i < numStreets; i++) { int startNum = lu.rng.Next(0, indexList.Count); TransportUnit startMid = indexList[startNum]; buildLev2(lu, startMid, lu.rng.Next(2, 80), lus.side); } Vector3 topright = UnitConverter.getWP(new SurfacePos(lus.side, (lu.indexI + 1) * sideLengthLarge, (lu.indexJ + 1) * sideLengthLarge), 10000, sideLength); Vector3 topleft = UnitConverter.getWP(new SurfacePos(lus.side, (lu.indexI) * sideLengthLarge, (lu.indexJ + 1) * sideLengthLarge), 10000, sideLength); Vector3 botright = UnitConverter.getWP(new SurfacePos(lus.side, (lu.indexI + 1) * sideLengthLarge, (lu.indexJ) * sideLengthLarge), 10000, sideLength); Vector3 botleft = UnitConverter.getWP(new SurfacePos(lus.side, (lu.indexI) * sideLengthLarge, (lu.indexJ) * sideLengthLarge), 10000, sideLength); Debug.DrawLine(topleft, botleft, Color.red, Mathf.Infinity); Debug.DrawLine(topleft, topright, Color.red, Mathf.Infinity); Debug.DrawLine(topright, botright, Color.red, Mathf.Infinity); Debug.DrawLine(botright, botleft, Color.red, Mathf.Infinity); lu.populated = true; }