/// <summary>
 /// [GET / SET] The collision shape on a given layer index from zero to (<see cref="LayerCount"/> - 1).
 /// </summary>
 /// <param name="layerIndex"></param>
 /// <returns></returns>
 public TileCollisionShape this[int layerIndex]
 {
     get
     {
         switch (layerIndex)
         {
             case 0: return this.Layer0;
             case 1: return this.Layer1;
             case 2: return this.Layer2;
             case 3: return this.Layer3;
         }
         throw new IndexOutOfRangeException("Invalid collision layer index");
     }
     set
     {
         switch (layerIndex)
         {
             case 0: this.Layer0 = value; return;
             case 1: this.Layer1 = value; return;
             case 2: this.Layer2 = value; return;
             case 3: this.Layer3 = value; return;
         }
         throw new IndexOutOfRangeException("Invalid collision layer index");
     }
 }
Exemple #2
0
        /// <summary>
        /// [GET / SET] The collision shape on a given layer index from zero to (<see cref="LayerCount"/> - 1).
        /// </summary>
        /// <param name="layerIndex"></param>
        /// <returns></returns>
        public                     TileCollisionShape this[int layerIndex]
        {
            get
            {
                switch (layerIndex)
                {
                case 0: return(this.Layer0);

                case 1: return(this.Layer1);

                case 2: return(this.Layer2);

                case 3: return(this.Layer3);
                }
                throw new IndexOutOfRangeException("Invalid collision layer index");
            }
            set
            {
                switch (layerIndex)
                {
                case 0: this.Layer0 = value; return;

                case 1: this.Layer1 = value; return;

                case 2: this.Layer2 = value; return;

                case 3: this.Layer3 = value; return;
                }
                throw new IndexOutOfRangeException("Invalid collision layer index");
            }
        }
Exemple #3
0
        private static void AddFenceCollisionEdges(Grid <TileCollisionShape> collisionData, TileEdgeMap targetEdgeMap)
        {
            // Populate the edge map with all the collision fences
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    TileCollisionShape collision = collisionData[x, y];

                    // Skip both free and completely solid tiles
                    if (collision == TileCollisionShape.Free)
                    {
                        continue;
                    }
                    if ((collision & TileCollisionShape.Solid) == TileCollisionShape.Solid)
                    {
                        continue;
                    }

                    // Add the various fence collision types
                    if ((collision & TileCollisionShape.Top) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y));
                    }
                    if ((collision & TileCollisionShape.Bottom) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    }
                    if ((collision & TileCollisionShape.Left) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x, y + 1));
                    }
                    if ((collision & TileCollisionShape.Right) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    }
                    if ((collision & TileCollisionShape.DiagonalDown) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y + 1));
                    }
                    if ((collision & TileCollisionShape.DiagonalUp) != TileCollisionShape.Free)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y));
                    }
                }
            }
        }
Exemple #4
0
        private int MergeCollisionData(int sectorX, int sectorY, Grid <TileCollisionShape> target)
        {
            Point2 beginTile = new Point2(sectorX * SectorSize, sectorY * SectorSize);
            Point2 endTile   = new Point2((sectorX + 1) * SectorSize, (sectorY + 1) * SectorSize);

            endTile.X = Math.Min(endTile.X, this.tileCount.X);
            endTile.Y = Math.Min(endTile.Y, this.tileCount.Y);

            TileInfo[][] tileData = GetRawTileData(this.sourceTilemaps);

            // Start with a non-zero checksum, so it doesn't equal the uninitialized sector checksum
            int checksum = 1;

            for (int y = beginTile.Y; y < endTile.Y; y++)
            {
                for (int x = beginTile.X; x < endTile.X; x++)
                {
                    TileCollisionShape mergedCollision = TileCollisionShape.Free;
                    for (int i = 0; i < this.sourceTilemaps.Length; i++)
                    {
                        if (this.sourceTilemaps[i] == null)
                        {
                            continue;
                        }
                        if (tileData[i] == null)
                        {
                            continue;
                        }

                        Tile tile = this.sourceTilemaps[i].Tiles[x, y];
                        TileCollisionShape collision = tileData[i][tile.Index].Collision[this.source[i].Layers];
                        mergedCollision |= collision;
                    }
                    target[x - beginTile.X, y - beginTile.Y] = mergedCollision;
                    MathF.CombineHashCode(ref checksum, (int)mergedCollision);
                }
            }

            return(checksum);
        }
Exemple #5
0
        private void PerformUserDrawAction()
        {
            Tileset tileset = this.SelectedTileset.Res;

            if (tileset == null)
            {
                return;
            }

            int tileIndex = this.TilesetView.HoveredTileIndex;

            if (tileIndex < 0 || tileIndex > tileset.TileCount)
            {
                return;
            }

            TileInput          input         = tileset.TileInput.Count > tileIndex ? tileset.TileInput[tileIndex] : default(TileInput);
            TileCollisionShape lastCollision = input.Collision[this.editLayerIndex];

            if (this.drawMode == CollisionDrawMode.Add)
            {
                input.Collision[this.editLayerIndex] |= this.drawShape;
            }
            else if (this.drawMode == CollisionDrawMode.Remove)
            {
                input.Collision[this.editLayerIndex] &= ~this.drawShape;
            }
            else
            {
                input.Collision[this.editLayerIndex] = this.drawShape;
            }

            TileCollisionShape newCollision = input.Collision[this.editLayerIndex];

            if (lastCollision != newCollision)
            {
                UndoRedoManager.Do(new EditTilesetTileInputAction(tileset, tileIndex, input));
            }
        }
Exemple #6
0
 /// <summary>
 /// [GET] The collision shape on the specified (set of) layer(s).
 /// </summary>
 /// <param name="layerMask"></param>
 /// <returns></returns>
 public                     TileCollisionShape this[TileCollisionLayer layerMask]
 {
     get
     {
         TileCollisionShape result = TileCollisionShape.Free;
         if ((layerMask & TileCollisionLayer.Layer0) != TileCollisionLayer.None)
         {
             result |= this.Layer0;
         }
         if ((layerMask & TileCollisionLayer.Layer1) != TileCollisionLayer.None)
         {
             result |= this.Layer1;
         }
         if ((layerMask & TileCollisionLayer.Layer2) != TileCollisionLayer.None)
         {
             result |= this.Layer2;
         }
         if ((layerMask & TileCollisionLayer.Layer3) != TileCollisionLayer.None)
         {
             result |= this.Layer3;
         }
         return(result);
     }
 }
Exemple #7
0
        private static void AddBlockCollisionEdges(Grid <TileCollisionShape> collisionData, TileEdgeMap targetEdgeMap, Point2 edgeMapPos, Point2 totalSize)
        {
            int leftBorderPos   = 0 - edgeMapPos.X;
            int rightBorderPos  = totalSize.X - edgeMapPos.X;
            int topBorderPos    = 0 - edgeMapPos.Y;
            int bottomBorderPos = totalSize.Y - edgeMapPos.Y;

            // Add block geometry to the specified edge map
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    // Skip non-solid blocks
                    bool center = (collisionData[x, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    if (!center)
                    {
                        continue;
                    }

                    // A filled block will always overwrite its inner diagonal edges
                    targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y + 1));
                    targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y));

                    // Determine block collision neighbourhood
                    bool left   = (x == 0)              ? (x == leftBorderPos) : (collisionData[x - 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool right  = (x == SectorSize - 1) ? (x == rightBorderPos) : (collisionData[x + 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool top    = (y == 0)              ? (y == topBorderPos) : (collisionData[x, y - 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool bottom = (y == SectorSize - 1) ? (y == bottomBorderPos) : (collisionData[x, y + 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;

                    // Adjust outer edge states
                    if (center != left)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x, y + 1));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                    }
                    if (center != right)
                    {
                        targetEdgeMap.AddEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                    }
                    if (center != top)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y), new Point2(x + 1, y));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                    }
                    if (center != bottom)
                    {
                        targetEdgeMap.AddEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    }
                    else
                    {
                        targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                    }
                }
            }

            // Detect diagonal fences next to solid blocks and remove the
            // edges that might have become redundant. This can't be done
            // in the above loop without complicating control flow, so it's
            // done here.
            for (int y = 0; y < SectorSize; y++)
            {
                for (int x = 0; x < SectorSize; x++)
                {
                    TileCollisionShape centerShape = collisionData[x, y];
                    bool diagonalDown = (centerShape & TileCollisionShape.DiagonalDown) == TileCollisionShape.DiagonalDown;
                    bool diagonalUp   = (centerShape & TileCollisionShape.DiagonalUp) == TileCollisionShape.DiagonalUp;

                    // Skip tiles that aren't diagonal fences
                    if (!diagonalDown && !diagonalUp)
                    {
                        continue;
                    }

                    // Determine block collision neighbourhood
                    bool left   = (x == 0)              ? (x == leftBorderPos) : (collisionData[x - 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool right  = (x == SectorSize - 1) ? (x == rightBorderPos) : (collisionData[x + 1, y] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool top    = (y == 0)              ? (y == topBorderPos) : (collisionData[x, y - 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;
                    bool bottom = (y == SectorSize - 1) ? (y == bottomBorderPos) : (collisionData[x, y + 1] & TileCollisionShape.Solid) == TileCollisionShape.Solid;

                    // Remove perpendicular edges that are redundant because of the diagonal fence
                    // connecting two adjacent solid blocks.
                    if (diagonalDown)
                    {
                        if (top && right)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                            targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                        }
                        if (bottom && left)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                        }
                    }
                    else
                    {
                        if (top && left)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x + 1, y));
                            targetEdgeMap.RemoveEdge(new Point2(x, y), new Point2(x, y + 1));
                        }
                        if (bottom && right)
                        {
                            targetEdgeMap.RemoveEdge(new Point2(x, y + 1), new Point2(x + 1, y + 1));
                            targetEdgeMap.RemoveEdge(new Point2(x + 1, y), new Point2(x + 1, y + 1));
                        }
                    }
                }
            }
        }
Exemple #8
0
        private void TilesetView_MouseDown(object sender, MouseEventArgs e)
        {
            Tileset tileset = this.SelectedTileset.Res;

            if (tileset == null)
            {
                return;
            }

            int tileIndex = this.TilesetView.HoveredTileIndex;

            if (tileIndex < 0 || tileIndex > tileset.TileCount)
            {
                return;
            }

            // Conditional toggle operation on left click
            if (e.Button == MouseButtons.Left)
            {
                TileInput          input     = tileset.TileInput.Count > tileIndex ? tileset.TileInput[tileIndex] : default(TileInput);
                TileCollisionShape collision = input.Collision[this.editLayerIndex];
                this.drawSimple = false;
                switch (this.hoveredArea)
                {
                case TileHotSpot.Left:
                    this.drawShape = TileCollisionShape.Left;
                    this.drawMode  = !collision.HasFlag(TileCollisionShape.Left) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                    break;

                case TileHotSpot.Right:
                    this.drawShape = TileCollisionShape.Right;
                    this.drawMode  = !collision.HasFlag(TileCollisionShape.Right) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                    break;

                case TileHotSpot.Top:
                    this.drawShape = TileCollisionShape.Top;
                    this.drawMode  = !collision.HasFlag(TileCollisionShape.Top) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                    break;

                case TileHotSpot.Bottom:
                    this.drawShape = TileCollisionShape.Bottom;
                    this.drawMode  = !collision.HasFlag(TileCollisionShape.Bottom) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                    break;

                default:
                    if (collision == TileCollisionShape.Free)
                    {
                        this.drawSimple = true;
                        this.drawMode   = CollisionDrawMode.Set;
                        this.drawShape  = TileCollisionShape.Solid;
                    }
                    else if (collision == TileCollisionShape.Solid)
                    {
                        this.drawMode  = CollisionDrawMode.Set;
                        this.drawShape = TileCollisionShape.DiagonalUp;
                    }
                    else if (collision.HasFlag(TileCollisionShape.DiagonalUp))
                    {
                        this.drawMode  = CollisionDrawMode.Set;
                        this.drawShape = TileCollisionShape.DiagonalDown;
                    }
                    else if (collision.HasFlag(TileCollisionShape.DiagonalDown))
                    {
                        this.drawMode  = CollisionDrawMode.Set;
                        this.drawShape = TileCollisionShape.Free;
                    }
                    else
                    {
                        this.drawMode  = CollisionDrawMode.Set;
                        this.drawShape = TileCollisionShape.Solid;
                    }
                    break;
                }
                this.isUserDrawing = true;
            }
            // Clear operation on right click
            else if (e.Button == MouseButtons.Right)
            {
                this.drawSimple    = true;
                this.drawShape     = TileCollisionShape.Free;
                this.drawMode      = CollisionDrawMode.Set;
                this.isUserDrawing = true;
            }

            // Perform the drawing operation
            this.PerformUserDrawAction();
            this.TilesetView.InvalidateTile(tileIndex, 0);
        }
Exemple #9
0
        private void TilesetView_PaintTiles(object sender, TilesetViewPaintTilesEventArgs e)
        {
            Color colorFree      = Color.White;
            Color colorCollision = Color.FromArgb(128, 192, 255);

            TileInput[] tileInput = e.Tileset.TileInput.Data;
            for (int i = 0; i < e.PaintedTiles.Count; i++)
            {
                TilesetViewPaintTileData paintData = e.PaintedTiles[i];

                // Prepare some data we'll need for drawing the tile collision info overlay
                TileCollisionShape collision = TileCollisionShape.Free;
                if (tileInput.Length > paintData.TileIndex)
                {
                    collision = tileInput[paintData.TileIndex].Collision[this.editLayerIndex];
                }
                bool tileHovered     = this.TilesetView.HoveredTileIndex == paintData.TileIndex;
                bool simpleCollision =
                    collision == TileCollisionShape.Solid ||
                    collision == TileCollisionShape.Free;

                // Draw the center icon indicating the tiles simple solid / free state, as well as diagonal slopes
                {
                    bool centerIsCollision =
                        collision == TileCollisionShape.Solid ||
                        collision.HasFlag(TileCollisionShape.DiagonalUp) ||
                        collision.HasFlag(TileCollisionShape.DiagonalDown);

                    Bitmap centerImage;
                    if (collision == TileCollisionShape.Solid)
                    {
                        centerImage = TilemapsResCache.TilesetCollisionBit;
                    }
                    else if (collision.HasFlag(TileCollisionShape.DiagonalUp))
                    {
                        centerImage = TilemapsResCache.TilesetCollisionDiagUp;
                    }
                    else if (collision.HasFlag(TileCollisionShape.DiagonalDown))
                    {
                        centerImage = TilemapsResCache.TilesetCollisionDiagDown;
                    }
                    else
                    {
                        centerImage = TilemapsResCache.TilesetCollisionBit;
                    }

                    Color centerColor;
                    if (centerIsCollision)
                    {
                        centerColor = colorCollision;
                    }
                    else
                    {
                        centerColor = colorFree;
                    }

                    e.Graphics.DrawImageTint(
                        centerImage,
                        Color.FromArgb(GetCollisionIconAlpha(
                                           tileHovered,
                                           this.hoveredArea == TileHotSpot.Center,
                                           centerIsCollision), centerColor),
                        paintData.ViewRect.X + (paintData.ViewRect.Width - centerImage.Width) / 2,
                        paintData.ViewRect.Y + (paintData.ViewRect.Height - centerImage.Height) / 2);
                }

                // Draw collision icons for specific directional passability.
                if (!simpleCollision || (tileHovered && (!this.isUserDrawing || !this.drawSimple)))
                {
                    e.Graphics.DrawImageTint(
                        TilemapsResCache.TilesetCollisionVertical,
                        Color.FromArgb(GetCollisionIconAlpha(
                                           tileHovered,
                                           this.hoveredArea == TileHotSpot.Right,
                                           !simpleCollision && collision.HasFlag(TileCollisionShape.Right)),
                                       collision.HasFlag(TileCollisionShape.Right) ? colorCollision : colorFree),
                        paintData.ViewRect.X + paintData.ViewRect.Width - TilemapsResCache.TilesetCollisionVertical.Width - 1,
                        paintData.ViewRect.Y + (paintData.ViewRect.Height - TilemapsResCache.TilesetCollisionVertical.Height) / 2);
                    e.Graphics.DrawImageTint(
                        TilemapsResCache.TilesetCollisionVertical,
                        Color.FromArgb(GetCollisionIconAlpha(
                                           tileHovered,
                                           this.hoveredArea == TileHotSpot.Left,
                                           !simpleCollision && collision.HasFlag(TileCollisionShape.Left)),
                                       collision.HasFlag(TileCollisionShape.Left) ? colorCollision : colorFree),
                        paintData.ViewRect.X + 1,
                        paintData.ViewRect.Y + (paintData.ViewRect.Height - TilemapsResCache.TilesetCollisionVertical.Height) / 2);
                    e.Graphics.DrawImageTint(
                        TilemapsResCache.TilesetCollisionHorizontal,
                        Color.FromArgb(GetCollisionIconAlpha(
                                           tileHovered,
                                           this.hoveredArea == TileHotSpot.Top,
                                           !simpleCollision && collision.HasFlag(TileCollisionShape.Top)),
                                       collision.HasFlag(TileCollisionShape.Top) ? colorCollision : colorFree),
                        paintData.ViewRect.X + (paintData.ViewRect.Width - TilemapsResCache.TilesetCollisionHorizontal.Width) / 2,
                        paintData.ViewRect.Y + 1);
                    e.Graphics.DrawImageTint(
                        TilemapsResCache.TilesetCollisionHorizontal,
                        Color.FromArgb(GetCollisionIconAlpha(
                                           tileHovered,
                                           this.hoveredArea == TileHotSpot.Bottom,
                                           !simpleCollision && collision.HasFlag(TileCollisionShape.Bottom)),
                                       collision.HasFlag(TileCollisionShape.Bottom) ? colorCollision : colorFree),
                        paintData.ViewRect.X + (paintData.ViewRect.Width - TilemapsResCache.TilesetCollisionHorizontal.Width) / 2,
                        paintData.ViewRect.Y + paintData.ViewRect.Height - TilemapsResCache.TilesetCollisionHorizontal.Height - 1);
                }
            }
        }
Exemple #10
0
 private static bool IsSolid(TileCollisionShape tileCollisionShape)
 {
     return(tileCollisionShape == TileCollisionShape.Solid || tileCollisionShape == TileCollisionShape.DiagonalDown || tileCollisionShape == TileCollisionShape.DiagonalUp);
 }
        private void TilesetView_MouseDown(object sender, MouseEventArgs e)
        {
            Tileset tileset = this.SelectedTileset.Res;
            if (tileset == null) return;

            int tileIndex = this.TilesetView.HoveredTileIndex;
            if (tileIndex < 0 || tileIndex > tileset.TileCount) return;

            // Conditional toggle operation on left click
            if (e.Button == MouseButtons.Left)
            {
                TileInput input = tileset.TileInput.Count > tileIndex ? tileset.TileInput[tileIndex] : default(TileInput);
                TileCollisionShape collision = input.Collision[this.editLayerIndex];
                this.drawSimple = false;
                switch (this.hoveredArea)
                {
                    case TileHotSpot.Left:
                        this.drawShape = TileCollisionShape.Left;
                        this.drawMode = !collision.HasFlag(TileCollisionShape.Left) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                        break;
                    case TileHotSpot.Right:
                        this.drawShape = TileCollisionShape.Right;
                        this.drawMode = !collision.HasFlag(TileCollisionShape.Right) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                        break;
                    case TileHotSpot.Top:
                        this.drawShape = TileCollisionShape.Top;
                        this.drawMode = !collision.HasFlag(TileCollisionShape.Top) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                        break;
                    case TileHotSpot.Bottom:
                        this.drawShape = TileCollisionShape.Bottom;
                        this.drawMode = !collision.HasFlag(TileCollisionShape.Bottom) ? CollisionDrawMode.Add : CollisionDrawMode.Remove;
                        break;
                    default:
                        if (collision == TileCollisionShape.Free)
                        {
                            this.drawSimple = true;
                            this.drawMode = CollisionDrawMode.Set;
                            this.drawShape = TileCollisionShape.Solid;
                        }
                        else if (collision == TileCollisionShape.Solid)
                        {
                            this.drawMode = CollisionDrawMode.Set;
                            this.drawShape = TileCollisionShape.DiagonalUp;
                        }
                        else if (collision.HasFlag(TileCollisionShape.DiagonalUp))
                        {
                            this.drawMode = CollisionDrawMode.Set;
                            this.drawShape = TileCollisionShape.DiagonalDown;
                        }
                        else if (collision.HasFlag(TileCollisionShape.DiagonalDown))
                        {
                            this.drawMode = CollisionDrawMode.Set;
                            this.drawShape = TileCollisionShape.Free;
                        }
                        else
                        {
                            this.drawMode = CollisionDrawMode.Set;
                            this.drawShape = TileCollisionShape.Solid;
                        }
                        break;
                }
                this.isUserDrawing = true;
            }
            // Clear operation on right click
            else if (e.Button == MouseButtons.Right)
            {
                this.drawSimple = true;
                this.drawShape = TileCollisionShape.Free;
                this.drawMode = CollisionDrawMode.Set;
                this.isUserDrawing = true;
            }

            // Perform the drawing operation
            this.PerformUserDrawAction();
            this.TilesetView.InvalidateTile(tileIndex, 0);
        }