Ejemplo n.º 1
0
    // helper method to get all the tiles that are above/below/right/left of a specific tile
    private List <LineTile> GetTilesSurroundingTile(LineTile tile)
    {
        List <LineTile> surroundingTiles = new List <LineTile>();

        int xIndex = tile.tileIndex.xIndex;
        int yIndex = tile.tileIndex.yIndex;

        if (xIndex > 0)
        {
            surroundingTiles.Add(tileMap[xIndex - 1][yIndex]);
        }
        if (xIndex < tileMapWidth - 1)
        {
            surroundingTiles.Add(tileMap[xIndex + 1][yIndex]);
        }

        if (yIndex > 0)
        {
            surroundingTiles.Add(tileMap[xIndex][yIndex - 1]);
        }
        if (yIndex < tileMapHeight - 1)
        {
            surroundingTiles.Add(tileMap[xIndex][yIndex + 1]);
        }

        return(surroundingTiles);
    }
Ejemplo n.º 2
0
    private void InitTileMap()
    {
        // setup overall container and place it in the middle of the screen
        boardContainer   = new FContainer();
        boardContainer.x = Futile.screen.halfWidth - tileMapWidth * tileSize / 2f;
        boardContainer.y = Futile.screen.halfHeight - tileMapHeight * tileSize / 2f;
        AddChild(boardContainer);

        // create the blank background tiles
        for (int i = 0; i < tileMapWidth; i++)
        {
            for (int j = 0; j < tileMapHeight; j++)
            {
                FSprite backgroundTile = new FSprite("WhiteBox");
                backgroundTile.width = backgroundTile.height = tileSize;
                backgroundTile.color = new Color(0.2f, 0.2f, 0.2f);
                backgroundTile.x     = (i + 0.5f) * tileSize;
                backgroundTile.y     = (j + 0.5f) * tileSize;
                boardContainer.AddChild(backgroundTile);
            }
        }

        // create random tiles and fill the board with them
        tileMap = new LineTile[tileMapWidth][];
        for (int i = 0; i < tileMapWidth; i++)
        {
            tileMap[i] = new LineTile[tileMapHeight];
            for (int j = 0; j < tileMapHeight; j++)
            {
                LineTileType randomTileType     = (LineTileType)Random.Range(0, (int)LineTileType.MAX);
                RotationType randomRotationType = (RotationType)Random.Range(0, (int)RotationType.MAX);
                LineTile     newTile            = new LineTile(randomTileType, randomRotationType);
                newTile.tileIndex.xIndex = i;
                newTile.tileIndex.yIndex = j;
                newTile.sprite.width     = newTile.sprite.height = tileSize;
                tileMap[i][j]            = newTile;
                newTile.x = (i + 0.5f) * tileSize;
                newTile.y = (j + 0.5f) * tileSize;
                boardContainer.AddChild(newTile);
            }
        }

        // create the tile outlines
        for (int i = 0; i < tileMapWidth; i++)
        {
            for (int j = 0; j < tileMapHeight; j++)
            {
                FSprite backgroundTile = new FSprite("lineTileOutline");
                backgroundTile.width = backgroundTile.height = tileSize;
                backgroundTile.color = new Color(0.2f, 0.2f, 0.2f);
                backgroundTile.x     = (i + 0.5f) * tileSize;
                backgroundTile.y     = (j + 0.5f) * tileSize;
                boardContainer.AddChild(backgroundTile);
            }
        }
    }
Ejemplo n.º 3
0
    // helper function to see if a tile already belongs to a match group
    private bool TileIsAlreadyInMatchGroup(LineTile tile)
    {
        bool tileIsAlreadyInMatchGroup = false;

        foreach (MatchGroup matchGroup in matchGroups)
        {
            if (matchGroup.tiles.Contains(tile))
            {
                tileIsAlreadyInMatchGroup = true;
                break;
            }
        }

        return(tileIsAlreadyInMatchGroup);
    }
Ejemplo n.º 4
0
    // helper method to get all the tiles in a specific row
    private LineTile[] GetRowTiles(int rowIndex)
    {
        if (rowIndex < 0 || rowIndex >= tileMapHeight)
        {
            throw new FutileException("invalid column: " + rowIndex);
        }

        LineTile[] rowTiles = new LineTile[tileMapWidth];

        for (int i = 0; i < tileMapWidth; i++)
        {
            rowTiles[i] = tileMap[i][rowIndex];
        }

        return(rowTiles);
    }
Ejemplo n.º 5
0
    // helper method to get all the tiles in a specific column
    private LineTile[] GetColumnTiles(int columnIndex)
    {
        if (columnIndex < 0 || columnIndex >= tileMapWidth)
        {
            throw new FutileException("invalid column: " + columnIndex);
        }

        LineTile[] columnTiles = new LineTile[tileMapHeight];

        for (int j = 0; j < tileMapHeight; j++)
        {
            columnTiles[j] = tileMap[columnIndex][j];
        }

        return(columnTiles);
    }
Ejemplo n.º 6
0
    // there are three types of connections two tiles can have.
    // 1. ValidWithSolidMatch: this means the tiles are accurately matched with their solid sides connected
    // 2. ValidWithOpenSide: this means the baseTile has an open side touching the other tile, so it doesn't matter what the other tile is
    // 3. Invalid: this means the baseTile's solid side is matched with the other tile's open side, resulting in a mismatch
    private TileConnectionType TileConnectionTypeBetweenTiles(LineTile baseTile, LineTile otherTile)
    {
        int baseTileBitmaskSide  = baseTile.bitmask;        // the bitmask for the specific baseTile side that is touching the other tile
        int otherTileBitmaskSide = otherTile.bitmask;       // the bitmask for the specific otherTile side that is touching the base tile

        // depending on which side of the base tile the other tile is on, bitwise & each side together with
        // the bitwise constant for that individual side. if the result is 0, then the side is open. otherwise,
        // the side is solid.
        if (otherTile.tileIndex.yIndex < baseTile.tileIndex.yIndex)
        {
            baseTileBitmaskSide  &= LineTile.kBitmaskBottom;
            otherTileBitmaskSide &= LineTile.kBitmaskTop;
        }
        else if (otherTile.tileIndex.yIndex > baseTile.tileIndex.yIndex)
        {
            baseTileBitmaskSide  &= LineTile.kBitmaskTop;
            otherTileBitmaskSide &= LineTile.kBitmaskBottom;
        }
        else if (otherTile.tileIndex.xIndex < baseTile.tileIndex.xIndex)
        {
            baseTileBitmaskSide  &= LineTile.kBitmaskLeft;
            otherTileBitmaskSide &= LineTile.kBitmaskRight;
        }
        else if (otherTile.tileIndex.xIndex > baseTile.tileIndex.xIndex)
        {
            baseTileBitmaskSide  &= LineTile.kBitmaskRight;
            otherTileBitmaskSide &= LineTile.kBitmaskLeft;
        }

        if (baseTileBitmaskSide == 0)
        {
            return(TileConnectionType.ValidWithOpenSide);                                  // baseTile side touching otherTile is open
        }
        else if (otherTileBitmaskSide != 0)
        {
            return(TileConnectionType.ValidWithSolidMatch);                                        // baseTile side and otherTile side are solid and matched
        }
        else
        {
            return(TileConnectionType.Invalid);         // baseTile side is solid but otherTile side is open. mismatch!
        }
    }
    // helper function to see if a tile already belongs to a match group
    private bool TileIsAlreadyInMatchGroup(LineTile tile)
    {
        bool tileIsAlreadyInMatchGroup = false;

        foreach (MatchGroup matchGroup in matchGroups) {
            if (matchGroup.tiles.Contains(tile)) {
                tileIsAlreadyInMatchGroup = true;
                break;
            }
        }

        return tileIsAlreadyInMatchGroup;
    }
    // there are three types of connections two tiles can have.
    // 1. ValidWithSolidMatch: this means the tiles are accurately matched with their solid sides connected
    // 2. ValidWithOpenSide: this means the baseTile has an open side touching the other tile, so it doesn't matter what the other tile is
    // 3. Invalid: this means the baseTile's solid side is matched with the other tile's open side, resulting in a mismatch
    private TileConnectionType TileConnectionTypeBetweenTiles(LineTile baseTile, LineTile otherTile)
    {
        int baseTileBitmaskSide = baseTile.bitmask; // the bitmask for the specific baseTile side that is touching the other tile
        int otherTileBitmaskSide = otherTile.bitmask; // the bitmask for the specific otherTile side that is touching the base tile

        // depending on which side of the base tile the other tile is on, bitwise & each side together with
        // the bitwise constant for that individual side. if the result is 0, then the side is open. otherwise,
        // the side is solid.
        if (otherTile.tileIndex.yIndex < baseTile.tileIndex.yIndex) {
            baseTileBitmaskSide &= LineTile.kBitmaskBottom;
            otherTileBitmaskSide &= LineTile.kBitmaskTop;
        }
        else if (otherTile.tileIndex.yIndex > baseTile.tileIndex.yIndex) {
            baseTileBitmaskSide &= LineTile.kBitmaskTop;
            otherTileBitmaskSide &= LineTile.kBitmaskBottom;
        }
        else if (otherTile.tileIndex.xIndex < baseTile.tileIndex.xIndex) {
            baseTileBitmaskSide &= LineTile.kBitmaskLeft;
            otherTileBitmaskSide &= LineTile.kBitmaskRight;
        }
        else if (otherTile.tileIndex.xIndex > baseTile.tileIndex.xIndex) {
            baseTileBitmaskSide &= LineTile.kBitmaskRight;
            otherTileBitmaskSide &= LineTile.kBitmaskLeft;
        }

        if (baseTileBitmaskSide == 0) return TileConnectionType.ValidWithOpenSide; // baseTile side touching otherTile is open
        else if (otherTileBitmaskSide != 0) return TileConnectionType.ValidWithSolidMatch; // baseTile side and otherTile side are solid and matched
        else return TileConnectionType.Invalid; // baseTile side is solid but otherTile side is open. mismatch!
    }
    private void InitTileMap()
    {
        // setup overall container and place it in the middle of the screen
        boardContainer = new FContainer();
        boardContainer.x = Futile.screen.halfWidth - tileMapWidth * tileSize / 2f;
        boardContainer.y = Futile.screen.halfHeight - tileMapHeight * tileSize / 2f;
        AddChild(boardContainer);

        // create the blank background tiles
        for (int i = 0; i < tileMapWidth; i++) {
            for (int j = 0; j < tileMapHeight; j++) {
                FSprite backgroundTile = new FSprite("WhiteBox");
                backgroundTile.width = backgroundTile.height = tileSize;
                backgroundTile.color = new Color(0.2f, 0.2f, 0.2f);
                backgroundTile.x = (i + 0.5f) * tileSize;
                backgroundTile.y = (j + 0.5f) * tileSize;
                boardContainer.AddChild(backgroundTile);
            }
        }

        // create random tiles and fill the board with them
        tileMap = new LineTile[tileMapWidth][];
        for (int i = 0; i < tileMapWidth; i++) {
            tileMap[i] = new LineTile[tileMapHeight];
            for (int j = 0; j < tileMapHeight; j++) {
                LineTileType randomTileType = (LineTileType)Random.Range(0, (int)LineTileType.MAX);
                RotationType randomRotationType = (RotationType)Random.Range(0, (int)RotationType.MAX);
                LineTile newTile = new LineTile(randomTileType, randomRotationType);
                newTile.tileIndex.xIndex = i;
                newTile.tileIndex.yIndex = j;
                newTile.sprite.width = newTile.sprite.height = tileSize;
                tileMap[i][j] = newTile;
                newTile.x = (i + 0.5f) * tileSize;
                newTile.y = (j + 0.5f) * tileSize;
                boardContainer.AddChild(newTile);
            }
        }

        // create the tile outlines
        for (int i = 0; i < tileMapWidth; i++) {
            for (int j = 0; j < tileMapHeight; j++) {
                FSprite backgroundTile = new FSprite("lineTileOutline");
                backgroundTile.width = backgroundTile.height = tileSize;
                backgroundTile.color = new Color(0.2f, 0.2f, 0.2f);
                backgroundTile.x = (i + 0.5f) * tileSize;
                backgroundTile.y = (j + 0.5f) * tileSize;
                boardContainer.AddChild(backgroundTile);
            }
        }
    }
    // helper method to get all the tiles that are above/below/right/left of a specific tile
    private List<LineTile> GetTilesSurroundingTile(LineTile tile)
    {
        List<LineTile> surroundingTiles = new List<LineTile>();

        int xIndex = tile.tileIndex.xIndex;
        int yIndex = tile.tileIndex.yIndex;

        if (xIndex > 0) surroundingTiles.Add(tileMap[xIndex - 1][yIndex]);
        if (xIndex < tileMapWidth - 1) surroundingTiles.Add(tileMap[xIndex + 1][yIndex]);

        if (yIndex > 0) surroundingTiles.Add(tileMap[xIndex][yIndex - 1]);
        if (yIndex < tileMapHeight - 1) surroundingTiles.Add(tileMap[xIndex][yIndex + 1]);

        return surroundingTiles;
    }
    // helper method to get all the tiles in a specific row
    private LineTile[] GetRowTiles(int rowIndex)
    {
        if (rowIndex < 0 || rowIndex >= tileMapHeight) throw new FutileException("invalid column: " + rowIndex);

        LineTile[] rowTiles = new LineTile[tileMapWidth];

        for (int i = 0; i < tileMapWidth; i++) rowTiles[i] = tileMap[i][rowIndex];

        return rowTiles;
    }
    // helper method to get all the tiles in a specific column
    private LineTile[] GetColumnTiles(int columnIndex)
    {
        if (columnIndex < 0 || columnIndex >= tileMapWidth) throw new FutileException("invalid column: " + columnIndex);

        LineTile[] columnTiles = new LineTile[tileMapHeight];

        for (int j = 0; j < tileMapHeight; j++) columnTiles[j] = tileMap[columnIndex][j];

        return columnTiles;
    }
Ejemplo n.º 13
0
    // go through the board and analyze all the tiles, looking for matches
    private void UpdateMatches()
    {
        // match groups are being updated so they're no longer dirty
        matchGroupsAreDirty = false;

        // since sliding columns/rows can mess up everything, we need to get rid of the old match groups and start over.
        // keep in mind there's probably a way to use the algorithm where we don't have to get rid of all the matches and
        // start over every time (say, just update the matches that are disrupted by a shift), but that can come later if
        // you need to improve performance
        foreach (MatchGroup matchGroup in matchGroups)
        {
            matchGroup.Destroy();
        }
        matchGroups.Clear();

        // we'll start analyzing the board from the bottom left tile. the current base tile will be the one
        // that we are currently starting from and building match groups off of.
        LineTile currentBaseTile = tileMap[0][0];

        List <LineTile> tileSurrounders;                      // variable that will store surrounding tiles of various base tiles
        List <LineTile> checkedTiles = new List <LineTile>(); // we'll store base tiles here once they've been analyzed so we don't reanalyze them
        MatchGroup      currentMatchGroup;                    // the match group we're analyzing that includes the current base tile

        // loop continuously through the board, making match groups until there are no more tiles to make match groups from
        while (currentBaseTile != null)
        {
            // create a new match group, add the current base tile as its first tile
            currentMatchGroup = new MatchGroup();
            currentMatchGroup.tiles.Add(currentBaseTile);

            // loop through the tiles starting on the current base tile, analyze their connections, find a new base tile,
            // and loop again, and so on until you find no more possible connections any of the tiles in the match group
            bool stillWorkingOnMatchGroup = true;

            while (stillWorkingOnMatchGroup)
            {
                // populate the tileSurrounders list with all the tiles surrounding the current base tile
                tileSurrounders = GetTilesSurroundingTile(currentBaseTile);

                // iterate through all the surrounding tiles and check if their solid sides are aligned with the base tile's solid sides
                foreach (LineTile surroundingTile in tileSurrounders)
                {
                    TileConnectionType connectionType = TileConnectionTypeBetweenTiles(currentBaseTile, surroundingTile);

                    // if there's a solid match, add the surrounder to the match group.
                    // if there's a mismatch, the matchgroup is not a perfect "closed" match group.
                    // if there's a mismatch because of an open side of the base tile, that doesn't actually matter
                    // since there's not a solid side being cut off (this is called TileConnectionType.ValidWithOpenSide)
                    if (connectionType == TileConnectionType.ValidWithSolidMatch)
                    {
                        currentMatchGroup.tiles.Add(surroundingTile);
                    }
                    else if (TileConnectionTypeBetweenTiles(currentBaseTile, surroundingTile) == TileConnectionType.Invalid)
                    {
                        currentMatchGroup.isClosed = false;
                    }
                }

                // if the base tile has a closed/solid side that touches the edge of the board, the match group can't be closed
                if (((currentBaseTile.bitmask & LineTile.kBitmaskTop) != 0 && currentBaseTile.tileIndex.yIndex == tileMapHeight - 1) ||
                    ((currentBaseTile.bitmask & LineTile.kBitmaskRight) != 0 && currentBaseTile.tileIndex.xIndex == tileMapWidth - 1) ||
                    ((currentBaseTile.bitmask & LineTile.kBitmaskBottom) != 0 && currentBaseTile.tileIndex.yIndex == 0) ||
                    ((currentBaseTile.bitmask & LineTile.kBitmaskLeft) != 0 && currentBaseTile.tileIndex.xIndex == 0))
                {
                    currentMatchGroup.isClosed = false;
                }

                // add our base tile to an array so we don't check it again later
                if (!checkedTiles.Contains(currentBaseTile))
                {
                    checkedTiles.Add(currentBaseTile);
                }

                // find a new base tile that we've added to the match gropu but haven't analyzed yet
                for (int i = 0; i < currentMatchGroup.tiles.Count; i++)
                {
                    LineTile tile = currentMatchGroup.tiles[i];

                    // if the checkedTiles array has the tile in it already, check to see if we're on the last
                    // tile in the match group. if we are, then there are no more base tile possibilities so
                    // done with the match group. if checkedTiles DOESN'T have a tile in the array, it means
                    // that tile is in the match group but hasn't been analyzed yet, so we need to set it as
                    // the next base tile.
                    if (checkedTiles.Contains(tile))
                    {
                        if (i == currentMatchGroup.tiles.Count - 1)
                        {
                            stillWorkingOnMatchGroup = false;
                            matchGroups.Add(currentMatchGroup);
                        }
                    }
                    else
                    {
                        currentBaseTile = tile;
                        break;
                    }
                }
            }

            // we're done with a match group, so now we need to find a new un-analyzed tile that's
            // not in any match groups to start a new one off of. so we'll set currentBaseTile to
            // null then see if we can find a new one.
            currentBaseTile = null;

            for (int i = 0; i < tileMapWidth; i++)
            {
                for (int j = 0; j < tileMapHeight; j++)
                {
                    LineTile newTile = tileMap[i][j];

                    if (!TileIsAlreadyInMatchGroup(newTile))
                    {
                        currentBaseTile = newTile;
                        break;
                    }
                }
                if (currentBaseTile != null)
                {
                    break;
                }
            }
        }
    }