コード例 #1
0
        /// <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);
        }
コード例 #2
0
 public TileConnectionMarker(TileConnection connection, Pen sourcePen, Pen destinationPen, Pen linePen)
 {
     this.connection     = connection;
     this.SourcePen      = sourcePen;
     this.DestinationPen = destinationPen;
     this.LinePen        = linePen;
 }
コード例 #3
0
        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);
        }
コード例 #4
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;
            }
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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());
        }
コード例 #7
0
        /// <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;
        }
コード例 #8
0
ファイル: Tile.cs プロジェクト: SirePi/duality
 /// <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;
 }
コード例 #9
0
 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;
 }
コード例 #10
0
 /// <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;
 }
コード例 #11
0
ファイル: Level.cs プロジェクト: krisz2000/hevadea
        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;
            }
        }
コード例 #12
0
        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;
        }
コード例 #13
0
        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;
        }
コード例 #14
0
        /// <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);
        }
コード例 #15
0
        /// <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);
        }
コード例 #16
0
        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();
                }
        }
コード例 #17
0
 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();
 }
コード例 #18
0
    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());
    }
コード例 #19
0
        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));
        }
コード例 #20
0
        /// <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;
                }
            }
        }
コード例 #21
0
        /// <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;
            }
        }
コード例 #22
0
ファイル: Chunk.cs プロジェクト: krisz2000/hevadea
        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>();
                }
            }
        }
コード例 #23
0
        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);
        }
コード例 #24
0
        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());
        }
コード例 #25
0
        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());
        }
コード例 #26
0
ファイル: AStarPath.cs プロジェクト: elliot-winch/Vampiric
    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);
    }
コード例 #27
0
        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();
                }
            }
        }
コード例 #28
0
        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));
                }
            }
        }
コード例 #29
0
        /// <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);
                }
            }
        }
コード例 #30
0
        /// <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;
            }
        }
コード例 #31
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);
     }
 }
コード例 #32
0
 public AddTrapConnectionCommand(TileConnection connection)
 {
     this.connection = connection;
 }
コード例 #33
0
        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);
        }
コード例 #34
0
        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));
                }
            }
        }
コード例 #35
0
        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);
            }
        }
コード例 #36
0
ファイル: Tile.cs プロジェクト: SirePi/duality
        /// <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;
            }
        }
コード例 #37
0
ファイル: Tile.cs プロジェクト: SirePi/duality
        /// <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;
                }
            }
        }
コード例 #38
0
        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();
                }
            }
        }
コード例 #39
0
        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);
        }
コード例 #40
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));
            }
        }
コード例 #41
0
 public IReadOnlyList<TileConnection> GetFallback(TileConnection connection)
 {
     return this.data[(int)connection] ?? NoFallbacks;
 }