protected void CreateNote(NoteObject note, TileGrid tileGrid) { for (int x = 0; x < tileGrid.Columns; x++) { for (int y = 0; y < tileGrid.Rows; y++) { if (tileGrid.Get(x, y) != null && tileGrid.Get(x, y) is WallTile) { if (tileGrid.Get(x + 1, y) is PathTile) { note.Position = tileGrid.Get(x, y).Position + new Vector3(102 /*100+modelDepth*/, 0, 0); } else if (tileGrid.Get(x, y + 1) is PathTile) { note.Position = tileGrid.Get(x, y).Position + new Vector3(0, 0, 102); } else if (tileGrid.Get(x - 1, y) is PathTile) { note.Position = tileGrid.Get(x, y).Position - new Vector3(102, 0, 0); } else if (tileGrid.Get(x, y - 1) is PathTile) { note.Position = tileGrid.Get(x, y).Position - new Vector3(0, 0, 102); } } } } }
void FindLinkedDoors() { var thisPosition = m_cTransform.position; var thisIndex = new Vector2Int((int)thisPosition.x, (int)thisPosition.y); //Indexes to look for. var rightIndex = thisIndex + Vector2Int.right; var leftIndex = thisIndex + Vector2Int.left; var upIndex = thisIndex + Vector2Int.up; var downIndex = thisIndex + Vector2Int.down; //Save the elements so we don't have to keep finding them. var rightElement = m_TileGrid.Get(rightIndex); var leftElement = m_TileGrid.Get(leftIndex); var upElement = m_TileGrid.Get(upIndex); var downElement = m_TileGrid.Get(downIndex); //Find right... if (rightElement.m_Type == TileType.DOOR && rightElement.m_TileColor == m_ColorCode.m_TileColor) { var doorTileLogic = rightElement.m_GameObject.GetComponent <DoorTileLogic>(); var createdDoor = doorTileLogic.GetCreatedDoor(); m_LinkedDoorRight = createdDoor.GetComponent <DoorLogic>(); } //Find left... if (leftElement.m_Type == TileType.DOOR && leftElement.m_TileColor == m_ColorCode.m_TileColor) { var doorTileLogic = leftElement.m_GameObject.GetComponent <DoorTileLogic>(); var createdDoor = doorTileLogic.GetCreatedDoor(); m_LinkedDoorLeft = createdDoor.GetComponent <DoorLogic>(); } //Find up... if (upElement.m_Type == TileType.DOOR && upElement.m_TileColor == m_ColorCode.m_TileColor) { var doorTileLogic = upElement.m_GameObject.GetComponent <DoorTileLogic>(); var createdDoor = doorTileLogic.GetCreatedDoor(); m_LinkedDoorUp = createdDoor.GetComponent <DoorLogic>(); } //Find down... if (downElement.m_Type == TileType.DOOR && downElement.m_TileColor == m_ColorCode.m_TileColor) { var doorTileLogic = downElement.m_GameObject.GetComponent <DoorTileLogic>(); var createdDoor = doorTileLogic.GetCreatedDoor(); m_LinkedDoorDown = createdDoor.GetComponent <DoorLogic>(); } }
// Does the actual work of setting up the outline. // - Vector2Int index: the index of the tile being set up // - bool setUpNeighbors: whether this function should also be called // on this tile's neighbors void SetupHelper(Vector2Int index, bool setUpNeighbors) { // Note: there are some redundancies throughout this process, mostly // in cases where avoiding them would be a huge hassle resulting in // code that's much more difficult to read. Nothing about this algorithm // is particularly computationally expensive, so it's unlikely that // any benefit would be gained at all from "fixing" these redundancies. var code = 0; // This code will be the index to use to retrieve the appropriate // outline sprite from the appropriate dictionary. Each bit in this // code corresponds to a portion of the outline, either a corner or // an edge: // // 2----5----1 // | | // 6 4 // | | // 3----7----0 // // The code starts out at 0 (indicating no outline at all), but its // bits are turned on based on various checks to determine whether // that part of the outline should be active. // A code of 0 is a suitable default for an ordinary square, but // non-square tiles, such as diagonal slopes, should have different // starting bit patterns. // // If other tile shapes are added later, this system should accommodate // them properly, but additional ASCII drawings should be added as well. // For now, the drawings here will reflect only the shapes that we // already have. // No solid right means either // + +-+ // |\ or |/ // +-+ + if (!m_SolidRight) { // + if (m_SolidDown) // |\ { code |= 0b00000001; // +-0 <- set this bit } if (m_SolidUp) // +-1 <- set this bit { code |= 0b00000010; // |/ } } // + // No solid up means either // + + // /| or |\ // +-+ +-+ if (!m_SolidUp) { // 1 <- set this bit if (m_SolidRight) // /| { code |= 0b00000010; // +-+ } if (m_SolidLeft) // set this bit -> 2 { code |= 0b00000100; // |\ } } // +-+ // No solid left means either // +-+ + // \| or /| // + +-+ if (!m_SolidLeft) { // set this bit -> 2-+ if (m_SolidUp) // \| { code |= 0b00000100; // + } if (m_SolidDown) // + { code |= 0b00001000; // /| } } // set this bit -> 3-+ // No solid down means either // +-+ +-+ // |/ or \| // + + if (!m_SolidDown) { // +-+ if (m_SolidLeft) // |/ { code |= 0b00001000; // set this bit -> 3 } if (m_SolidRight) // +-+ { code |= 0b00000001; // \| } } // 1 <- set this bit // So far, all the setup we've done to prepare the code value has been based // on data present on this object itself, but now it's time to start looking // at our neighbors. // First we compute indices for all the neighboring grid elements var rdI = index + Vector2Int.right + Vector2Int.down; var ruI = index + Vector2Int.right + Vector2Int.up; var luI = index + Vector2Int.left + Vector2Int.up; var ldI = index + Vector2Int.left + Vector2Int.down; var rI = index + Vector2Int.right; var uI = index + Vector2Int.up; var lI = index + Vector2Int.left; var dI = index + Vector2Int.down; // Then we get the elements themselves from those indices var rd = s_TileGrid.Get(rdI); var ru = s_TileGrid.Get(ruI); var lu = s_TileGrid.Get(luI); var ld = s_TileGrid.Get(ldI); var r = s_TileGrid.Get(rI); var u = s_TileGrid.Get(uI); var l = s_TileGrid.Get(lI); var d = s_TileGrid.Get(dI); // Then we grab all the SolidEdgeOutliners of those elements, if any var rdO = rd.GetComponent <SolidEdgeOutliner>(); var ruO = ru.GetComponent <SolidEdgeOutliner>(); var luO = lu.GetComponent <SolidEdgeOutliner>(); var ldO = ld.GetComponent <SolidEdgeOutliner>(); var rO = r.GetComponent <SolidEdgeOutliner>(); var uO = u.GetComponent <SolidEdgeOutliner>(); var lO = l.GetComponent <SolidEdgeOutliner>(); var dO = d.GetComponent <SolidEdgeOutliner>(); // Now we get references to the PathMover components of each element, if any. // Outliners will treat objects with different paths as if they have // different outliner indices var pm = GetComponent <PathMover>(); var rdP = rd.GetComponent <PathMover>(); var ruP = ru.GetComponent <PathMover>(); var luP = lu.GetComponent <PathMover>(); var ldP = ld.GetComponent <PathMover>(); var rP = r.GetComponent <PathMover>(); var uP = u.GetComponent <PathMover>(); var lP = l.GetComponent <PathMover>(); var dP = d.GetComponent <PathMover>(); // Now that we have each neighboring outliner, we can proceed. The // overall idea here is that a bit should be set if the neighbor in the // corresponding direction is either not solid "toward" this tile, or the // equivalent thereof (e.g., it's null, etc.). Beyond that, experimentation // has revealed that there are a handful of additional conditions that // warrant turning on a bit, and those are checked here as well. // // Additionally, after looking at each neighbor and potentially modifying the // code value based on it, we also need to call SetupHelper on that neighbor // so that it has a chance to make its outline look right based on this tile // that is now being set up. Of course, in this case, SetupHelper is called // with its own setUpNeighbors flag false, so that we don't set this tile up // again and then set up the neighbor again and so on infinitely. // // A recent addition to this system adds the m_OutlineIndex property. If a // neighboring tile's outliner has a different outline index from this one's, // then it is not considered solid toward this tile. // // Finally, the newest change is that the outliner also takes the PathMover // component into account when deciding how to outline areas. If two objects // do not have the same path, then they are not outlined together // +----+..... // |this| rO . // +----+..... // . dO .rdO . // ........... if (rdO == null || rdO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, rdP) || rdO.m_BeingErased || (!rdO.m_SolidLeft || !rdO.m_SolidUp) || (rO != null && rO.m_OutlineIndex == m_OutlineIndex && rO.m_SolidLeft && !rO.m_SolidDown) || (dO != null && dO.m_OutlineIndex == m_OutlineIndex && dO.m_SolidUp && !dO.m_SolidRight)) { code |= 0b00000001; } // Set up rdO if appropriate else if (rdO != null && setUpNeighbors) { rdO.SetupHelper(rdI, false); } // ........... // . uO .ruO . // +----+..... // |this| rO . // +----+..... if (ruO == null || ruO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, ruP) || ruO.m_BeingErased || (!ruO.m_SolidLeft || !ruO.m_SolidDown) || (rO != null && rO.m_OutlineIndex == m_OutlineIndex && rO.m_SolidLeft && !rO.m_SolidUp) || (uO != null && uO.m_OutlineIndex == m_OutlineIndex && uO.m_SolidDown && !uO.m_SolidRight)) { code |= 0b00000010; } // Set up ruO if appropriate else if (ruO != null && setUpNeighbors) { ruO.SetupHelper(ruI, false); } // ........... // .luO . uO . // .....+----+ // . lO |this| // .....+----+ if (luO == null || luO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, luP) || luO.m_BeingErased || (!luO.m_SolidRight || !luO.m_SolidDown) || (lO != null && lO.m_OutlineIndex == m_OutlineIndex && lO.m_SolidRight && !lO.m_SolidUp) || (uO != null && uO.m_OutlineIndex == m_OutlineIndex && uO.m_SolidDown && !uO.m_SolidLeft)) { code |= 0b00000100; } // Set up luO if appropriate else if (luO != null && setUpNeighbors) { luO.SetupHelper(luI, false); } // .....+----+ // . lO |this| // .....+----+ // .ldO . dO . // ........... if (ldO == null || ldO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, ldP) || ldO.m_BeingErased || (!ldO.m_SolidRight || !ldO.m_SolidUp) || (lO != null && lO.m_OutlineIndex == m_OutlineIndex && lO.m_SolidRight && !lO.m_SolidDown) || (dO != null && dO.m_OutlineIndex == m_OutlineIndex && dO.m_SolidUp && !dO.m_SolidLeft)) { code |= 0b00001000; } // Set up ldO if appropriate else if (ldO != null && setUpNeighbors) { ldO.SetupHelper(ldI, false); } // +----+..... // |this| rO . // +----+..... if (rO == null || rO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, rP) || rO.m_BeingErased || !rO.m_SolidLeft) { code |= 0b00010011; } // Set up rO if appropriate else if (rO != null && setUpNeighbors) { rO.SetupHelper(rI, false); } // ...... // . uO . // +----+ // |this| // +----+ if (uO == null || uO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, uP) || uO.m_BeingErased || !uO.m_SolidDown) { code |= 0b00100110; } // Set up uO if appropriate else if (uO != null && setUpNeighbors) { uO.SetupHelper(uI, false); } // .....+----+ // . lO |this| // .....+----+ if (lO == null || lO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, lP) || lO.m_BeingErased || !lO.m_SolidRight) { code |= 0b01001100; } // Set up lO if appropriate else if (lO != null && setUpNeighbors) { lO.SetupHelper(lI, false); } // +----+ // |this| // +----+ // . dO . // ...... if (dO == null || dO.m_OutlineIndex != m_OutlineIndex || !PathMover.SamePath(pm, dP) || dO.m_BeingErased || !dO.m_SolidUp) { code |= 0b10001001; } // Set up dO if appropriate else if (dO != null && setUpNeighbors) { dO.SetupHelper(dI, false); } // Now we're done with our neighbors, and it's time for more // introspection. We're going to be turning bits off this time. A // slope tile without a solid top, for example, should certainly // not have the top of its outline drawn, regardless of what's // going on with its neighbors. We also want to turn corner bits // off for similar reasons. // // Here's this diagram, once again: // // 2----5----1 // | | // 6 4 // | | // 3----7----0 if (!m_SolidRight) // No solid right means turn off bit 4 { code &= ~(0b00010000); if (!m_SolidDown) // No solid right && no solid down means turn off bit 0 { code &= ~(0b00000001); } if (!m_SolidUp) // No solid right && no solid up means turn off bit 1 { code &= ~(0b00000010); } } if (!m_SolidUp) // No solid up means turn off bit 5 { code &= ~(0b00100000); if (!m_SolidRight) // No solid up && no solid right means turn off bit 1 { code &= ~(0b00000010); } if (!m_SolidLeft) // No solid up && no solid left means turn off bit 2 { code &= ~(0b00000100); } } if (!m_SolidLeft) // No solid left means turn off bit 6 { code &= ~(0b01000000); if (!m_SolidUp) // No solid left && no solid up means turn off bit 2 { code &= ~(0b00000100); } if (!m_SolidDown) // No solid left && no solid down means turn off bit 3 { code &= ~(0b00001000); } } if (!m_SolidDown) // No solid down means turn off bit 7 { code &= ~(0b10000000); if (!m_SolidLeft) // No solid down && no solid left means turn off bit 3 { code &= ~(0b00001000); } if (!m_SolidRight) // No solid down && no solid right means turn off bit 0 { code &= ~(0b00000001); } } // Oookay. One last bit of potential code manipulation: // // The outline on every tile is an interior stroke -- that is, // it doesn't spill out of the visible area of the tile itself. // (This is true whether it's a solid square tile or any other // shape.) // // Now, the placement of the outline pixels within the sprites // themselves is in most cases entirely determinable by the // bits that have been set, and thus by the code value // determined thereby; that is, in a slope tile with, say, bits // 0, 1, 3, and 4, set, it unambiguously specifies the shape: // // + // / | // / | // + + // // However, when the bits get set like this: // // + + // / or \ // / \ // + + // // ...is this a ceiling? Or is it a floor? You can't tell by // the code bits alone (unlike in any other case). And it // matters, because the outline pixels of the slope part of a // ceiling slope tile are not in the same part of the sprite // as the outline pixels of the slope part of a floor slope. // // So, to handle this situation, which comes about only when // this is a slope tile where no bits got set in checking // neighbors (and no bits got cleared afterward), we determine // whether this is a ceiling tile based on the solidity flags // and then use the special code value of -1 if it's a ceiling. // So, to recap all of that: // IF: // - it's a slope tile, determined opposite sides having // opposite solidities, AND // - it's a ceiling slope, determined by the top being // solid, AND // - the code value is unmodified from its initial state, // so it's either 0000 0101 or 0000 1010, // THEN: // - we set the code to be the special code value of -1. if (m_SolidUp && !m_SolidDown && m_SolidRight != m_SolidLeft && (code == 0b00000101 || code == 0b00001010)) { code = -1; } // Now that all of the fuss about the code is through, it's // time to interpret it and use it to get the appropriate // sprite for the outline renderer. // First of all, if the code is 0, then there's no outline // at all, and so we should just turn the damn thing off if (code == 0) { m_SpriteRenderer.enabled = false; } else { // Otherwise, the renderer should be enabled m_SpriteRenderer.enabled = true; // We'll use the solidity flags to determine which dictionary // to look in to find the correct outline sprite Dictionary <int, Sprite> sprites = null; // If all four sides are solid, then it's a square if (m_SolidRight && m_SolidUp && m_SolidLeft && m_SolidDown) { sprites = s_SquareSprites; } // Otherwise, if opposite sides have opposite solidities, // then it's one of the two kinds of slope tile else if (m_SolidRight != m_SolidLeft && m_SolidUp != m_SolidDown) { // If the right side has the same solidity as the bottom, // then it's a left-down-to-right-up slope if (m_SolidRight == m_SolidDown) { sprites = s_LDtoRUSlopeSprites; } // Otherwise, it's a left-up-to-right-down slope else { sprites = s_LUtoRDSlopeSprites; } } // Finally, we index the chosen dictionary and assign the // sprite we get from it to the outline renderer. m_SpriteRenderer.sprite = sprites[code]; } }
/// <summary> /// Creating/generating the level itself /// </summary> /// <param name="roomNumber">The number of the room</param> /// <param name="tiles">The size the Mainpath should be, counted in tiles</param> /// <param name="chased">Whether or not the monster is chasing the player</param> public RandomLevel(int roomNumber, int tiles = 12, bool chased = false, int noteID = 0) { //Setting a boolean for the monster this.chased = chased; //Assining the variables tileList = new Dictionary <Point, Tile>(); keyList = new List <Point>(); random = GameEnvironment.Random; //Select the tiles to use int pathType = random.Next(4); if (pathType < 9) { pathID = "0" + (pathType + 1); } else { pathID = "" + (pathType + 1); } int wallType = random.Next(4); if (wallType < 9) { wallID = "0" + (wallType + 1); } else { pathID = "" + (wallType + 1); } newTile = new EntryTile(pathID); this.tiles = tiles; //Create the startpoint position = Point.Zero; tileList.Add(position, newTile); keyList.Add(position); //Creating the paths CreateMainPath(); for (int i = random.Next(1, (int)Math.Pow(tiles, 2 / 3)); i > 0; i--) { CreateSidePath(random.Next(3, 15), chased); } //making the tile grid TileGrid tileGrid = Grid; gameObjects.Add(tileGrid); //making the player player = new Player(Vector3.Zero); gameObjects.Add(player); player.Parent = this; player.LoadContent(); foreach (GameObject obj in tileGrid.Objects) { if (obj != null) { if (obj.ID == "EntryTile") { player.Position = new Vector3(obj.Position.X, obj.Position.Y + GameObjectGrid.CellHeight, obj.Position.Z); foreach (GameObject tile in tileGrid.Objects) { if (tile != null) { if (tile.Position.X == obj.Position.X + 200 && tile.Position.Z == obj.Position.Z && tile.ID == "PathTile") { player.viewAngleX = 0f; } if (tile.Position.X == obj.Position.X && tile.Position.Z == obj.Position.Z + 200 && tile.ID == "PathTile") { player.viewAngleX = (float)(Math.PI / 2); } if (tile.Position.X == obj.Position.X - 200 && tile.Position.Z == obj.Position.Z && tile.ID == "PathTile") { player.viewAngleX = (float)(Math.PI); } if (tile.Position.X == obj.Position.X && tile.Position.Z == obj.Position.Z - 200 && tile.ID == "PathTile") { player.viewAngleX = (float)(Math.PI * 1.5); } } } } } } //Adding decoration objects TileGrid grid = Find("TileGrid") as TileGrid; for (int x = 0; x < grid.Columns; x++) { for (int y = 0; y < grid.Rows; y++) { if (grid.Get(x, y) != null) { if (grid.Get(x, y).ID == "WallTile" && GameEnvironment.Random.Next(15) == 0) { try { if (grid.Get(x + 1, y) != null && grid.Get(x + 1, y).ID == "PathTile" && grid.Get(x + 1, y).ID != "DecorationTile") { AddDecoration(grid.Get(x, y).Position, new Vector3(-1, 0, 0)); grid.Add(new DecorationTile(pathID), x + 1, y); } else if (grid.Get(x, y + 1) != null && grid.Get(x, y + 1).ID == "PathTile" && grid.Get(x, y + 1).ID != "DecorationTile") { AddDecoration(grid.Get(x, y).Position, new Vector3(0, 0, -1)); grid.Add(new DecorationTile(pathID), x, y + 1); } else if (grid.Get(x - 1, y) != null && grid.Get(x - 1, y).ID == "PathTile" && grid.Get(x - 1, y).ID != "DecorationTile") { AddDecoration(grid.Get(x, y).Position, new Vector3(1, 0, 0)); grid.Add(new DecorationTile(pathID), x - 1, y); } else if (grid.Get(x, y - 1) != null && grid.Get(x, y - 1).ID == "PathTile" && grid.Get(x, y - 1).ID != "DecorationTile") { AddDecoration(grid.Get(x, y).Position, new Vector3(0, 0, 1)); grid.Add(new DecorationTile(pathID), x, y - 1); } } catch (IndexOutOfRangeException e) { Console.WriteLine(e.StackTrace); } } } } } //Add the note if (noteID != 0) { NoteObject note = new NoteObject(noteID.ToString()); note.Parent = this; CreateNote(note, tileGrid); gameObjects.Add(note); } //Making the monster if (chased) { monster = new Monster(Grid.Objects); monster.Parent = this; monster.LoadContent(); gameObjects.Add(monster); } //Making the stamina bar stamina = new Stamina(); gameObjects.Add(stamina); stamina.Parent = this; exitText.text = "Press E to proceed"; //Making the room counter roomCounter = new TextGameObject("text"); roomCounter.text = roomNumber.ToString(); gameObjects.Add(roomCounter); }
protected void CreateNote(NoteObject note, TileGrid tileGrid) { for (int x = 0; x < tileGrid.Columns; x++) { for (int y =0; y < tileGrid.Rows; y++) { if (tileGrid.Get(x, y) != null && tileGrid.Get(x, y) is WallTile) { if(tileGrid.Get(x + 1, y) is PathTile) { note.Position = tileGrid.Get(x, y).Position + new Vector3(102/*100+modelDepth*/, 0, 0); } else if(tileGrid.Get(x, y + 1) is PathTile) { note.Position = tileGrid.Get(x, y).Position + new Vector3(0, 0, 102); } else if(tileGrid.Get(x - 1, y) is PathTile) { note.Position = tileGrid.Get(x, y).Position - new Vector3(102, 0, 0); } else if(tileGrid.Get(x, y - 1)is PathTile) { note.Position = tileGrid.Get(x, y).Position - new Vector3(0, 0, 102); } } } } }