IEnumerator MapInit() { seed = (int)Random.Range(0, 0); for (int x = 0; x < width_x; x++) { for (int z = 0; z < width_z; z++) { Vector3 pos = new Vector3(x, 0, z); float xCoord = (pos.x + seed) / waveLength; float zCoord = (pos.z + seed) / waveLength; pos.y = (int)(Mathf.PerlinNoise(xCoord, zCoord) * amplitude + groundHeightOffset); Block.Type blockType = Block.PosYWithBlockType((int)pos.y); CreateBlock(pos, true, blockType); while (pos.y > 0) { //지면 아래의 보이지 않는 블럭들을 배열에 넣는다. //실제로 객체는 만들어지지 않는다. pos.y--; blockType = Block.PosYWithBlockType((int)pos.y); CreateBlock(pos, false, blockType); } } } yield return(null); }
/// <summary> /// Sets a block in the specified position, of the specified type. Does NOT update any corners. /// <para>blockName is here for optimization - didn't want to use enum.toString() every time. The GameObject will be called "blockName x,y" with the given values.</para> /// </summary> public void setBlock(int x, int y, Block.Type blockType, string blockName = "???") { if (blockType == Block.Type.None) { if (blocks[x, y] != null) { Destroy(blocks[x, y].gameObject); blocks[x, y] = null; } return; } GameObject newBlock = new GameObject(); newBlock.name = blockName + " " + x + "," + y; newBlock.transform.SetParent(blocksObject.transform); newBlock.transform.localPosition = new Vector3(x, y); Block blockscript = newBlock.AddComponent <Block>(); blockscript.type = blockType; blockscript.init(); if (blocks[x, y] != null) { Destroy(blocks[x, y].gameObject); } blocks[x, y] = blockscript; }
private Chunk makeDefaultChunk(int chunkXcoord, int chunkYcoord) { Floor.Type typeOfFloor = Floor.Type.Asphalt; Block.Type typeOfEdgeBlock = Block.Type.wCement; string typeOfFloorName = typeOfFloor.ToString(); string typeOfBlockName = Block.toStrings[typeOfEdgeBlock]; Chunk chunk = new GameObject().AddComponent <Chunk>(); chunk.name = "Default chunk " + chunkXcoord + ", " + chunkYcoord; chunk.chunkX = chunkXcoord; chunk.chunkY = chunkYcoord; chunk.width = chunkSize; chunk.height = chunkSize; chunk.init(); chunks.Add(new global::Point(chunkXcoord, chunkYcoord), chunk); for (int x = 0; x < chunkSize; x++) { for (int y = 0; y < chunkSize; y++) { chunk.setFloor(x, y, typeOfFloor, typeOfFloorName); if (x == 0 || y == 0 || x == chunkSize - 1 || y == chunkSize - 1) { setBlock(chunkXcoord, chunkYcoord, x, y, typeOfEdgeBlock, false, typeOfBlockName); } } } return(chunk); }
public static bool Place(int x, int y, Block.Type type) { int displayX = x; int displayY = y; if (x < 0) { x = World.size * Chunk.size + x; } else if (x >= World.size * Chunk.size) { x = x - World.size * Chunk.size; } bool res; if (CanPlace(x, y, out res)) { World.GetChunk(x).AddBlock(Chunk.GetLocaleX(x), y, displayX, displayY, type); Delay.StartDelay(World.BlockTilemap, 0.3f, () => { World.UI2BlockTilemap.SetCell(x, -y + Chunk.height, -1); }, (delta, time) => { int tile = Mathf.FloorToInt(delta * 16 / time); World.UI2BlockTilemap.SetCell(x, -y + Chunk.height, tile); } ); } return(res); }
/// Ajoute un block au Chunk (coordonées locales) public void AddBlock(int x, int y, Block.Type type) { if (x < 0 || x >= size || y < 0 || y > (chunkMax - chunkMin)) { return; } blocks[x][y] = new Block(type, x + (id * size), y); DrawBlock(blocks[x][y]); }
/// Ajoute un block au Chunk (coordonées locales) public void AddBlock(int x, int y, int displayX, int displayY, Block.Type type) { if (!IsInChunk(x, y)) { throw new OutOfBoundsException2D("AddBlock", x, 0, size - 1, y, chunkMin, chunkMax); } blocks[x][y].SetType(type); DrawBlock(blocks[x][y], displayX, displayY); }
// Update is called once per frame void Update() { // Drop if (this.drop != null && !this.drop.MoveNext()) { this.drop = null; } // Dig if (Input.GetKey(KeyCode.Space) && Time.time > nextDigTime) { nextDigTime = Time.time + this.digTimeRate; this.walkButtonOn = false; Dig(); } // Walk if (this.walk != null && !this.walk.MoveNext()) { this.walk = null; Block.Type hit = blockController.Collision(this.pos, Direction.Down); if (hit == Block.Type.Empty) { DropStart(); } } this.walkButtonOn = false; if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.H)) { this.direction = Direction.Left; this.walkButtonOn = true; if (this.walk == null) { this.walk = GetWalkEnumerator(Direction.Left); } } else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.L)) { this.direction = Direction.Right; this.walkButtonOn = true; if (this.walk == null) { this.walk = GetWalkEnumerator(Direction.Right); } } else if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.K)) { this.direction = Direction.Up; } else if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.J)) { this.direction = Direction.Down; } }
public Block BlockAtPos(Vector2 pos) { Block.Type type = Collision(pos); if (type == Block.Type.Empty) { return(null); } else { int row = Row(pos.y); int col = Col(pos.x); Block block = this.fixedBlocks[row, col]; return(block); } }
void Dig() { Block.Type hit = blockController.Collision(this.pos, this.direction); Debug.Log("dig:" + this.direction + " hit:" + hit); if (hit != Block.Type.Empty) { blockController.RemoveAtPos( this.pos + BlockController.Offset[this.direction] ); if (this.direction == Direction.Down) { DropStart(); } } }
public void CreateBlock(Vector3 blockpos, bool visual, Block.Type type) { if (worldBlocks[(int)blockpos.x, (int)blockpos.y, (int)blockpos.z] != null) { //Debug.Log("이미 블록이 설치된 좌표입니다!!!"); return; } //Block.Type blockType = Block.PosYWithBlockType((int)blockpos.y); if (visual) { GameObject blockObj = (GameObject)Instantiate(blockPrefabs[(int)type], blockpos, Quaternion.identity); worldBlocks[(int)blockpos.x, (int)blockpos.y, (int)blockpos.z] = new Block(type, visual, blockObj); } else { worldBlocks[(int)blockpos.x, (int)blockpos.y, (int)blockpos.z] = new Block(type, visual, null); } }
IEnumerator GetDropEnumerator() { Block.Type hit = blockController.Collision(this.pos, Direction.Down); while (hit == Block.Type.Empty) { float gravityPerFrame = blockController.gravity * Time.deltaTime; this.pos.y += gravityPerFrame; if (blockController.Collision(this.pos, Direction.Down) != Block.Type.Empty) { break; } yield return(true); } this.pos.y = Mathf.Floor(this.pos.y); }
/// <summary> /// Sets the specified block (by chunk coordinates and local coordinates) to the specified type, updating corners if needed. /// </summary> public void setBlock(int chunkX, int chunkY, int localX, int localY, Block.Type blockType, bool updateCorners, string blockName = "???") { Chunk chunk; //If chunk is valid if (chunks.TryGetValue(new global::Point(chunkX, chunkY), out chunk)) { chunk.setBlock(localX, localY, blockType, blockName); if (updateCorners) { updateCornersStandard((int)(chunkX * chunkSize + localX), (int)(chunkY * chunkSize + localY), (int)(chunkX * chunkSize + localX), (int)(chunkY * chunkSize + localY)); } } else //attempt to set a block in a nonexistent chunk { Debug.LogError("You just made an attempt to set a block in a nonexistent chunk!"); return; } }
/// <summary> /// Update the point at the given location with a new blcok type id, and potentially a new density value /// This also updates the bit mask for all the blocks around the point being updated. /// </summary> /// <param name="location">The xyz of the point to update</param> /// <param name="blockTypeId">The new block id</param> /// <param name="densityValue">the new density value</param> /// <returns>the updated block value with bitmask included</returns> public void updateBlock(Coordinate location, Block.Type blockType, float?densityValue = null) { updateBlockType(location, blockType); if (densityValue != null) { updateBlockScalarDensity(location, (float)densityValue); } // for all the blocks around this point, update their bitmasks foreach (Octants.Octant neightboringVertexDirection in Octants.All) { Coordinate blockLocation = location - 1 + neightboringVertexDirection.Offset; //update the vertex mask to a 1 for the neighbor updateBlockVertexMask( blockLocation, neightboringVertexDirection.Reverse, Block.Types.Get(blockType.Id).IsSolid ); } }
IEnumerator CreateMeshData(MeshData meshData, ushort[] blocks, World3 pos, bool transparent) { // int[,] mask = GetMask(); // int[] x = GetInt3(); // int[] q = GetInt3(); // int[] du = GetInt3(); // int[] dv = GetInt3(); int[,] mask = new int[Chunk.Size, Chunk.Size]; int[] x = new int[3]; int[] q = new int[3]; int[] du = new int[3]; int[] dv = new int[3]; // Sweep over 3 axes, 0..2 for (int axis = 0; axis < 3; axis++) { // u and v are orthogonal directions to the main axis int u = (axis + 1) % 3; int v = (axis + 2) % 3; q[axis] = 1; // Include each side to compute outer visibility for (x[axis] = -1; x[axis] < Chunk.Size;) { // Compute mask for this face for (x[v] = 0; x[v] < Chunk.Size; x[v]++) { for (x[u] = 0; x[u] < Chunk.Size; x[u]++) { ushort front_block = Block.Null; ushort back_block = Block.Null; // Edge cases. Grab a block from the world to check visibility if (x[axis] == -1) { ushort block = Block.Null; block = World.GetBlock(new World3(pos.x + x[0], pos.y + x[1], pos.z + x[2])); Block.Type type = Blocks.GetType(block); if ((!transparent && type == Block.Type.rock) || (transparent && (type == Block.Type.glass || type == Block.Type.rock))) { front_block = block; } } if (x[axis] == Chunk.Size - 1) { ushort block = Block.Null; block = World.GetBlock(new World3(pos.x + x[0] + q[0], pos.y + x[1] + q[1], pos.z + x[2] + q[2])); Block.Type type = Blocks.GetType(block); if ((!transparent && type == Block.Type.rock) || (transparent && (type == Block.Type.glass || type == Block.Type.rock))) { back_block = block; } } // Check visibility within chunk if (0 <= x[axis] && Blocks.GetType(blocks[Chunk.BlockIndex(x[0], x[1], x[2])]) == Block.Type.rock) { front_block = blocks[Chunk.BlockIndex(x[0], x[1], x[2])]; } if (x[axis] < Chunk.Size - 1 && Blocks.GetType(blocks[Chunk.BlockIndex(x[0] + q[0], x[1] + q[1], x[2] + q[2])]) == Block.Type.rock) { back_block = blocks[Chunk.BlockIndex(x[0] + q[0], x[1] + q[1], x[2] + q[2])]; } bool maskAssigned = false; if (transparent) { if (0 <= x[axis] && Blocks.GetType(blocks[Chunk.BlockIndex(x[0], x[1], x[2])]) == Block.Type.glass) { front_block = blocks[Chunk.BlockIndex(x[0], x[1], x[2])]; } if (x[axis] < Chunk.Size - 1 && Blocks.GetType(blocks[Chunk.BlockIndex(x[0] + q[0], x[1] + q[1], x[2] + q[2])]) == Block.Type.glass) { back_block = blocks[Chunk.BlockIndex(x[0] + q[0], x[1] + q[1], x[2] + q[2])]; } Block.Type frontType = Blocks.GetType(front_block); Block.Type backType = Blocks.GetType(back_block); // if this is transparent and one block is rock and one is glass, this cannot be seen. if (frontType == Block.Type.glass && backType == Block.Type.rock || frontType == Block.Type.rock && backType == Block.Type.glass) { mask[x[u], x[v]] = 0; maskAssigned = true; } if (frontType == Block.Type.rock) { front_block = Block.Null; } if (backType == Block.Type.rock) { back_block = Block.Null; } } if (!maskAssigned) { // if both blocks are something, or both are nothing assign 0 to the mask. this cannot be seen. if ((front_block == Block.Null && back_block == Block.Null) || (front_block != Block.Null && back_block != Block.Null)) { mask[x[u], x[v]] = 0; } // the front block only is nothing else if (front_block != Block.Null) { // don't include the frontside mesh if x[axis] = -1 as this lies outside the chunk if (x[axis] >= 0) { mask[x[u], x[v]] = (int)(front_block + 1); } else { mask[x[u], x[v]] = 0; } } else { // don't include the backside mesh if x[axis] = Chunk.Size - 1 as this lies outside the chunk if (x[axis] < Chunk.Size - 1) { // The sign indicates the side the mesh is on mask[x[u], x[v]] = -(int)(back_block + 1); } else { mask[x[u], x[v]] = 0; } } } } } // Increment x[axis] x[axis]++; // Generate mesh for mask using lexicographic ordering for (int j = 0; j < Chunk.Size; j++) { for (int i = 0; i < Chunk.Size;) { // this is the block code, signed according to what side the mesh is on int block = mask[i, j]; if (block != 0) { // compute width. expand as long as the same block code is encountered in the mask int width = 1; for ( ; i + width < Chunk.Size && block == mask[i + width, j]; width++) { } // compute height. expand as long as the total height and width have the same block code bool done = false; int height = 1; for ( ; j + height < Chunk.Size; height++) { for (int k = 0; k < width; k++) { if (block != mask[i + k, j + height]) { done = true; break; } } if (done) { break; } } // Add quad x[u] = i; x[v] = j; for (int ix = 0; ix <= 2; ix++) { dv[ix] = 0; du[ix] = 0; } Block.Direction dir; if (block > 0) { dv[v] = height; du[u] = width; dir = Block.Direction.up; } else { block = -block; du[v] = height; dv[u] = width; dir = Block.Direction.down; } meshData.AddVertex(new Vector3(x[0], x[1], x[2])); meshData.AddVertex(new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2])); meshData.AddVertex(new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2])); meshData.AddVertex(new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2])); meshData.AddQuadTriangles(); meshData.uv.AddRange(Blocks.GetFaceUVs((ushort)block, dir, width, height)); if (transparent) { meshData.AddVertex(new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2])); meshData.AddVertex(new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2])); meshData.AddVertex(new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2])); meshData.AddVertex(new Vector3(x[0], x[1], x[2])); meshData.AddQuadTriangles(); meshData.uv.AddRange(Blocks.GetFaceUVs((ushort)block, dir, width, height)); } // Clear this portion of the mask for (int l = 0; l < height; l++) { for (int k = 0; k < width; k++) { mask[i + k, j + l] = 0; } } // Increment and continue i += width; } else { i++; } } } } for (int ix = 0; ix <= 2; ix++) { x[ix] = 0; q[ix] = 0; } } // ReturnInt3(x); // ReturnInt3(q); // ReturnInt3(du); // ReturnInt3(dv); // ReturnMask(mask); meshData.complete = true; yield return(null); }
/// <summary> /// Creates and returns the junction that fits a junction who's neighboring on the four input blocks, some of which can be null. /// <para>Will return null if there should be none there - which happens if none of them appear more than once.</para> /// <para>In case of ties (two Cement Walls and two Water Pools, for example), will return a junction with two children</para> /// </summary> public static Junction createJunction(Block topLeft, Block topRight, Block bottomLeft, Block bottomRight) { HashSet <Block.Type> types = new HashSet <Block.Type>(); Block.Type firstMajority = Block.Type.None; Block.Type secondMajority = Block.Type.None; Block[] array = new Block[] { topLeft, topRight, bottomLeft, bottomRight }; int numOfNeighbors = 0; foreach (Block b in array) { if (b != null) { numOfNeighbors++; if (types.Contains(b.type)) //type appears at least twice { if (firstMajority == Block.Type.None) { firstMajority = b.type; } else if (b.type != firstMajority) { //exactly 2 of two different types :( secondMajority = b.type; break; } } else { types.Add(b.type); } } } if (firstMajority == Block.Type.None) //0 or 1 junctions per type. Trivial case that will happen 70% of the time! { return(null); } if (secondMajority == Block.Type.None) //one majority. That's the easy case that will happen 29% of the time! { string shapeString = ""; //NOTE: I programmed this with "top" being the lower Y value, but Unity has it with a positive Y, so that's why the following 4 lines are bottom-to-top. shapeString += (bottomLeft == null || bottomLeft.type != firstMajority) ? "O" : "X"; shapeString += (bottomRight == null || bottomRight.type != firstMajority) ? "O" : "X"; shapeString += (topLeft == null || topLeft.type != firstMajority) ? "O" : "X"; shapeString += (topRight == null || topRight.type != firstMajority) ? "O" : "X"; Junction.Shape shape = (Junction.Shape)System.Enum.Parse(typeof(Junction.Shape), shapeString); Junction j = new GameObject().AddComponent <Junction>(); j.shape = shape; //This area of the code probably takes the most time, with all the string conversions... TODO visit this if stuff is slow string blockType = firstMajority.ToString(); if (blockType[0] == 'w') //wall { j.WallOrPool = true; } else if (blockType[0] == 'p') //pool { j.WallOrPool = false; } else { Debug.LogError("Good evening, dear sir or madam. I seem to have found a bug: This Block thing exists, but its enum type does not start with a \"p\" or a \"w\". How peculiar! Here, see for yourself: " + blockType); } j.type = (Junction.Type)System.Enum.Parse(typeof(Junction.Type), blockType.Substring(1)); j.life = ( (topLeft == null ? 0 : topLeft.life) + (topRight == null ? 0 : topRight.life) + (bottomLeft == null ? 0 : bottomLeft.life) + (bottomRight == null ? 0 : bottomRight.life) ) / numOfNeighbors; j.updateSprite(); return(j); } if (secondMajority != Block.Type.None) //This check is unnecessary. Like this stupid edge case. { //(Explanation for this case: This is what happens when two junctions need to be in the same place) string shapeString1 = ""; shapeString1 += (bottomLeft.type != firstMajority) ? "O" : "X"; shapeString1 += (bottomRight.type != firstMajority) ? "O" : "X"; shapeString1 += (topLeft.type != firstMajority) ? "O" : "X"; shapeString1 += (topRight.type != firstMajority) ? "O" : "X"; string shapeString2 = ""; foreach (char c in shapeString1) { shapeString2 += c == 'O' ? 'X' : 'O'; } Junction.Shape shape1 = (Junction.Shape)System.Enum.Parse(typeof(Junction.Shape), shapeString1); Junction.Shape shape2 = (Junction.Shape)System.Enum.Parse(typeof(Junction.Shape), shapeString2); Junction favoriteChild = new GameObject().AddComponent <Junction>(); string blockType1 = firstMajority.ToString(); if (blockType1[0] == 'w') { favoriteChild.WallOrPool = true; } else if (blockType1[0] == 'p') { favoriteChild.WallOrPool = false; } favoriteChild.type = (Junction.Type)System.Enum.Parse(typeof(Junction.Type), blockType1.Substring(1)); favoriteChild.shape = shape1; Junction theOtherFuckingChild = new GameObject().AddComponent <Junction>(); string blockType2 = secondMajority.ToString(); if (blockType2[0] == 'w') { theOtherFuckingChild.WallOrPool = true; } else if (blockType2[0] == 'p') { theOtherFuckingChild.WallOrPool = false; } theOtherFuckingChild.type = (Junction.Type)System.Enum.Parse(typeof(Junction.Type), blockType2.Substring(1)); theOtherFuckingChild.shape = shape2; //make their lifes correct favoriteChild.life = 0; theOtherFuckingChild.life = 0; if (bottomLeft.type == firstMajority) { favoriteChild.life += bottomLeft.life; } else { theOtherFuckingChild.life += bottomLeft.life; } if (bottomRight.type == firstMajority) { favoriteChild.life += bottomRight.life; } else { theOtherFuckingChild.life += bottomRight.life; } if (topLeft.type == firstMajority) { favoriteChild.life += topLeft.life; } else { theOtherFuckingChild.life += topLeft.life; } if (topRight.type == firstMajority) { favoriteChild.life += topRight.life; } else { theOtherFuckingChild.life += topRight.life; } favoriteChild.life /= 2; //average theOtherFuckingChild.life /= 2; // favoriteChild.updateSprite(); theOtherFuckingChild.updateSprite(); Junction sadMom = new GameObject().AddComponent <Junction>(); sadMom.shape = Junction.Shape.Fat; // :( sadMom.WallOrPool = false; //Irrelevant sadMom.type = Junction.Type.Sad; // :( favoriteChild.transform.SetParent(sadMom.transform); theOtherFuckingChild.transform.SetParent(sadMom.transform); theOtherFuckingChild.transform.SetAsLastSibling(); //Hmph! favoriteChild.name = "favorite child"; theOtherFuckingChild.name = "that other f*****g child"; return(sadMom); } //WON'T HAPPEN return(null); }
public SavedTile(Transform tile, ParticleSystem particleSystem, Block.Type blockType) { this.tile = tile; this.particleSystem = particleSystem; this.blockType = blockType; }
IEnumerator GetWalkEnumerator(Direction d) { this.direction = d; switch (d) { case Direction.Left: if (this.pos.x < 1) { yield break; } break; case Direction.Right: if (this.pos.x > blockController.numBlockCols - 2) { yield break; } break; default: yield break; } Vector2 offset = Vector2.zero; if (this.drop != null) { offset.y += 1; } Block.Type hit = blockController.Collision(this.pos + offset, d); if (hit != Block.Type.Empty) { // いちだんうえにあがれるか Block.Type upperHit = blockController.Collision( this.pos + offset, Direction.Up ); Block.Type nextUpperHit = blockController.Collision( this.pos + offset + BlockController.Offset[d], Direction.Up ); if (upperHit == Block.Type.Empty && (nextUpperHit == Block.Type.Empty)) { float beforeWait = Time.time; while (Time.time - beforeWait < this.walkToUpperWait) { if (!walkButtonOn) { yield break; } yield return(true); } this.pos.y -= 1; } else { yield break; } } float walkFrom = this.pos.x; int sign = (d == Direction.Left ? -1 : 1); float walkTotal = 0; while (walkTotal < 0.9f) { float speedPerFrame = this.walkSpeed * Time.deltaTime; this.pos.x += speedPerFrame * sign; walkTotal += speedPerFrame; yield return(true); } this.pos.x = walkFrom + sign; }
/// <summary> /// Helper function to set just the id of a block at a given location /// </summary> /// <param name="location">the x,y,z of the block to set</param> /// <param name="blockType">The new block id</param> protected void updateBlockType(Coordinate location, Block.Type blockType) { setBlock(location, getBlock(location).SetBlockTypeId(blockType.Id)); }