/// <summary> /// Generates a transitive fallback map where each item is a sorted list of all items in the items fallback chain. /// </summary> /// <param name="directMap"></param> private static TileConnection[][] CreateTransitiveMap(TileConnection[] directMap) { TileConnection[][] transitiveMap = new TileConnection[StateCount][]; List <TileConnection> currentChain = new List <TileConnection>(); for (int stateIndex = 0; stateIndex < StateCount; stateIndex++) { // Build the transitive chain of this state int current = stateIndex; while (directMap[current] != TileConnection.All && (int)directMap[current] != current) { currentChain.Add(directMap[current]); current = (int)directMap[current]; } // Map it and start over if (currentChain.Count > 0) { transitiveMap[stateIndex] = currentChain.ToArray(); currentChain.Clear(); } } return(transitiveMap); }
public TileConnectionMarker(TileConnection connection, Pen sourcePen, Pen destinationPen, Pen linePen) { this.connection = connection; this.SourcePen = sourcePen; this.DestinationPen = destinationPen; this.LinePen = linePen; }
public bool Reroll(Func <RandomLevelData, bool> requirements) { TileConnection requirement = TileConnection.None; if (this.data.up && this.up != null && this.up.data != null) { requirement |= TileConnection.Up; } if (this.data.down && this.down != null && this.down.data != null) { requirement |= TileConnection.Down; } if (this.data.left && this.left != null && this.left.data != null) { requirement |= TileConnection.Left; } if (this.data.right && this.right != null && this.right.data != null) { requirement |= TileConnection.Right; } RandomLevelData tile = LevelGenerator.GetTile(requirement, this.data, type: LevGenType.Deathmatch, lambdaReq: requirements); if (tile == null) { return(false); } this.data = tile; if (this.symmetricalPartner != null) { this.symmetricalPartner.data = tile.Flipped(); } return(true); }
/// <summary> /// Initializes a new tile with the specified <see cref="BaseIndex"/> and derives all other values /// from their defaults as specified in the provided <see cref="Tileset"/>. /// /// This guarantees that, even for AutoTiles, the specified <see cref="BaseIndex"/> will be used /// directly as-is, without the resolve step adjusting it. When possible, prefer other methods of /// initializing tiles, as this one is more expensive than the others. /// </summary> /// <param name="baseIndex"></param> /// <param name="defaultLookup"></param> public Tile(int baseIndex, ContentRef <Tileset> defaultLookup) { Tileset tileset = defaultLookup.Res; if (tileset == null) { throw new ArgumentNullException("defaultLookup"); } // As long as not resolved otherwise, use the base index directly. this.Index = baseIndex; this.BaseIndex = baseIndex; this.DepthOffset = 0; // By default, pre-initialize the tile with the AutoTile connectivity state that is // specified for it in the Tileset. This way, when painting the tile unaltered, // resolving it using base index and connectivity state won't replace it with a // different tile. TileInfo tileInfo = tileset.TileData[baseIndex]; int autoTileLayer = tileInfo.AutoTileLayer; if (autoTileLayer != 0) { TilesetAutoTileInfo autoTile = tileset.AutoTileData[autoTileLayer - 1]; IReadOnlyList <TilesetAutoTileItem> autoTileInfo = autoTile.TileInfo; this.AutoTileCon = autoTileInfo[baseIndex].Neighbours; this.BaseIndex = autoTile.BaseTileIndex; } else { this.AutoTileCon = TileConnection.None; } }
public static List <RandomLevelData> GetTiles( TileConnection requirement, TileConnection filter) { if (requirement == TileConnection.None) { return(new List <RandomLevelData>((IEnumerable <RandomLevelData>)LevelGenerator._tiles)); } bool flag1 = (requirement & TileConnection.Left) != TileConnection.None; bool flag2 = (requirement & TileConnection.Right) != TileConnection.None; bool flag3 = (requirement & TileConnection.Up) != TileConnection.None; bool flag4 = (requirement & TileConnection.Down) != TileConnection.None; bool flag5 = (filter & TileConnection.Left) != TileConnection.None; bool flag6 = (filter & TileConnection.Right) != TileConnection.None; bool flag7 = (filter & TileConnection.Up) != TileConnection.None; bool flag8 = (filter & TileConnection.Down) != TileConnection.None; List <RandomLevelData> randomLevelDataList = new List <RandomLevelData>(); foreach (RandomLevelData tile in LevelGenerator._tiles) { if ((tile.left || !flag1) && (tile.right || !flag2) && ((tile.up || !flag3) && (tile.down || !flag4)) && ((!tile.left || !flag5) && (!tile.right || !flag6) && ((!tile.up || !flag7) && (!tile.down || !flag8)))) { randomLevelDataList.Add(tile); } } return(randomLevelDataList); }
public void TestToString() { var tc = new TileConnection(new List <Tile>() { new Tile(new Column(0), 1), new Tile(new Column(1), 2), new Tile(new Column(2), 3) }); Assert.AreEqual("[0,1] - [2,3]", tc.ToString()); tc = new TileConnection(new List <Tile>() { new Tile(new Column(2), 1), new Tile(new Column(2), 2), new Tile(new Column(2), 3) }); Assert.AreEqual("[2,1] - [2,3]", tc.ToString()); tc = new TileConnection(new List <Tile>() { new Tile(new Column(2), 1) }); Assert.AreEqual("[2,1] - [2,1]", tc.ToString()); }
/// <summary> /// Generates a transitive fallback map where each item is a sorted list of all items in the items fallback chain. /// </summary> /// <param name="directMap"></param> /// <returns></returns> private static TileConnection[][] CreateTransitiveMap(TileConnection[] directMap) { TileConnection[][] transitiveMap = new TileConnection[StateCount][]; List<TileConnection> currentChain = new List<TileConnection>(); for (int stateIndex = 0; stateIndex < StateCount; stateIndex++) { // Build the transitive chain of this state int current = stateIndex; while (directMap[current] != TileConnection.All && (int)directMap[current] != current) { currentChain.Add(directMap[current]); current = (int)directMap[current]; } // Map it and start over if (currentChain.Count > 0) { transitiveMap[stateIndex] = currentChain.ToArray(); currentChain.Clear(); } } return transitiveMap; }
/// <summary> /// Initializes a new tile with the specified <see cref="BaseIndex"/> and <see cref="AutoTileCon">AutoTile connectivity</see>. /// The <see cref="Index"/> will be resolved when set in a <see cref="Tilemap"/>. /// </summary> /// <param name="baseIndex"></param> /// <param name="connectivity"></param> public Tile(int baseIndex, TileConnection connectivity) { // As long as not resolved otherwise, use the base index directly. this.Index = baseIndex; this.BaseIndex = baseIndex; this.DepthOffset = 0; this.AutoTileCon = connectivity; }
public AddConnectionDialog(TileConnection initialConnection) : this() { sourceXUpDown.Value = initialConnection.Source.X; sourceYUpDown.Value = initialConnection.Source.Y; destinationXUpDown.Value = initialConnection.Destination.X; destinationYUpDown.Value = initialConnection.Destination.Y; }
public void SetTileConnection(int tx, int ty, TileConnection tileConnection) { Chunk chunk = GetChunkAt(tx, ty); if (chunk != null) { chunk.CachedTileConnection[tx % Chunk.CHUNK_SIZE, ty % Chunk.CHUNK_SIZE] = tileConnection; } }
private void tilesetView_SelectedAreaEditingFinished(object sender, EventArgs e) { // Early-out, if nothing is selected if (this.tilesetView.SelectedArea.IsEmpty) { // When clearing the selection, remove it as tile drawing source, if it was set before if (TilemapsEditorPlugin.Instance.TileDrawingSource == this.paletteSource) { TilemapsEditorPlugin.Instance.TileDrawingSource = TilemapsEditorPlugin.EmptyTileDrawingSource; } return; } // Retrieve selected tile data Tileset tileset = this.SelectedTileset.Res; IReadOnlyGrid <Tile> selectedTiles = this.tilesetView.SelectedTiles; Grid <bool> shape = new Grid <bool>(selectedTiles.Width, selectedTiles.Height); Grid <Tile> pattern = new Grid <Tile>(selectedTiles.Width, selectedTiles.Height); for (int y = 0; y < selectedTiles.Height; y++) { for (int x = 0; x < selectedTiles.Width; x++) { Tile tile = selectedTiles[x, y]; // For standard autotile parts, only paint the autotiles base index // and ignore which specific part was selected. // // Note that this doesn't ensure completely normalized autotile base indices // across the tilemap, only normalized new indices being painted. A full // normalization guarantee would be possible by changing Tile.ResolveIndex, // but since it isn't actually necessary and potentially destructive, we'll // just make sure "most indices are generally" normalized. int autoTileIndex = tileset.TileData[tile.BaseIndex].AutoTileLayer - 1; if (autoTileIndex >= 0) { TilesetAutoTileInfo autoTile = tileset.AutoTileData[autoTileIndex]; TileConnection connectivity = autoTile.TileInfo[tile.BaseIndex].Neighbours; bool isDefaultTile = autoTile.StateToTile[(int)connectivity] == tile.BaseIndex; if (isDefaultTile) { tile.BaseIndex = autoTile.BaseTileIndex; } } shape[x, y] = true; pattern[x, y] = tile; } } this.paletteSource.SetData(shape, pattern); // Apply the selected tiles to the palettes source for tile drawing TilemapsEditorPlugin.Instance.TileDrawingSource = this.paletteSource; }
public void ClearIntermediateConnections() { var oldHighlights = new HighlightMarker[_intermediateConnectionHighlights.Count]; _intermediateConnectionHighlights.CopyTo(oldHighlights, 0); _intermediateConnectionHighlights.Clear(); foreach (var highlight in oldHighlights) { highlight.Invalidate(this); } currentConnection = TileConnection.Invalid; }
/// <summary> /// Counts the number of connected neighbours in the specified connectivity state. /// </summary> /// <param name="connectivity"></param> private static int GetConnectedNeighbours(TileConnection connectivity) { // See here: https://stackoverflow.com/questions/12171584/what-is-the-fastest-way-to-count-set-bits-in-uint32 int count = 0; int bits = (int)connectivity; while (bits != 0) { count++; bits &= bits - 1; } return(count); }
/// <summary> /// Finds an existing base tile where a certain sub-tile matches with the specified connectivity state. /// Returns <see cref="TileConnection.None"/> if no match was found in the existing set. /// </summary> /// <param name="quadrant"></param> /// <param name="targetConnectivity"></param> /// <param name="isStateAvailable"></param> private static TileConnection FindGeneratedAutoTileBase(TileQuadrant quadrant, TileConnection targetConnectivity, bool[] isStateAvailable) { TileConnection mask = AutoTileFallbackMap.GetSubTileMask(quadrant); TileConnection targetBits = targetConnectivity & mask; IReadOnlyList <TileConnection> baseTiles = AutoTileFallbackMap.BaseConnectivityTiles; TileConnection bestMatch = TileConnection.None; int bestMatchNeighbourCount = 0; for (int i = 0; i < baseTiles.Count; i++) { // Skip tiles that are not available in the tileset TileConnection connectivity = baseTiles[i]; if (!isStateAvailable[(int)connectivity]) { continue; } // Skip tiles that do not match in the required bits TileConnection bits = connectivity & mask; if (bits != targetBits) { continue; } // Special case: Skip the entirely unconnected tile, since this one is often // different from any partially connected tiles. Note if this should change: // It's also currently conflicting with the "no match found" return value. if (connectivity == TileConnection.None) { continue; } // Prefer the most connected match we can find, since less connected tiles // tend to be more specialized in their visual appearance. Only consider // connectivity that we also find in the target tile to avoid under-specializing. TileConnection sharedConnectivity = connectivity & targetConnectivity; int neighbourCount = GetConnectedNeighbours(sharedConnectivity); if (neighbourCount > bestMatchNeighbourCount) { bestMatchNeighbourCount = neighbourCount; bestMatch = connectivity; } } return(bestMatch); }
private void AddTrapConnection() { var selectedIndex = listBox.SelectedIndex; var connection = new TileConnection(0, 0, 0, 0); if (selectedIndex > -1) { connection = _owner.Level.TrapConnections[selectedIndex]; } using (var dialog = new AddConnectionDialog(connection)) if (dialog.ShowDialog() == DialogResult.OK) { _owner.AddTrapConnection(dialog.TileConnection); listBox.SelectedIndex = _owner.Level.TrapConnections.Count - 1; UpdateTitle(); } }
public override void Do() { if (Index > -1 && Index < Owner.Level.CloneConnections.Count) { connection = Owner.Level.CloneConnections[Index]; Owner.Level.CloneConnections.RemoveAt(Index); } else { Owner.Level.CloneConnections.Remove(connection); } Owner.Invalidate(connection); foreach (var cloneConnection in Owner.Level.CloneConnections) { Owner.Invalidate(cloneConnection); } Owner.UpdateTileCoordinatesAndHighlights(); }
private void GetNewGoal() { // Find availableTiles List <Tile> tilesAvailable = new List <Tile>(); for (int x = 0; x < boardSize; x++) { for (int y = 0; y < boardSize; y++) { if (tiles[x, y] != null && tiles[x, y].tileConnections.Count > 0) { tilesAvailable.Add(tiles[x, y]); } } } // Create tile path int desiredPathLength = (int)Mathf.Max(Mathf.Round(gamemodeCurrent.levelAttributesCurrent.comboLength + Random.Range(-gamemodeCurrent.levelAttributesCurrent.comboLength / 2f, gamemodeCurrent.levelAttributesCurrent.comboLength / 2f)), 2); List <Tile> pathTiles = new List <Tile>(); pathTiles.Add(tilesAvailable[Random.Range(0, tilesAvailable.Count)]); tilesAvailable.Remove(pathTiles[0]); desiredPathLength--; while (desiredPathLength > 0 && pathTiles[pathTiles.Count - 1].tileConnections.Where(c => tilesAvailable.Contains(c.tile) == true).Count() > 0) { List <TileConnection> availableConnections = pathTiles[pathTiles.Count - 1].tileConnections.Where(tc => tilesAvailable.Contains(tc.tile) == true).ToList(); TileConnection randomConnection = availableConnections[Random.Range(0, availableConnections.Count)]; tilesAvailable.Remove(randomConnection.tile); pathTiles.Add(randomConnection.tile); desiredPathLength--; } goal = ComputeTilePath(pathTiles); // Set UI text_GoalTop.text = goal.ToString(); text_GoalBottom.text = goal.ToString(); // Modify Bar timerTickCoroutine = StartCoroutine(TimerTickCoroutine()); }
public void TestWillTokenPlacedWinGameForPlayer_NotWinnable() { var player = new Object(); var tiles = new List <Tile>(); tiles.Add(new Tile(new Column(0), 0, null)); tiles.Add(new Tile(new Column(1), 0, null)); tiles.Add(new Tile(new Column(2), 0, null)); tiles.Add(new Tile(new Column(3), 0, player)); tiles.Add(new Tile(new Column(4), 0, player)); tiles.Add(new Tile(new Column(5), 0, null)); tiles.Add(new Tile(new Column(6), 0, null)); var tileConnection = new TileConnection(tiles); Assert.IsFalse(tileConnection.WillTokenPlacedWinGameForPlayer(player, tileConnection[2])); Assert.IsFalse(tileConnection.WillTokenPlacedWinGameForPlayer(player, tileConnection[5])); Assert.IsFalse(tileConnection.WillTokenPlacedWinGameForPlayer(player, tileConnection[6])); Assert.IsFalse(tileConnection.HasImmediatlyWinnableConnectionForPlayer(player)); }
/// <summary> /// Resolves the <see cref="Index"/> of the <see cref="Tile"/> based on /// its <see cref="BaseIndex"/> and <see cref="AutoTileCon"/>. /// </summary> /// <param name="autoTile"></param> private void ResolveIndex(TilesetAutoTileInfo autoTile) { // Non-AutoTiles always use their base index directly. if (autoTile == null) { this.Index = this.BaseIndex; } // AutoTiles require a dynamic lookup with their connectivity state, because // they might use generated tiles that do not have a consistent index across // different Tileset configs. else { // If there is no connectivity info and a non-matching base index, this tile // was likely painted before it was configured to be an AutoTile. In that case, // derive the appropriate connectivity from the specs and adjust the base index // to match. if (this.BaseIndex != autoTile.BaseTileIndex && this.AutoTileCon == TileConnection.None) { this.AutoTileCon = autoTile.TileInfo[this.BaseIndex].Neighbours; this.BaseIndex = autoTile.BaseTileIndex; } int targetIndex = autoTile.StateToTile[(int)this.AutoTileCon]; // If the AutoTile connectivity state already matches the one we'd get with the default // resolved tile index, use the current one directly and don't change it. // This will allow scenarios where users specify multiple tiles for a certain connectivity // state, without forcing them back to a single one during resolve. if (autoTile.TileInfo[this.BaseIndex].Neighbours == autoTile.TileInfo[targetIndex].Neighbours) { this.Index = this.BaseIndex; } // Otherwise, lookup the expected tile using base index and connectivity. This // will retrieve the proper generated tile, which has an index that may change // between multiple compilations. else { this.Index = targetIndex; } } }
/// <summary> /// Modifies the specified fallback map so that all permutations of the specified /// base fallback and state flags map back to the base fallback. /// </summary> /// <param name="mapToFallback"></param> /// <param name="fallback"></param> /// <param name="stateFlags"></param> private static void MapAllPermutations(TileConnection[] mapToFallback, TileConnection fallback, params TileConnection[] stateFlags) { int permutationCount = 1 << stateFlags.Length; for (int permutationIndex = 1; permutationIndex < permutationCount; permutationIndex++) { // Generate the state bitmask for this permutation of state flags TileConnection state = fallback; for (int stateIndex = 0; stateIndex < stateFlags.Length; stateIndex++) { int permutationFlag = (1 << stateIndex); if ((permutationIndex & permutationFlag) == permutationFlag) { state |= stateFlags[stateIndex]; } } // Set all permutations to map to this fallback mapToFallback[(int)state] = fallback; } }
public Chunk(int x, int y) { X = x; Y = y; Tiles = new Tile[CHUNK_SIZE, CHUNK_SIZE]; Data = new Dictionary <string, object> [CHUNK_SIZE, CHUNK_SIZE]; CachedTileConnection = new TileConnection[CHUNK_SIZE, CHUNK_SIZE]; Entities = new List <Entity>(); EntitiesOnTiles = new List <Entity> [CHUNK_SIZE, CHUNK_SIZE]; for (int xx = 0; xx < CHUNK_SIZE; xx++) { for (int yy = 0; yy < CHUNK_SIZE; yy++) { Tiles[xx, yy] = TILES.VOID; Data[xx, yy] = new Dictionary <string, object>(); EntitiesOnTiles[xx, yy] = new List <Entity>(); } } }
private TileConnection GetFilter() { TileConnection tileConnection = TileConnection.None; if (this.left == null) { tileConnection |= TileConnection.Left; } if (this.right == null) { tileConnection |= TileConnection.Right; } if (this.up == null) { tileConnection |= TileConnection.Up; } if (this.down == null) { tileConnection |= TileConnection.Down; } return(tileConnection); }
public void GetWinnableConnectionAround_OnEdge() { object player1 = new object(); object player2 = new object(); var tc = new TileConnection(new List <Tile>() { new Tile(new Column(0), 1, player1), new Tile(new Column(1), 1, player1), new Tile(new Column(2), 1), new Tile(new Column(3), 1), new Tile(new Column(4), 1), new Tile(new Column(5), 1), new Tile(new Column(6), 1) }); var winnable = tc.GetWinnableConnectionAround(tc.Tiles[0]); //4,1 + is out since it's too far away Assert.AreEqual(4, winnable.Tiles.Count); Assert.AreEqual("[0,1] - [3,1]", winnable.ToString()); }
public void GetWinnableConnectionAround_Simple() { object player1 = new object(); object player2 = new object(); var tc = new TileConnection(new List <Tile>() { new Tile(new Column(0), 1, player2), new Tile(new Column(1), 1), new Tile(new Column(2), 1, player1), new Tile(new Column(3), 1), new Tile(new Column(4), 1), new Tile(new Column(5), 1), new Tile(new Column(6), 1) }); var winnable = tc.GetWinnableConnectionAround(tc.Tiles[2]); //0,1 is out since it's the wrong player //6,1 is out since it's too far away Assert.AreEqual(5, winnable.Tiles.Count); Assert.AreEqual("[1,1] - [5,1]", winnable.ToString()); }
List <TileConnection> ReconstructPath(Dictionary <Tile, Tile> path, Tile start, Tile end) { List <TileConnection> validPath = new List <TileConnection>(); Stack <Tile> pathStack = new Stack <Tile>(); Tile current = end; pathStack.Push(end); while (path.ContainsKey(current)) { current = path[current]; pathStack.Push(current); } current = pathStack.Pop(); while (pathStack.Count > 0) { Tile prev = pathStack.Pop(); Debug.Log(prev.Position); TileConnection tc = current.Connections.Single((compData) => { return(compData.Destination == prev); }); validPath.Add(tc); current = prev; } return(validPath); }
private static void DrawConnectivityOutlines(GraphicsPath path, TileConnection connectivity, Rectangle baseRect) { if (connectivity == TileConnection.All) return; Rectangle fullRect = baseRect; fullRect.Width -= 1; fullRect.Height -= 1; Rectangle centerRect = GetConnectivityRegionRect(TileConnection.None, baseRect); centerRect.Width -= 1; centerRect.Height -= 1; // Add lines for the 4-neighbourhood that is not connected if (!connectivity.HasFlag(TileConnection.Top)) { path.AddLine(centerRect.Left, centerRect.Top, centerRect.Right, centerRect.Top); path.StartFigure(); } if (!connectivity.HasFlag(TileConnection.Bottom)) { path.AddLine(centerRect.Left, centerRect.Bottom, centerRect.Right, centerRect.Bottom); path.StartFigure(); } if (!connectivity.HasFlag(TileConnection.Left)) { path.AddLine(centerRect.Left, centerRect.Top, centerRect.Left, centerRect.Bottom); path.StartFigure(); } if (!connectivity.HasFlag(TileConnection.Right)) { path.AddLine(centerRect.Right, centerRect.Top, centerRect.Right, centerRect.Bottom); path.StartFigure(); } // Add lines for connectivity borders between the four corners and the main area if (connectivity.HasFlag(TileConnection.TopLeft) && (connectivity.HasFlag(TileConnection.Top) != connectivity.HasFlag(TileConnection.Left))) { path.AddLine(fullRect.Left, fullRect.Top, centerRect.Left, centerRect.Top); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.TopLeft) != connectivity.HasFlag(TileConnection.Top)) { path.AddLine(centerRect.Left, centerRect.Top, centerRect.Left, fullRect.Top); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.TopLeft) != connectivity.HasFlag(TileConnection.Left)) { path.AddLine(centerRect.Left, centerRect.Top, fullRect.Left, centerRect.Top); path.StartFigure(); } } if (connectivity.HasFlag(TileConnection.TopRight) && (connectivity.HasFlag(TileConnection.Top) != connectivity.HasFlag(TileConnection.Right))) { path.AddLine(fullRect.Right, fullRect.Top, centerRect.Right, centerRect.Top); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.TopRight) != connectivity.HasFlag(TileConnection.Top)) { path.AddLine(centerRect.Right, centerRect.Top, centerRect.Right, fullRect.Top); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.TopRight) != connectivity.HasFlag(TileConnection.Right)) { path.AddLine(centerRect.Right, centerRect.Top, fullRect.Right, centerRect.Top); path.StartFigure(); } } if (connectivity.HasFlag(TileConnection.BottomLeft) && (connectivity.HasFlag(TileConnection.Bottom) != connectivity.HasFlag(TileConnection.Left))) { path.AddLine(fullRect.Left, fullRect.Bottom, centerRect.Left, centerRect.Bottom); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.BottomLeft) != connectivity.HasFlag(TileConnection.Bottom)) { path.AddLine(centerRect.Left, centerRect.Bottom, centerRect.Left, fullRect.Bottom); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.BottomLeft) != connectivity.HasFlag(TileConnection.Left)) { path.AddLine(centerRect.Left, centerRect.Bottom, fullRect.Left, centerRect.Bottom); path.StartFigure(); } } if (connectivity.HasFlag(TileConnection.BottomRight) && (connectivity.HasFlag(TileConnection.Bottom) != connectivity.HasFlag(TileConnection.Right))) { path.AddLine(fullRect.Right, fullRect.Bottom, centerRect.Right, centerRect.Bottom); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.BottomRight) != connectivity.HasFlag(TileConnection.Bottom)) { path.AddLine(centerRect.Right, centerRect.Bottom, centerRect.Right, fullRect.Bottom); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.BottomRight) != connectivity.HasFlag(TileConnection.Right)) { path.AddLine(centerRect.Right, centerRect.Bottom, fullRect.Right, centerRect.Bottom); path.StartFigure(); } } }
private static void DrawConnectivityRegion(GraphicsPath path, TileConnection connectivity, Rectangle baseRect) { if (connectivity == TileConnection.None) return; Rectangle fullRect = baseRect; Rectangle centerRect = GetConnectivityRegionRect(TileConnection.None, baseRect); // Add rects for the 4-neighbourhood that is connected if (connectivity.HasFlag(TileConnection.Top)) path.AddRectangle(new Rectangle(centerRect.Left, fullRect.Top, centerRect.Width, centerRect.Top - fullRect.Top)); if (connectivity.HasFlag(TileConnection.Bottom)) path.AddRectangle(new Rectangle(centerRect.Left, centerRect.Bottom, centerRect.Width, fullRect.Bottom - centerRect.Bottom)); if (connectivity.HasFlag(TileConnection.Left)) path.AddRectangle(new Rectangle(fullRect.Left, centerRect.Top, centerRect.Left - fullRect.Left, centerRect.Height)); if (connectivity.HasFlag(TileConnection.Right)) path.AddRectangle(new Rectangle(centerRect.Right, centerRect.Top, fullRect.Right - centerRect.Right, centerRect.Height)); // Add rects for the corners of the connected 8-neighbourhood if (connectivity.HasFlag(TileConnection.TopLeft)) { if (connectivity.HasFlag(TileConnection.Top) && !connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Top), new Point(centerRect.Left, fullRect.Top), new Point(centerRect.Left, centerRect.Top), }); } else if (!connectivity.HasFlag(TileConnection.Top) && connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Top), new Point(fullRect.Left, centerRect.Top), new Point(centerRect.Left, centerRect.Top), }); } else { path.AddRectangle(new Rectangle(fullRect.Left, fullRect.Top, centerRect.Left - fullRect.Left, centerRect.Top - fullRect.Top)); } } if (connectivity.HasFlag(TileConnection.TopRight)) { if (connectivity.HasFlag(TileConnection.Top) && !connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Top), new Point(centerRect.Right, fullRect.Top), new Point(centerRect.Right, centerRect.Top), }); } else if (!connectivity.HasFlag(TileConnection.Top) && connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Top), new Point(fullRect.Right, centerRect.Top), new Point(centerRect.Right, centerRect.Top), }); } else { path.AddRectangle(new Rectangle(centerRect.Right, fullRect.Top, fullRect.Right - centerRect.Right, centerRect.Top - fullRect.Top)); } } if (connectivity.HasFlag(TileConnection.BottomRight)) { if (connectivity.HasFlag(TileConnection.Bottom) && !connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Bottom), new Point(centerRect.Right, fullRect.Bottom), new Point(centerRect.Right, centerRect.Bottom), }); } else if (!connectivity.HasFlag(TileConnection.Bottom) && connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Bottom), new Point(fullRect.Right, centerRect.Bottom), new Point(centerRect.Right, centerRect.Bottom), }); } else { path.AddRectangle(new Rectangle(centerRect.Right, centerRect.Bottom, fullRect.Right - centerRect.Right, fullRect.Bottom - centerRect.Bottom)); } } if (connectivity.HasFlag(TileConnection.BottomLeft)) { if (connectivity.HasFlag(TileConnection.Bottom) && !connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Bottom), new Point(centerRect.Left, fullRect.Bottom), new Point(centerRect.Left, centerRect.Bottom), }); } else if (!connectivity.HasFlag(TileConnection.Bottom) && connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Bottom), new Point(fullRect.Left, centerRect.Bottom), new Point(centerRect.Left, centerRect.Bottom), }); } else { path.AddRectangle(new Rectangle(fullRect.Left, centerRect.Bottom, centerRect.Left - fullRect.Left, fullRect.Bottom - centerRect.Bottom)); } } }
/// <summary> /// Updates the <see cref="AutoTileCon"/> state of an arbitrary region on the specified tile grid /// based on its connectivity state with neighbouring tiles. /// </summary> /// <param name="tileGrid"></param> /// <param name="updateMask"></param> /// <param name="beginX"></param> /// <param name="beginY"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="tilesetRes"></param> public static void UpdateAutoTileCon(Grid <Tile> tileGrid, Grid <bool> updateMask, int beginX, int beginY, int width, int height, ContentRef <Tileset> tileset) { if (tileset.Res == null) { throw new ArgumentNullException("tileset"); } if (tileGrid == null) { throw new ArgumentNullException("tileGrid"); } Tileset tilesetRes = tileset.Res; TileInfo[] tileData = tilesetRes.TileData.Data; Tile[] tiles = tileGrid.RawData; bool[] maskData = updateMask != null ? updateMask.RawData : null; int tileStride = tileGrid.Width; int maskStride = updateMask.Width; int maxTileX = tileGrid.Width - 1; int maxTileY = tileGrid.Height - 1; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // Skip tiles that have been masked away int m = x + maskStride * y; if (maskData != null && !maskData[m]) { continue; } // Determine tilemap coordinates and index int tileX = x + beginX; int tileY = y + beginY; int i = tileX + tileStride * tileY; // Skip non-AutoTiles int autoTileIndex = tileData[tiles[i].BaseIndex].AutoTileLayer - 1; if (autoTileIndex == -1) { continue; } // Lookup AutoTile data TilesetAutoTileInfo autoTile = tilesetRes.AutoTileData[autoTileIndex]; IReadOnlyList <TilesetAutoTileItem> autoTileInfo = autoTile.TileInfo; // Check neighbour connectivity bool topLeft = (tileX <= 0 || tileY <= 0) || autoTileInfo[tiles[i - 1 - tileStride].Index].ConnectsToAutoTile; bool top = (tileY <= 0) || autoTileInfo[tiles[i - tileStride].Index].ConnectsToAutoTile; bool topRight = (tileX >= maxTileX || tileY <= 0) || autoTileInfo[tiles[i + 1 - tileStride].Index].ConnectsToAutoTile; bool left = (tileX <= 0) || autoTileInfo[tiles[i - 1].Index].ConnectsToAutoTile; bool right = (tileX >= maxTileX) || autoTileInfo[tiles[i + 1].Index].ConnectsToAutoTile; bool bottomLeft = (tileX <= 0 || tileY >= maxTileY) || autoTileInfo[tiles[i - 1 + tileStride].Index].ConnectsToAutoTile; bool bottom = (tileY >= maxTileY) || autoTileInfo[tiles[i + tileStride].Index].ConnectsToAutoTile; bool bottomRight = (tileX >= maxTileX || tileY >= maxTileY) || autoTileInfo[tiles[i + 1 + tileStride].Index].ConnectsToAutoTile; // Create connectivity bitmask TileConnection autoTileCon = TileConnection.None; if (topLeft) { autoTileCon |= TileConnection.TopLeft; } if (top) { autoTileCon |= TileConnection.Top; } if (topRight) { autoTileCon |= TileConnection.TopRight; } if (left) { autoTileCon |= TileConnection.Left; } if (right) { autoTileCon |= TileConnection.Right; } if (bottomLeft) { autoTileCon |= TileConnection.BottomLeft; } if (bottom) { autoTileCon |= TileConnection.Bottom; } if (bottomRight) { autoTileCon |= TileConnection.BottomRight; } // Update connectivity and re-resolve index tiles[i].AutoTileCon = autoTileCon; tiles[i].ResolveIndex(autoTile); } } }
private static Rectangle GetConnectivityRegionRect(TileConnection connectivity, Rectangle baseRect) { Size borderSize = new Size( baseRect.Width / 4, baseRect.Height / 4); switch (connectivity) { default: case TileConnection.All: return baseRect; case TileConnection.TopLeft: return new Rectangle( baseRect.X, baseRect.Y, borderSize.Width, borderSize.Height); case TileConnection.Top: return new Rectangle( baseRect.X + borderSize.Width, baseRect.Y, baseRect.Width - borderSize.Width * 2, borderSize.Height); case TileConnection.TopRight: return new Rectangle( baseRect.X + baseRect.Width - borderSize.Width, baseRect.Y, borderSize.Width, borderSize.Height); case TileConnection.Left: return new Rectangle( baseRect.X, baseRect.Y + borderSize.Height, borderSize.Width, baseRect.Height - borderSize.Height * 2); case TileConnection.None: return new Rectangle( baseRect.X + borderSize.Width, baseRect.Y + borderSize.Height, baseRect.Width - borderSize.Width * 2, baseRect.Height - borderSize.Height * 2); case TileConnection.Right: return new Rectangle( baseRect.X + baseRect.Width - borderSize.Width, baseRect.Y + borderSize.Height, borderSize.Width, baseRect.Height - borderSize.Height * 2); case TileConnection.BottomLeft: return new Rectangle( baseRect.X, baseRect.Y + baseRect.Height - borderSize.Height, borderSize.Width, borderSize.Height); case TileConnection.Bottom: return new Rectangle( baseRect.X + borderSize.Width, baseRect.Y + baseRect.Height - borderSize.Height, baseRect.Width - borderSize.Width * 2, borderSize.Height); case TileConnection.BottomRight: return new Rectangle( baseRect.X + baseRect.Width - borderSize.Width, baseRect.Y + baseRect.Height - borderSize.Height, borderSize.Width, borderSize.Height); } }
public AddTrapConnectionCommand(TileConnection connection) { this.connection = connection; }
private void GenerateData() { TileConnection[] directFallbacks = new TileConnection[StateCount]; for (int i = 0; i < directFallbacks.Length; i++) { // Since our default is the AutoTile's base tile, which is fully connected, // use the fully connected state as a default. directFallbacks[i] = TileConnection.All; } // // DontCare permutations, reducing the overall number of required connectivity states to 47. // See here: https://cloud.githubusercontent.com/assets/14859411/11279962/ccc1ac2e-8ef3-11e5-8e99-861b0d7a1c9a.png // MapAllPermutations(directFallbacks, Left | Right | BottomLeft | Bottom | BottomRight, TopLeft, TopRight); MapAllPermutations(directFallbacks, TopLeft | Top | Left | BottomLeft | Bottom, TopRight, BottomRight); MapAllPermutations(directFallbacks, Left | BottomLeft | Bottom, TopLeft, TopRight, BottomRight); MapAllPermutations(directFallbacks, TopLeft | Top | TopRight | Left | Right, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Left | Right, TopLeft, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, TopLeft | Top | Left, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Left, TopLeft, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Top | TopRight | Right | Bottom | BottomRight, TopLeft, BottomLeft); MapAllPermutations(directFallbacks, Right | Bottom | BottomRight, TopLeft, TopRight, BottomLeft); MapAllPermutations(directFallbacks, Top | Bottom, TopLeft, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Bottom, TopLeft, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Top | TopRight | Right, TopLeft, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Right, TopLeft, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Top, TopLeft, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, None, TopLeft, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Left | Right | BottomLeft | Bottom, TopLeft, TopRight); MapAllPermutations(directFallbacks, Left | Right | Bottom | BottomRight, TopLeft, TopRight); MapAllPermutations(directFallbacks, Left | Right | Bottom, TopLeft, TopRight); MapAllPermutations(directFallbacks, Top | Left | BottomLeft | Bottom, TopRight, BottomRight); MapAllPermutations(directFallbacks, TopLeft | Top | Left | Bottom, TopRight, BottomRight); MapAllPermutations(directFallbacks, Top | Left | Bottom, TopRight, BottomRight); MapAllPermutations(directFallbacks, Left | Bottom, TopLeft, TopRight, BottomRight); MapAllPermutations(directFallbacks, Top | TopRight | Left | Right, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, TopLeft | Top | Left | Right, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Top | Left | Right, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Top | Left, TopRight, BottomLeft, BottomRight); MapAllPermutations(directFallbacks, Top | Right | Bottom | BottomRight, TopLeft, BottomLeft); MapAllPermutations(directFallbacks, Top | TopRight | Right | Bottom, TopLeft, BottomLeft); MapAllPermutations(directFallbacks, Top | Right | Bottom, TopLeft, BottomLeft); MapAllPermutations(directFallbacks, Right | Bottom, TopLeft, TopRight, BottomLeft); MapAllPermutations(directFallbacks, Top | Right, TopLeft, BottomLeft, BottomRight); // // Actual fallbacks in case a certain connectivity state is unavailable. // directFallbacks[(int)(Top | Left | Right | BottomLeft | Bottom | BottomRight)] = Left | Right | BottomLeft | Bottom | BottomRight; directFallbacks[(int)(TopLeft | Top | Left | Right | BottomLeft | Bottom)] = TopLeft | Top | Left | BottomLeft |Bottom; directFallbacks[(int)(Top | TopRight | Left | Right | Bottom | BottomRight)] = Top | TopRight | Right | Bottom | BottomRight; directFallbacks[(int)(TopLeft | Top | TopRight | Left | Right | Bottom)] = TopLeft | Top | TopRight | Left | Right; directFallbacks[(int)(Top | TopRight | Left | Right | BottomLeft | Bottom | BottomRight)] = All; directFallbacks[(int)(TopLeft | Top | Left | Right | BottomLeft | Bottom | BottomRight)] = All; directFallbacks[(int)(TopLeft | Top | TopRight | Left | Right | Bottom | BottomRight)] = All; directFallbacks[(int)(TopLeft | Top | TopRight | Left | Right | BottomLeft | Bottom)] = All; directFallbacks[(int)(Top | TopRight | Left | Right | BottomLeft | Bottom)] = All; directFallbacks[(int)(TopLeft | Top | Left | Right | Bottom | BottomRight)] = All; directFallbacks[(int)(TopLeft | Top | Left | Right | Bottom)] = All; directFallbacks[(int)(Top | TopRight | Left | Right | Bottom)] = All; directFallbacks[(int)(Top | Left | Right | BottomLeft | Bottom)] = All; directFallbacks[(int)(Top | Left | Right | Bottom | BottomRight)] = All; directFallbacks[(int)(Left | Right | Top | Bottom)] = All; directFallbacks[(int)(Left | Right | BottomLeft | Bottom)] = Left | Right | BottomLeft | Bottom | BottomRight; directFallbacks[(int)(Left | Right | BottomRight | Bottom)] = Left | Right | BottomLeft | Bottom | BottomRight; directFallbacks[(int)(Left | Right | Bottom)] = Left | Right | BottomLeft | Bottom | BottomRight; directFallbacks[(int)(Top | Left | BottomLeft | Bottom)] = TopLeft | Top | Left | BottomLeft | Bottom; directFallbacks[(int)(TopLeft | Top | Left | Bottom)] = TopLeft | Top | Left | BottomLeft | Bottom; directFallbacks[(int)(Top | Left | Bottom)] = TopLeft | Top | Left | BottomLeft | Bottom; directFallbacks[(int)(Top | TopRight | Left | Right)] = TopLeft | Top | TopRight | Left | Right; directFallbacks[(int)(TopLeft | Top | Left | Right)] = TopLeft | Top | TopRight | Left | Right; directFallbacks[(int)(Top | Left | Right)] = TopLeft | Top | TopRight | Left | Right; directFallbacks[(int)(Top | Right | Bottom | BottomRight)] = Top | TopRight | Right | Bottom | BottomRight; directFallbacks[(int)(Top | TopRight | Right | Bottom)] = Top | TopRight | Right | Bottom | BottomRight; directFallbacks[(int)(Top | Right | Bottom)] = Top | TopRight | Right | Bottom | BottomRight; directFallbacks[(int)(Top | Left)] = TopLeft | Top | Left; directFallbacks[(int)(Top | Right)] = Top | TopRight | Right; directFallbacks[(int)(Left | Bottom)] = Left | BottomLeft | Bottom; directFallbacks[(int)(Right | Bottom)] = Right | Bottom | BottomRight; // Create a transitive fallback chain for each connectivity state this.data = CreateTransitiveMap(directFallbacks); }
private static void DrawConnectivityRegion(GraphicsPath path, TileConnection connectivity, Rectangle baseRect) { if (connectivity == TileConnection.None) { return; } Rectangle fullRect = baseRect; Rectangle centerRect = GetConnectivityRegionRect(TileConnection.None, baseRect); // Add rects for the 4-neighbourhood that is connected if (connectivity.HasFlag(TileConnection.Top)) { path.AddRectangle(new Rectangle(centerRect.Left, fullRect.Top, centerRect.Width, centerRect.Top - fullRect.Top)); } if (connectivity.HasFlag(TileConnection.Bottom)) { path.AddRectangle(new Rectangle(centerRect.Left, centerRect.Bottom, centerRect.Width, fullRect.Bottom - centerRect.Bottom)); } if (connectivity.HasFlag(TileConnection.Left)) { path.AddRectangle(new Rectangle(fullRect.Left, centerRect.Top, centerRect.Left - fullRect.Left, centerRect.Height)); } if (connectivity.HasFlag(TileConnection.Right)) { path.AddRectangle(new Rectangle(centerRect.Right, centerRect.Top, fullRect.Right - centerRect.Right, centerRect.Height)); } // Add rects for the corners of the connected 8-neighbourhood if (connectivity.HasFlag(TileConnection.TopLeft)) { if (connectivity.HasFlag(TileConnection.Top) && !connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Top), new Point(centerRect.Left, fullRect.Top), new Point(centerRect.Left, centerRect.Top), }); } else if (!connectivity.HasFlag(TileConnection.Top) && connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Top), new Point(fullRect.Left, centerRect.Top), new Point(centerRect.Left, centerRect.Top), }); } else { path.AddRectangle(new Rectangle(fullRect.Left, fullRect.Top, centerRect.Left - fullRect.Left, centerRect.Top - fullRect.Top)); } } if (connectivity.HasFlag(TileConnection.TopRight)) { if (connectivity.HasFlag(TileConnection.Top) && !connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Top), new Point(centerRect.Right, fullRect.Top), new Point(centerRect.Right, centerRect.Top), }); } else if (!connectivity.HasFlag(TileConnection.Top) && connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Top), new Point(fullRect.Right, centerRect.Top), new Point(centerRect.Right, centerRect.Top), }); } else { path.AddRectangle(new Rectangle(centerRect.Right, fullRect.Top, fullRect.Right - centerRect.Right, centerRect.Top - fullRect.Top)); } } if (connectivity.HasFlag(TileConnection.BottomRight)) { if (connectivity.HasFlag(TileConnection.Bottom) && !connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Bottom), new Point(centerRect.Right, fullRect.Bottom), new Point(centerRect.Right, centerRect.Bottom), }); } else if (!connectivity.HasFlag(TileConnection.Bottom) && connectivity.HasFlag(TileConnection.Right)) { path.AddPolygon(new Point[] { new Point(fullRect.Right, fullRect.Bottom), new Point(fullRect.Right, centerRect.Bottom), new Point(centerRect.Right, centerRect.Bottom), }); } else { path.AddRectangle(new Rectangle(centerRect.Right, centerRect.Bottom, fullRect.Right - centerRect.Right, fullRect.Bottom - centerRect.Bottom)); } } if (connectivity.HasFlag(TileConnection.BottomLeft)) { if (connectivity.HasFlag(TileConnection.Bottom) && !connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Bottom), new Point(centerRect.Left, fullRect.Bottom), new Point(centerRect.Left, centerRect.Bottom), }); } else if (!connectivity.HasFlag(TileConnection.Bottom) && connectivity.HasFlag(TileConnection.Left)) { path.AddPolygon(new Point[] { new Point(fullRect.Left, fullRect.Bottom), new Point(fullRect.Left, centerRect.Bottom), new Point(centerRect.Left, centerRect.Bottom), }); } else { path.AddRectangle(new Rectangle(fullRect.Left, centerRect.Bottom, centerRect.Left - fullRect.Left, fullRect.Bottom - centerRect.Bottom)); } } }
private void TilesetView_MouseMove(object sender, MouseEventArgs e) { Size tileSize = this.TilesetView.DisplayedTileSize; Point tilePos = this.TilesetView.GetTileIndexLocation(this.TilesetView.HoveredTileIndex); Point posOnTile = new Point(e.X - tilePos.X, e.Y - tilePos.Y); Size centerSize = new Size(tileSize.Width / 2, tileSize.Height / 2); // Determine the hovered tile hotspot for user interaction TileConnection lastHoveredArea = this.hoveredArea; if (posOnTile.X > (tileSize.Width - centerSize.Width) / 2 && posOnTile.Y > (tileSize.Height - centerSize.Height) / 2 && posOnTile.X < (tileSize.Width + centerSize.Width) / 2 && posOnTile.Y < (tileSize.Height + centerSize.Height) / 2) { this.hoveredArea = TileConnection.None; } else { float angle = MathF.Angle(tileSize.Width / 2, tileSize.Height / 2, posOnTile.X, posOnTile.Y); float threshold = MathF.DegToRad(22.5f); if (MathF.CircularDist(angle, MathF.DegToRad(315.0f)) <= threshold) { this.hoveredArea = TileConnection.TopLeft; } else if (MathF.CircularDist(angle, MathF.DegToRad(0.0f)) <= threshold) { this.hoveredArea = TileConnection.Top; } else if (MathF.CircularDist(angle, MathF.DegToRad(45.0f)) <= threshold) { this.hoveredArea = TileConnection.TopRight; } else if (MathF.CircularDist(angle, MathF.DegToRad(270.0f)) <= threshold) { this.hoveredArea = TileConnection.Left; } else if (MathF.CircularDist(angle, MathF.DegToRad(90.0f)) <= threshold) { this.hoveredArea = TileConnection.Right; } else if (MathF.CircularDist(angle, MathF.DegToRad(225.0f)) <= threshold) { this.hoveredArea = TileConnection.BottomLeft; } else if (MathF.CircularDist(angle, MathF.DegToRad(180.0f)) <= threshold) { this.hoveredArea = TileConnection.Bottom; } else { this.hoveredArea = TileConnection.BottomRight; } } // Update action state TilesetAutoTileInput autoTile = this.currentAutoTile; if (autoTile != null) { this.isBaseTileDraw = autoTile.BaseTileIndex == -1 || autoTile.BaseTileIndex == this.TilesetView.HoveredTileIndex; } this.UpdateExternalDrawMode(); // If the user is in the process of setting or clearing bits, perform the drawing operation if (this.isUserDrawing) { this.PerformUserDrawAction(); } if (lastHoveredArea != this.hoveredArea) { this.TilesetView.InvalidateTile(this.TilesetView.HoveredTileIndex, 0); } }
/// <summary> /// Initializes a new tile with the specified <see cref="BaseIndex"/> and derives all other values /// from their defaults as specified in the provided <see cref="Tileset"/>. /// /// This guarantees that, even for AutoTiles, the specified <see cref="BaseIndex"/> will be used /// directly as-is, without the resolve step adjusting it. When possible, prefer other methods of /// initializing tiles, as this one is more expensive than the others. /// </summary> /// <param name="baseIndex"></param> /// <param name="defaultLookup"></param> public Tile(int baseIndex, ContentRef<Tileset> defaultLookup) { Tileset tileset = defaultLookup.Res; if (tileset == null) throw new ArgumentNullException("defaultLookup"); // As long as not resolved otherwise, use the base index directly. this.Index = baseIndex; this.BaseIndex = baseIndex; this.DepthOffset = 0; // By default, pre-initialize the tile with the AutoTile connectivity state that is // specified for it in the Tileset. This way, when painting the tile unaltered, // resolving it using base index and connectivity state won't replace it with a // different tile. TileInfo tileInfo = tileset.TileData[baseIndex]; int autoTileLayer = tileInfo.AutoTileLayer; if (autoTileLayer != 0) { TilesetAutoTileInfo autoTile = tileset.AutoTileData[autoTileLayer - 1]; IReadOnlyList<TilesetAutoTileItem> autoTileInfo = autoTile.TileInfo; this.AutoTileCon = autoTileInfo[baseIndex].Neighbours; this.BaseIndex = autoTile.BaseTileIndex; } else { this.AutoTileCon = TileConnection.None; } }
private static void DrawConnectivityOutlines(GraphicsPath path, TileConnection connectivity, Rectangle baseRect) { if (connectivity == TileConnection.All) { return; } Rectangle fullRect = baseRect; fullRect.Width -= 1; fullRect.Height -= 1; Rectangle centerRect = GetConnectivityRegionRect(TileConnection.None, baseRect); centerRect.Width -= 1; centerRect.Height -= 1; // Add lines for the 4-neighbourhood that is not connected if (!connectivity.HasFlag(TileConnection.Top)) { path.AddLine(centerRect.Left, centerRect.Top, centerRect.Right, centerRect.Top); path.StartFigure(); } if (!connectivity.HasFlag(TileConnection.Bottom)) { path.AddLine(centerRect.Left, centerRect.Bottom, centerRect.Right, centerRect.Bottom); path.StartFigure(); } if (!connectivity.HasFlag(TileConnection.Left)) { path.AddLine(centerRect.Left, centerRect.Top, centerRect.Left, centerRect.Bottom); path.StartFigure(); } if (!connectivity.HasFlag(TileConnection.Right)) { path.AddLine(centerRect.Right, centerRect.Top, centerRect.Right, centerRect.Bottom); path.StartFigure(); } // Add lines for connectivity borders between the four corners and the main area if (connectivity.HasFlag(TileConnection.TopLeft) && (connectivity.HasFlag(TileConnection.Top) != connectivity.HasFlag(TileConnection.Left))) { path.AddLine(fullRect.Left, fullRect.Top, centerRect.Left, centerRect.Top); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.TopLeft) != connectivity.HasFlag(TileConnection.Top)) { path.AddLine(centerRect.Left, centerRect.Top, centerRect.Left, fullRect.Top); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.TopLeft) != connectivity.HasFlag(TileConnection.Left)) { path.AddLine(centerRect.Left, centerRect.Top, fullRect.Left, centerRect.Top); path.StartFigure(); } } if (connectivity.HasFlag(TileConnection.TopRight) && (connectivity.HasFlag(TileConnection.Top) != connectivity.HasFlag(TileConnection.Right))) { path.AddLine(fullRect.Right, fullRect.Top, centerRect.Right, centerRect.Top); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.TopRight) != connectivity.HasFlag(TileConnection.Top)) { path.AddLine(centerRect.Right, centerRect.Top, centerRect.Right, fullRect.Top); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.TopRight) != connectivity.HasFlag(TileConnection.Right)) { path.AddLine(centerRect.Right, centerRect.Top, fullRect.Right, centerRect.Top); path.StartFigure(); } } if (connectivity.HasFlag(TileConnection.BottomLeft) && (connectivity.HasFlag(TileConnection.Bottom) != connectivity.HasFlag(TileConnection.Left))) { path.AddLine(fullRect.Left, fullRect.Bottom, centerRect.Left, centerRect.Bottom); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.BottomLeft) != connectivity.HasFlag(TileConnection.Bottom)) { path.AddLine(centerRect.Left, centerRect.Bottom, centerRect.Left, fullRect.Bottom); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.BottomLeft) != connectivity.HasFlag(TileConnection.Left)) { path.AddLine(centerRect.Left, centerRect.Bottom, fullRect.Left, centerRect.Bottom); path.StartFigure(); } } if (connectivity.HasFlag(TileConnection.BottomRight) && (connectivity.HasFlag(TileConnection.Bottom) != connectivity.HasFlag(TileConnection.Right))) { path.AddLine(fullRect.Right, fullRect.Bottom, centerRect.Right, centerRect.Bottom); path.StartFigure(); } else { if (connectivity.HasFlag(TileConnection.BottomRight) != connectivity.HasFlag(TileConnection.Bottom)) { path.AddLine(centerRect.Right, centerRect.Bottom, centerRect.Right, fullRect.Bottom); path.StartFigure(); } if (connectivity.HasFlag(TileConnection.BottomRight) != connectivity.HasFlag(TileConnection.Right)) { path.AddLine(centerRect.Right, centerRect.Bottom, fullRect.Right, centerRect.Bottom); path.StartFigure(); } } }
private void TilesetView_MouseMove(object sender, MouseEventArgs e) { Size tileSize = this.TilesetView.DisplayedTileSize; Point tilePos = this.TilesetView.GetTileIndexLocation(this.TilesetView.HoveredTileIndex); Point posOnTile = new Point(e.X - tilePos.X, e.Y - tilePos.Y); Size centerSize = new Size(tileSize.Width / 2, tileSize.Height / 2); // Determine the hovered tile hotspot for user interaction TileConnection lastHoveredArea = this.hoveredArea; if (posOnTile.X > (tileSize.Width - centerSize.Width) / 2 && posOnTile.Y > (tileSize.Height - centerSize.Height) / 2 && posOnTile.X < (tileSize.Width + centerSize.Width) / 2 && posOnTile.Y < (tileSize.Height + centerSize.Height) / 2) { this.hoveredArea = TileConnection.None; } else { float angle = MathF.Angle(tileSize.Width / 2, tileSize.Height / 2, posOnTile.X, posOnTile.Y); float threshold = MathF.DegToRad(22.5f); if (MathF.CircularDist(angle, MathF.DegToRad(315.0f)) <= threshold) this.hoveredArea = TileConnection.TopLeft; else if (MathF.CircularDist(angle, MathF.DegToRad( 0.0f)) <= threshold) this.hoveredArea = TileConnection.Top; else if (MathF.CircularDist(angle, MathF.DegToRad( 45.0f)) <= threshold) this.hoveredArea = TileConnection.TopRight; else if (MathF.CircularDist(angle, MathF.DegToRad(270.0f)) <= threshold) this.hoveredArea = TileConnection.Left; else if (MathF.CircularDist(angle, MathF.DegToRad( 90.0f)) <= threshold) this.hoveredArea = TileConnection.Right; else if (MathF.CircularDist(angle, MathF.DegToRad(225.0f)) <= threshold) this.hoveredArea = TileConnection.BottomLeft; else if (MathF.CircularDist(angle, MathF.DegToRad(180.0f)) <= threshold) this.hoveredArea = TileConnection.Bottom; else this.hoveredArea = TileConnection.BottomRight; } // Update action state TilesetAutoTileInput autoTile = this.SelectedAutoTile; if (autoTile != null) { this.isBaseTileDraw = autoTile.BaseTileIndex == -1 || autoTile.BaseTileIndex == this.TilesetView.HoveredTileIndex; } this.UpdateExternalDrawMode(); // If the user is in the process of setting or clearing bits, perform the drawing operation if (this.isUserDrawing) this.PerformUserDrawAction(); if (lastHoveredArea != this.hoveredArea) this.TilesetView.InvalidateTile(this.TilesetView.HoveredTileIndex, 0); }
private static Rectangle GetConnectivityRegionRect(TileConnection connectivity, Rectangle baseRect) { Size borderSize = new Size( baseRect.Width / 4, baseRect.Height / 4); switch (connectivity) { default: case TileConnection.All: return (baseRect); case TileConnection.TopLeft: return(new Rectangle( baseRect.X, baseRect.Y, borderSize.Width, borderSize.Height)); case TileConnection.Top: return(new Rectangle( baseRect.X + borderSize.Width, baseRect.Y, baseRect.Width - borderSize.Width * 2, borderSize.Height)); case TileConnection.TopRight: return(new Rectangle( baseRect.X + baseRect.Width - borderSize.Width, baseRect.Y, borderSize.Width, borderSize.Height)); case TileConnection.Left: return(new Rectangle( baseRect.X, baseRect.Y + borderSize.Height, borderSize.Width, baseRect.Height - borderSize.Height * 2)); case TileConnection.None: return(new Rectangle( baseRect.X + borderSize.Width, baseRect.Y + borderSize.Height, baseRect.Width - borderSize.Width * 2, baseRect.Height - borderSize.Height * 2)); case TileConnection.Right: return(new Rectangle( baseRect.X + baseRect.Width - borderSize.Width, baseRect.Y + borderSize.Height, borderSize.Width, baseRect.Height - borderSize.Height * 2)); case TileConnection.BottomLeft: return(new Rectangle( baseRect.X, baseRect.Y + baseRect.Height - borderSize.Height, borderSize.Width, borderSize.Height)); case TileConnection.Bottom: return(new Rectangle( baseRect.X + borderSize.Width, baseRect.Y + baseRect.Height - borderSize.Height, baseRect.Width - borderSize.Width * 2, borderSize.Height)); case TileConnection.BottomRight: return(new Rectangle( baseRect.X + baseRect.Width - borderSize.Width, baseRect.Y + baseRect.Height - borderSize.Height, borderSize.Width, borderSize.Height)); } }
public IReadOnlyList<TileConnection> GetFallback(TileConnection connection) { return this.data[(int)connection] ?? NoFallbacks; }