<h1><p style="text-align:center; padding-top:14px;">Hexagonal Chess</p></h1>
<h3><p style="text-align:center; padding-top:14px;">In my interpretation of hexagonal chess, I used Gliński’s version of the game’s mechanics.
This game is played on a hexagonal board, each side being 6 cells long. In total, the board has 91 hex cells of three different colors.</p></h3>
<br>
<br>
<div style="position:relative; padding-bottom:56.25%; padding-left:30px; height:0; overflow:hidden; align:center;">
<iframe  width="725" height="344" src="https://www.youtube.com/embed/qUuExQmTvo0" frameborder="0" allowfullscreen 
			style="position:absolute; width:97%; height:100%; align:center;">
</iframe>
  </div><br>
<br><h3><p style="text-align:center; padding-top:14px;">
I am going to show several scripts to present main concepts of how this game is made.
<br><br><br>
The board is made from scratch. Everything starts with a vertice, then weaved into triangle, which are finally connected...</p></h3>
<br><br><br>
<desc>HexMesh.cs</desc>
<br>
<pre><code>
using UnityEngine;
using System.Collections.Generic;
using Controller.Board;
using Model.Cell;


namespace Render {
    [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
    public class HexMesh : MonoBehaviour {

        private Mesh _hexMesh;
        private List&lt;Vector3> _vertices;
        private List&lt;int> _triangles;
        private List&lt;Color> _colors;
        private MeshCollider _meshCollider;

        void Awake() {
            GetComponent&lt;MeshFilter>().mesh = _hexMesh = new Mesh();
            _meshCollider = gameObject.AddComponent&lt;MeshCollider>();
            _hexMesh.name = "Hex Mesh";
            _vertices = new List&lt;Vector3>();
            _colors = new List&lt;Color>();
            _triangles = new List&lt;int>();
        }

        void Triangulate(HexCell cell) {
               
            Vector3 center = cell.transform.localPosition;

            for (int i = 0; i &lt; 6; i++) {
                AddTriangle(
                    center,
                    center + HexMetrics.corners[i],
                    center + HexMetrics.corners[i + 1]
                );

                AddTriangleColor(cell.GetCurrentColor());
            }
        }

        public void Triangulate(HexCell[] cells) {
            _hexMesh.Clear();
            _vertices.Clear();
            _triangles.Clear();
            _colors.Clear();

            for (int i = 0; i &lt; HexGrid.cellsCount; i++) {
                if (cells[i] != null)
                Triangulate(cells[i]);
            }

            _hexMesh.vertices = _vertices.ToArray();
            _hexMesh.triangles = _triangles.ToArray();
            _hexMesh.colors = _colors.ToArray();
            _hexMesh.RecalculateNormals();
            _meshCollider.sharedMesh = _hexMesh;
        }

        void AddTriangleColor (Color color) {
            _colors.Add(color);
    		_colors.Add(color);
    		_colors.Add(color);
    	}

        void AddTriangle(Vector3 v1, Vector3 v2, Vector3 v3) {
            int vertexIndex = _vertices.Count;
            _vertices.Add(v1);
            _vertices.Add(v2);
            _vertices.Add(v3);
            _triangles.Add(vertexIndex);
            _triangles.Add(vertexIndex + 1);
            _triangles.Add(vertexIndex + 2);
        }
    }
}</pre></code>

<br><br><br>
<h3><p style="text-align:center; padding-top:14px;">Next step is to control every cell.</p></h3>
<br><br><br>
<desc>HexCell.cs</desc>
<br>
<pre><code>namespace Model.Cell {
    public class HexCell : MonoBehaviour {
        public float yOffset;
        public Color currentColor;
        public Color nativeColor;
        public List&lt;HexAbility> hexAbilities = new List&lt;HexAbility>();

        private HexCoordinates _coordinates;
        private Vector3 _offsetCoordinates = Vector3.zero;        
        private GameObject _currentChessman;

        public static int sizeLimit;

        private int _x;
        public int X {
            get { return _x + HexGrid.boardSize - 1; }
            set { _x = value; }
        }
        private int _y;
        public int Y {
            get { return _y + HexGrid.boardSize - 1; }
            set { _y = value; }
        }
        private int _z;
        public int Z {
            get { return _z + HexGrid.boardSize - 1; }
            set { _z = value; }
        }

        public Vector3 ReturnCoords() {
            return new Vector3(X, Y, Z);
        }

        private Vector3 GetOffsetCoords() {
            if (_offsetCoordinates == Vector3.zero) _offsetCoordinates = new Vector3(0f, -yOffset, 0f);
            return _offsetCoordinates;
        }

        public void AddAbility(HexAbility ability, List&lt;Player> playerExceptions) {
            ability.SetPlayersExceptionsList(playerExceptions);
            hexAbilities.Add(ability);
        }

        public void SetNativeColor(Color color) {
            nativeColor = color;
            currentColor = nativeColor;
        }

        public void SetSelectionColor(Color color) {
            currentColor = color;
        }

        public void SetCurrentChessman(GameObject chessman) {
            _currentChessman = chessman;
        }

        public void UndoSelection() {
            currentColor = nativeColor;
        }

        public Color GetCurrentColor() {
            return currentColor;
        }

        public void SpawnChessman(GameObject chessman, Player player) {
            _currentChessman = Instantiate(chessman) as GameObject;
            _currentChessman.transform.SetParent(transform);
            _currentChessman.transform.localPosition = GetOffsetCoords();
            _currentChessman.transform.rotation = chessman.transform.rotation;
            _currentChessman.GetComponentInChildren&lt;Chessman>().ChessPlayer = player;
        }

        public void RemoveChessman() {
            if (_currentChessman != null) Destroy(_currentChessman);
            else {
                Debug.LogError("You're trying to remove a chessman, but this cell doesn't have one!");
            }
        }

        public bool HasChessman() {
            return (_currentChessman != null);
        }

        public GameObject GetChessman()
        {
            return _currentChessman;
        }

        public Dictionary&lt;HexCell, HexGrid.MoveType> GetChessmanMoves() {
            //function allows a player to see active chessman and shows him possible moves
            //we'll return possible moves (cells)

            if (_currentChessman == null) {
                Debug.Log("There is any chessmen on those cell!");
                return null;
            }

            Movable[] movableScripts = _currentChessman.GetComponentsInChildren&lt;Movable>();
            if (movableScripts == null) {
                Debug.LogError("Your chessmans don't have movable scripts!");
                return null;
            }

            var board = BoardManager.Instance;
            var possibleMoves = new Dictionary&lt;HexCell, HexGrid.MoveType>();

            sizeLimit = (HexGrid.boardSize - 1) * 2;
            foreach (Movable script in movableScripts) {
                Dictionary&lt;HexCell, HexGrid.MoveType> currentPossibleMoves = script.GetPossibleMoves(X, Y, Z, sizeLimit, board.CurrentPlayer);
                foreach (var pair in currentPossibleMoves) {
                    possibleMoves.Add(pair.Key, pair.Value);
                }
            }

            return possibleMoves;
        }

        void Awake() {
            hexAbilities.Add(new StandartMove());
        }
    }
}</code></pre>


<br><br><br><h3><p style="text-align:center; padding-top:14px;">
Every chessman inherits Movable class. Movable is the class with all basic rules for every chess piece on the board: setting position, coordinates, moving. So every chess piece just need to implement how it changes coordinates in order to move. Let Bishop be an example!</p></h3>
<br><br><br>
<desc>Bishop.cs</desc>
<br>
<pre><code>
namespace GameLogic {
    public class Bishop : Movable {
        // This function returns the dictionary with coordinates of all the moves that the active chess piece can make
        public override Dictionary&lt;HexCell, HexGrid.MoveType> GetPossibleMoves(
                                                                int currentX, 
                                                                int currentY, 
                                                                int currentZ, 
                                                                int maxValue, 
                                                                Player player) 
        {
            var board = BoardManager.Instance;
            int indexX = 0;
            int indexY = 0;
            int indexZ = 0;
            var possibleMoves = new Dictionary&lt;HexCell, HexGrid.MoveType>();
            HexCell cell;
            
            CheckMoves checkMoves = changeCoords => {
                //current position of the chess piece. 
                indexX = currentX;
                indexY = currentY;
                indexZ = currentZ;

                while (true) {
                    // we'll go out from the cycle after findind another chessman or the limit of the board

                    //the function that we recieve as a parameter. it's getting coordinates to the neighbour cell of one of the possible directions for movement
                    changeCoords(); // for example move to the cell which has position with indexY++; indexZ--;
                    // are we trying to exceed the limit of the board ?
                    if (indexX > maxValue || indexX &lt; 0 || indexY > maxValue || indexY &lt; 0 || indexZ &lt; 0 || indexZ > maxValue)
                        break;

                    cell = board.GetCellByCoords(indexX, indexY, indexZ);

                    if (cell != null) {
                        //if cell has other's player chessman - we can ATTACK
                        if (cell.HasChessman()) {
                            if (cell.GetChessman().GetComponent&lt;Chessman>().ChessPlayer != player) {
                                possibleMoves.Add(cell, HexGrid.MoveType.Kill);
                            }
                            break;
                        }
                        //if the cell is empty - you can move
                        else
                            possibleMoves.Add(cell, HexGrid.MoveType.Move);
                    }
                };
            };

            // we have 3 directions, and we need to check all of them
            // each direction is a line, so it turns in 2 ways

            //some calculations. that's how hexagonal bishop moves.
            checkMoves(() => { indexX += 2; indexY--; indexZ--; });
            checkMoves(() => { indexZ += 2; indexY--; indexX--; });
            checkMoves(() => { indexY += 2; indexX--; indexZ--; });


            checkMoves(() => { indexX -= 2; indexY++; indexZ++; });
            checkMoves(() => { indexZ -= 2; indexY++; indexX++; });
            checkMoves(() => { indexY -= 2; indexX++; indexZ++; });

            return possibleMoves;
        }
    }
}
</pre></code>

<br><br><br><h3><p style="text-align:center; padding-top:14px;">
The hardest thing is to get all pieces together and to make this work. That's the duty of the next script.</p></h3>
<br><br><br>
<desc>HexGrid.cs</desc>
<br>
<pre><code>
namespace Controller.Board {
    public class HexGrid : MonoBehaviour {
        #region StaticVariables
        public static HexGrid Instance { get; set; }
        public static HexCell[] cells;
        public static int cellsCount;
        public static int coordsLength;
        public static int boardSize;
        #endregion

        #region Prefabs
        public HexCell cellPrefab;
        public GameObject highlinePrefab;

        //there are 3 types of islands.
        //is classical chess types are 2 colors of cells, but there is one more direction, so 3 colors
        public GameObject firstIsland;
        public GameObject secondIsland;
        public GameObject thirdIsland;

        public Text cellLabelPrefab;

        [SerializeField]
        private GameObject messageWindow;
        #endregion
        
        #region Colors
        public Color attackColor;
        public Color attackColor2;
        public Color moveColor;
        public Color moveColor2;
        public Color arrowColor;
        public Color arrowColor2;
        public Color activeColor;
        public Color activeColor2;
        #endregion

        #region Islands
        private GameObject _islandsParent;
        [SerializeField]
        private IslandShaker _shiverIsland;

        public GameObject[] islands;

        #endregion
        
        #region Components
        //to not mess the scene
        private GameObject _cellsParent;

        private BoardManager board;

        private MessageWindow _messageWindow;
        private Canvas _gridCanvas;
        private HexMesh _hexMesh;
        #endregion

        //Arrow type is for future modifications
        public enum MoveType { Kill, Move, Arrow };

        private Dictionary&lt;HexCell, MoveType> _possibleMoves;
        private Dictionary&lt;MoveType, Color> _moveColors1;
        private Dictionary&lt;MoveType, Color> _moveColors2;
        private Dictionary&lt;Vector3, Vector3> _enpassanDict;
        private Dictionary&lt;HexCell, Highline> _highlines;

        private HexCell _activeCell = null;

        private List&lt;CellCoords> cellCoordsList = new List&lt;CellCoords>();

        private Coroutine _shiverCoroutine;

        class CellCoords {
            int cellIndex;
            Vector3 position;

            public CellCoords(int index, Vector3 coords) {
                cellIndex = index;
                position = coords;
            }

            //helps to compare real physical coods to board coords
            public bool IsInside(Vector3 coords) {
                float xPos = position.x;
                float yPos = position.y;
                float zPos = position.z;

                float r = HexMetrics.innerRadius;

                if (Vector3.Distance(position, coords) &lt; = r )
                    return true;
                return false;
            }
        }

        public void SetEnpassanMove(Vector3 point1, Vector3 point2)
        {
            _enpassanDict.Add(point1, point2);
        }

        void DrawBoard(int size) {
            boardSize = size;
            coordsLength = size - 1;
            cellsCount = 6 * (size / 2) * (size - 1) + 1;
            _cellsParent = new GameObject();
            _cellsParent.name = "Cells";
            _cellsParent.transform.parent = this.transform;
            _gridCanvas = GetComponentInChildren&lt; Canvas>();
            _hexMesh = GetComponentInChildren&lt;HexMesh >();
            _hexMesh.transform.position += Vector3.up * 1f;

            cells = new HexCell[cellsCount];
            _highlines = new Dictionary&lt;HexCell, Highline>();
            islands = new GameObject[cellsCount];

            int currentEl = 0;

            int rowsCount = 1 + 4 * (size - 1); //for example rows from 0 to 19 for size = 6
            int currentRow = rowsCount;

            int topRowsCount = size - 1;
            int bottomRowsCount = topRowsCount;
            int middleRowsCount = size * 2 - 1;

            DrawTopRows(topRowsCount, ref currentEl, ref currentRow);
            DrawMiddleRows(middleRowsCount, ref currentEl, ref currentRow);
            DrawBottomRows(bottomRowsCount, ref currentEl, ref currentRow);
        }

        void DrawTopRows(int rowsCount, ref int currentEl, ref int currentRow) {
            int startZ = 0;
            int startX = -coordsLength;
            int startY = coordsLength;

            for (int rowWidth = 0; rowWidth &lt; rowsCount; rowWidth++) {
                int currentX = startX;
                int currentZ = startZ;
                int currentY = startY;

                for (int currentWidth = 0; currentWidth &lt;= rowWidth; currentWidth++) {
                    CreateCell(currentX, currentY, currentZ, currentEl++, currentRow);
                    currentZ -= 2;
                    currentX++;
                    currentY++;
                }
                currentRow--;
                startY--;
                startZ++;
            }
        }

        void DrawMiddleRows(int rowsCount, ref int currentEl, ref int currentRow) {
            int startZ = coordsLength;
            int startY = 0;
            int startX = -coordsLength;

            for (int rowNum = 0; rowNum &lt; rowsCount; rowNum += 2) {
                int currentX = startX;
                int currentZ = startZ;
                int currentY = startY;

                for (int currentWidth = 0; currentWidth &lt; boardSize; currentWidth++) {
                    CreateCell(currentX++, currentY++, currentZ, currentEl++, currentRow);
                    currentZ -= 2;
                }

                currentRow--;
                currentZ = startZ - 1;
                currentX = startX + 1;
                currentY = startY;

                for (int currentWidth = 0; currentWidth &lt; boardSize - 1; currentWidth++) {
                    CreateCell(currentX++, currentY++, currentZ, currentEl++, currentRow);
                    currentZ -= 2;
                }
                currentRow--;

                startY--;
                startX++;
            }
        }

        void DrawBottomRows(int rowsCount, ref int currentEl, ref int currentRow) {
            int startZ = coordsLength - 2;
            int startY = -coordsLength;
            int startX = 2;

            for (int rowNum = 0; rowNum &lt; rowsCount; rowNum++) {
                int currentX = startX;
                int currentZ = startZ;
                int currentY = startY;

                for (int currentWidth = 0; currentWidth &lt; rowsCount - rowNum - 1; currentWidth++) {
                    CreateCell(currentX, currentY, currentZ, currentEl++, currentRow);
                    currentZ -= 2;
                    currentX++;
                    currentY++;
                }

                currentRow--;
                startZ--;
                startX++;
            }
        }

        void Awake() {
            _messageWindow = messageWindow.GetComponent&lt;MessageWindow>();
            Instance = this;
            _enpassanDict = new Dictionary&lt;Vector3, Vector3>();
            _moveColors1 = new Dictionary&lt;MoveType, Color> {
                { MoveType.Kill, attackColor },
                { MoveType.Move, moveColor},
                { MoveType.Arrow, arrowColor}
            };

            _moveColors2 = new Dictionary&lt;MoveType, Color> {
                { MoveType.Kill, attackColor2 },
                { MoveType.Move, moveColor2},
                { MoveType.Arrow, arrowColor2}
            };

            _possibleMoves = null;
            _islandsParent = new GameObject();
            _islandsParent.name = "Islands";
            _islandsParent.transform.parent = transform;
            DrawBoard(6);
            BoardManager.Instance.SetCenterPoint(CenterCoords());
        }

        void Start() {
            _hexMesh.Triangulate(cells);
            board = BoardManager.Instance;
        }

        public void DiscardSelection() {
            if (_shiverIsland!= null) _shiverIsland.StopShivering();
            _shiverIsland = null;
            if (_highlines.Count != 0)
                foreach(var highline in _highlines) {
                    highline.Value.Fade();
                }
            if (_possibleMoves != null) {
                if (_activeCell != null) { _activeCell.UndoSelection(); _activeCell = null; }
                if (_possibleMoves.Count > 0) {
                    foreach (var selectedCell in _possibleMoves) {
                        selectedCell.Key.UndoSelection();
                        _highlines[selectedCell.Key].Fade(); 
                    }
                };
                _possibleMoves = null;
                _hexMesh.Triangulate(cells);
            }
        }

        //update board after player's move
        public void ActivateChessman(MoveType action, Vector3 startCoords, Vector3 finalCoords) {
            
            var board = BoardManager.Instance;
            HexCell startCell = board.GetCellByCoords((int)startCoords.x, (int)startCoords.y, (int)startCoords.z);
            HexCell finalCell = board.GetCellByCoords((int)finalCoords.x, (int)finalCoords.y, (int)finalCoords.z);
            Player owner;

            GameObject chessman = startCell.GetChessman();
            if(chessman == null) {
                return;
            }
            Movable[] movableScripts = chessman.GetComponentsInChildren&lt;Movable>();
            foreach (var script in movableScripts) {
                script.SignFirstMove();
            }

            switch (action) {
                case MoveType.Move:
                    Chessman chessmanScript = chessman.GetComponentInChildren&lt;Chessman>();
                    owner = chessmanScript.ChessPlayer;
                    if (board.IsKing(chessmanScript)) board.kings[owner] = finalCell;
                    finalCell.SpawnChessman(startCell.GetChessman(), owner);
                    startCell.RemoveChessman();

                    break;
                case MoveType.Kill:
                    //CHECK: if final cell has a king - current player wins! 
                    foreach (var entry in board.kings)
                        if (entry.Value == finalCell) Debug.Log("WIN");
                    owner = startCell.GetChessman().GetComponentInChildren&lt;Chessman>().ChessPlayer;

                    finalCell.RemoveChessman();
                    finalCell.SpawnChessman(startCell.GetChessman(), owner);
                    startCell.RemoveChessman();
                    break;
                default:
                    break;
            }

            board.NextPlayerTurn();
        }

        public StandartMove TryMove(MoveType action, HexCell startCell, HexCell finalCell)
        {
            Player owner;

            //1. to take a chess piece from the cell
            GameObject chessman = startCell.GetChessman();
            //2. to get all moves that are available 
            Movable[] movableScripts = chessman.GetComponentsInChildren&lt;Movable>();
            foreach (var script in movableScripts)
            {
                script.SignFirstMove();
            }

            StandartMove moveAction = null;
            Player enemy = GetEnemy();
            foreach (var hexAbility in finalCell.hexAbilities)
            {
                if (hexAbility.GetType() == typeof(StandartMove))
                {
                    moveAction = hexAbility as StandartMove;
                }
            }

            Chessman chessmanScript = chessman.GetComponentInChildren&lt;Chessman>();
            owner = chessmanScript.ChessPlayer;

            switch (action)
            {
                //if it's movement
                case MoveType.Move:

                    //where is enemy's king?
                    if (board.IsKing(chessmanScript)) board.kings[owner] = finalCell;

                    //change the parent of a chess piece logically, but not visually, 'cause the move isnt done yet
                    if (moveAction != null)
                        moveAction.ChangeParent(startCell, finalCell.transform);
                    else
                        Debug.Log("moveaction = null");

                    break;
                case MoveType.Kill:
                    //CHECK: if final cell has a king - current player wins!
                    foreach (var entry in board.kings)
                        if (entry.Value == finalCell) Debug.Log("WIN");
                    if (board.IsKing(chessmanScript)) board.kings[owner] = finalCell;

                    if (moveAction != null)
                        moveAction.ChangeParent(startCell, finalCell.transform);
                    else
                        Debug.Log("moveaction = null");

                    break;
                case MoveType.Arrow:
                    foreach (var entry in board.kings)
                        if (entry.Value == finalCell) Debug.Log("WIN");

                    owner = startCell.GetChessman().GetComponentInChildren&lt;Chessman>().ChessPlayer;

                    finalCell.RemoveChessman();
                    GameManager.Instance.AbilityIsReady();
                    break;
                default:
                    break;
            }

            return moveAction;
        }

        //checks if a player can make the move
        public void TryActivateChessman(MoveType action, HexCell startCell, HexCell finalCell) {
            GameObject chessman = startCell.GetChessman();
            StandartMove moveAction = TryMove(action, startCell, finalCell);

            GameManager gm = GameManager.Instance;

            bool moved = false;

            int fullAbilitiesCount = 0;
            if (IsCheck(GetEnemy(), GetAlly())) {
                gm.RevertTurn();
                gm.SetActiveAbilities(0);
                moveAction.ReturnParent();
                _messageWindow.ShowChangeTurn();
                Chessman chessmanScript = chessman.GetComponentInChildren&lt;Chessman>();
                if (board.IsKing(chessmanScript)) board.kings[chessmanScript.ChessPlayer] = startCell;
                return;
            }
            
            //how much actions we need?
            foreach (var hexAbility in finalCell.hexAbilities) {
                if (hexAbility.WorksFor(chessman)) fullAbilitiesCount++;
            };

            gm.SetActiveAbilities(fullAbilitiesCount);

            moveAction.ReturnParent();
            if (action == MoveType.Kill) finalCell.RemoveChessman();
            foreach (var hexAbility in finalCell.hexAbilities) {
                if (hexAbility.WorksFor(chessman)) hexAbility.Move(startCell, chessman.GetComponentInChildren&lt;Chessman>(), finalCell);
            }

            if (moved) GameManager.Instance.AbilityIsReady();
            int moveType = (int) action;
            Vector3 start = new Vector3(startCell.X, startCell.Y, startCell.Z);
            Vector3 final = new Vector3(finalCell.X, finalCell.Y, finalCell.Z);
        }

        public Player GetEnemy() {
            if (board.CurrentPlayer == board.GetFirstPlayer()) {
                return board.GetSecondPlayer();
            }
            else {
                return board.GetFirstPlayer();
            }
        }

        public Player GetAlly() {
            if (board.CurrentPlayer == board.GetFirstPlayer()) {
                return board.GetFirstPlayer();
            }
            else {
                return board.GetSecondPlayer();
            }
        }

        public void ActivateHighLine(HexCell cell, Color color1, Color color2, bool isActive) {
            Highline highline = _highlines[cell];
            highline.ChangeColors(color1, color2);
            highline.Appear();
        }

        public void ClickCell(Vector3 position) {

            HexCell cell = FindCell(position);

            if (cell == null) return;

            //if position corresponds to one of selected cell (one of possible moves) - do something (move/kill/etc) with the chessman!
            //and then discard selection
            if (_possibleMoves != null && _activeCell != null)
                foreach (var currentCell in _possibleMoves) {
                    HexCell cellCoords = currentCell.Key;
                    if (cell.X == cellCoords.X && cell.Y == cellCoords.Y && cell.Z == cellCoords.Z) {
                        TryActivateChessman(currentCell.Value, _activeCell, cell);
                        DiscardSelection();
                        return;
                    }
                }

            //clear previous selection
            _enpassanDict = new Dictionary&lt;Vector3, Vector3>();
            DiscardSelection();

            if (cell.HasChessman()) {
                if (cell.GetChessman().GetComponentInChildren&lt;Chessman>().ChessPlayer != BoardManager.Instance.CurrentPlayer) return;
                _activeCell = cell;
                cell.SetSelectionColor(activeColor);
                ActivateHighLine(cell, activeColor, activeColor2, true);
                ShakeIsland(_highlines[cell].transform.parent.gameObject, cell.GetChessman());
            }
            else return;

            _possibleMoves = cell.GetChessmanMoves();

            //if we have at least one move for those chessman
            if (_possibleMoves != null && _possibleMoves.Count > 0)
                //each Cell to select and type of type of movement
                foreach (var possibleCell in _possibleMoves) {
                    Color selectionColor1;
                    Color selectionColor2;
                    //we want to find color of this type of movement to select our cell
                    bool found1 = _moveColors1.TryGetValue(possibleCell.Value, out selectionColor1);
                    bool found2 = _moveColors2.TryGetValue(possibleCell.Value, out selectionColor2);
                    if (found1 && found2)
                    {
                        possibleCell.Key.SetSelectionColor(selectionColor1);
                        ActivateHighLine(possibleCell.Key, selectionColor1, selectionColor2, false);
                    }

                    else
                        Debug.LogError("You haven't set color for " + possibleCell.Value);
            }
            _hexMesh.Triangulate(cells);
        }

        public HexCell FindCell(Vector3 currentCoords) {
            for (int i = 0; i &lt; cellsCount; i++) {
                if (cellCoordsList[i].IsInside(currentCoords))
                    return cells[i];
            }
            return null;
        }

        public HexCell FindCell(int x, int y, int z) {
            for (int i=0; i &lt; cells.Length; i++) {
                HexCell curentCell = cells[i];
                if ((curentCell.X == x) && (curentCell.Y == y) && (curentCell.Z == z)) {
                    return curentCell;
                }
            }
            return null;
        }

        private Vector3 CenterCoords() {
            int middleIndex = boardSize - 1;
            HexCell centerCell = FindCell(middleIndex, middleIndex, middleIndex);
            Transform placement = centerCell.transform;
            return new Vector3(placement.position.x, placement.position.y, placement.position.z);
        }

        private void CreateCell(int x, int y, int z, int i, int currentHeight) {
            Vector3 position;

            position.y = 0f;
            position.z = HexMetrics.innerRadius * currentHeight;
            position.x = - z * 1.5f * HexMetrics.outerRadius;

            cells[i] = Instantiate&lt;HexCell>(cellPrefab);
            HexCell cell = cells[i];
            cell.transform.SetParent(_cellsParent.transform, false);
            cell.transform.localPosition = position;

            cellCoordsList.Add(new CellCoords(i, cell.transform.position));

            GameObject island;
            if (currentHeight % 3 == 0) {
                //cell.SetNativeColor(firstColor);
                island = Instantiate&lt;GameObject>(firstIsland);
            }
            else if (currentHeight % 3 == 1) {
                //cell.SetNativeColor(secondColor);
                island = Instantiate&lt;GameObject>(secondIsland);
            }
            else {
                //cell.SetNativeColor(thirdColor);
                island = Instantiate&lt;GameObject>(thirdIsland);
            }

            cell.X = x;
            cell.Y = y;
            cell.Z = z;

            island.AddComponent&lt;IslandShaker>();

            GameObject highline;
            highline = Instantiate(highlinePrefab);
            highline.transform.position = position + new Vector3(0f, -8f, 0f);
            float yOffset = UnityEngine.Random.Range(0f, 6f);
            cell.yOffset = yOffset;
            island.transform.position = position - new Vector3(0f, 8f + yOffset, 0f);
            highline.transform.position -= new Vector3(0f, yOffset, 0f);
            island.transform.SetParent(_islandsParent.transform);
            highline.transform.SetParent(island.transform);
            islands[i] = island;
            Highline _highlinescript = highline.GetComponent&lt;Highline>();
            _highlines.Add(cell, _highlinescript);
            
            Text label = Instantiate&lt;Text>(cellLabelPrefab);
            label.rectTransform.SetParent(_gridCanvas.transform, false);
            label.rectTransform.anchoredPosition =
                new Vector3(position.x, position.y, position.z);

            label.text = (cell.X.ToString() + " " + cell.Y.ToString() + " " + cell.Z.ToString());
            label.transform.position = position;     
        }

        public void AfterTurn() {
            Player ally;
            Player enemy;
            if (board.CurrentPlayer == board.GetFirstPlayer()) {
                ally = board.GetFirstPlayer();
                enemy = board.GetSecondPlayer();
            }
            else {
                ally = board.GetSecondPlayer();
                enemy = board.GetFirstPlayer();
            }
            bool isCheck = IsCheck(enemy, ally);
            if (isCheck)
            {
                //Debug.Log("there is a in check");
                if (isMate()) Debug.LogError("MATE!!!");
                else
                {
                    _messageWindow.ShowKingAttacked();
                }
            }
        }

        public void ShakeIsland(GameObject island, GameObject chessman) {   
            if (_shiverIsland != null) _shiverIsland.StopShivering();
            _shiverIsland = island.GetComponent&lt;IslandShaker>();
            _shiverIsland.StartShivering(chessman);
        }

        //in order to understand if there is a possible check we need to take all enemy's chess pieces and check if they can attack current player's king
        public bool IsCheck(Player enemy, Player ally) {
            var currentPlayerCell = board.kings[ally];

            foreach (var cell in cells) {
                //we're trying to take a chessman from every cell
                GameObject chessmanGO = cell.GetChessman();
                //then, if there is a chessman
                if (chessmanGO != null) {
                    //we check it
                    Chessman chessman = chessmanGO.GetComponentInChildren&lt;Chessman>();
                    if (chessman.ChessPlayer == enemy) //it's the enemy!
                    {
                        //what moves are possible for this enemy's chessman?
                        Movable[] moves = chessmanGO.GetComponentsInChildren&lt;Movable>();
                       
                        foreach (var move in moves) {
                            if (chessman.ChessPlayer == enemy) //it's the enemy!
                            foreach (var possibleCell in move.GetPossibleMoves(cell.X, cell.Y, cell.Z, HexCell.sizeLimit, enemy)) {
                                if (possibleCell.Value == MoveType.Kill) {
                                        if (currentPlayerCell.X == possibleCell.Key.X && currentPlayerCell.Y == possibleCell.Key.Y && currentPlayerCell.Z == possibleCell.Key.Z) {
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }

        //is it chessmate?
        //first of all, we check, if there is check
        //they, if tehre is any move that can protect the king, it's mate
        public bool isMate()
        {
            GameManager gm = GameManager.Instance;
            bool noMate = false;
            HexCell currentCell = board.kings[board.CurrentPlayer];
            King ourKing = currentCell.GetChessman().GetComponentInChildren&lt;Movable>() as King;
            //maybe king can just ran away?
            foreach (var possibleMove in ourKing.GetPossibleMoves(currentCell.X, currentCell.Y, currentCell.Z, HexCell.sizeLimit, board.CurrentPlayer))
            {
                StandartMove moveAction = TryMove(possibleMove.Value, currentCell, possibleMove.Key);
            
                noMate = (!IsCheck(GetEnemy(), GetAlly()));
                gm.RevertTurn();
                gm.SetActiveAbilities(0);
                moveAction.ReturnParent();
                if (board.IsKing(currentCell.GetChessman().GetComponentInChildren&lt;Chessman>())) board.kings[currentCell.GetChessman().GetComponentInChildren&lt;Chessman>().ChessPlayer] = currentCell;
                if (noMate) return false;
            }
            //if not, can someone protect him?
            foreach(HexCell cell in cells) {
                GameObject chessman = cell.GetChessman();
                if (chessman != null) {
                    Movable[] moves = chessman.GetComponentsInChildren&lt;Movable>();
                    //we are trying to move only attacked player's chessmen 
                    if (cell.GetChessman().GetComponentInChildren&lt;Chessman>().ChessPlayer == board.CurrentPlayer)
                        foreach (var movableScript in moves)
                            foreach (var possibleMove in movableScript.GetPossibleMoves(currentCell.X, currentCell.Y, currentCell.Z, HexCell.sizeLimit, board.CurrentPlayer)) {
                                StandartMove moveAction = TryMove(possibleMove.Value, currentCell, possibleMove.Key);

                                noMate = (!IsCheck(GetEnemy(), GetAlly()));
                                gm.RevertTurn();
                                gm.SetActiveAbilities(0);
                                moveAction.ReturnParent();
                                if (noMate) return false;
                            }
                }
            }
        
            Debug.LogError("oh my god! that's mate!");
            return true;
        }
    }
}</pre></code>
<br><br><br><h3><p style="text-align:center; padding-top:14px;">
Don't forget about good-looking! This script brings those animated shine thank appears when a player clicks on a board alive.</p></h3>
<br><br><br>
<desc>Highline.cs</desc>
<br>
<pre><code>
namespace View {    
    public class Highline : MonoBehaviour {
        //min and max transparasy of the Highline
        [SerializeField]
        private float minAlpha = 0f;
        [SerializeField]
        private float maxAlpha = 0.2f;

        //time spent of the changing minAlpha and maxAlpha
        [SerializeField]
        private float autoSeconds = 0.25f;

        private float _alphaPerSecond;
        private bool _appears;
        private bool _fades;

        private Renderer _renderer;

        //every Highline is made of two materials
        private Material mat1;
        private Material mat2;
        private Color _color;

        private bool _isActive = false;
        private Vector2 startTextureOffset1 = new Vector2(0.3f, 0.05f);
        private Vector2 startTextureOffset2 = new Vector2(0.9f, 0.05f);

        void Awake() {
            //Highline has to have a child with two HexGlows
            _renderer = GetComponentInChildren<Renderer>();
            mat1 = _renderer.materials[0];
            mat2 = _renderer.materials[1];

            //different offsets make interesting visual effect
            mat1.SetTextureOffset("_MainTex", startTextureOffset1);
            mat2.SetTextureOffset("_MainTex", startTextureOffset2);
        }

        void Update () { 
            if (_fades) {
                _color = mat1.GetColor("_TintColor");//Tint Color
                _color.a -= _alphaPerSecond * Time.deltaTime;
                mat1.SetColor("_TintColor", _color);
                _color = mat2.GetColor("_TintColor");//Tint Color
                _color.a -= _alphaPerSecond * Time.deltaTime;
                mat2.SetColor("_TintColor", _color);
            }
            if (_appears) {
                _color = mat1.GetColor("_TintColor");
                _color.a += _alphaPerSecond * Time.deltaTime;
                mat1.SetColor("_TintColor", _color);

                _color = mat2.GetColor("_TintColor");
                _color.a += _alphaPerSecond * Time.deltaTime;
                mat2.SetColor("_TintColor", _color);
            }
            if (_isActive) {
                Vector2 tiling = mat1.GetTextureOffset("_MainTex");
                if (tiling.x >= 1f) mat1.SetTextureOffset("_MainTex", startTextureOffset1);
                else {
                    tiling.x += 0.001f;
                    mat1.SetTextureOffset("_MainTex", tiling);
                }

                tiling = mat2.GetTextureOffset("_MainTex");
                if (tiling.x &lt;= 0f) mat2.SetTextureOffset("_MainTex", startTextureOffset2);
                else {
                    tiling.x -= 0.001f;
                    mat2.SetTextureOffset("_MainTex", tiling);
                }
            }
    	}

        public void Fade() {
            //we don't need to fade twice
            if (!_renderer.enabled) return;
            Fade(autoSeconds);
        }

        public void Appear() {
            Appear(autoSeconds);
        }

        public void Fade(float seconds) {
            _alphaPerSecond = (maxAlpha - minAlpha) / seconds;
            _fades = true;
            StartCoroutine(StartFade(seconds));
        }

        public void Appear(float seconds) {
            _isActive = true;
            _alphaPerSecond = (maxAlpha - minAlpha) / seconds;
            _color = mat1.GetColor("_TintColor");
            _color.a = minAlpha;
            mat1.SetColor("_TintColor", _color);
            _color = mat2.GetColor("_TintColor");
            _color.a = minAlpha;
            mat2.SetColor("_TintColor", _color);
            _appears = true;
            _renderer.enabled = true;
            StartCoroutine(StartAppear(seconds));
        }

        private IEnumerator StartFade(float seconds) {
            _appears = false;
            yield return new WaitForSeconds(seconds);
            _fades = false;
            _isActive = false;
            if (!_appears) {
                _renderer.enabled = false;
            }
            yield break;
        }

        //active means with active chessman
        private IEnumerator StartAppear(float seconds) {
            _fades = false;
            yield return new WaitForSeconds(seconds);
            _appears = false;
            yield break;
        }

        public void ChangeColors(Color color1, Color color2)
        {
            Color alpha = color1;
            mat1.SetColor("_TintColor", color1);
            alpha = color2;
            mat2.SetColor("_TintColor", color2);
        }
    }
}
</pre></code>
.container {
  height: 400px;
  width: 330px;
  margin: 20px auto;
}
.portfolio-thesis-img {
  max-width: 800px;
  max-height: 400px;
  box-shadow: 15px 15px 15px 15px rgba(0,0,0,0.45);
}
desc {
  font-size: x-large; 
  padding-left: 58px;
}
pre, code {
  font-family: monospace, monospace;
  font-size: large; 
}
pre {
  overflow: auto;
}
pre > code {
  display: block;
  padding: 1rem;
  word-wrap: normal;
}
pre{
  font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
  margin-bottom: 10px;
  overflow: auto;
  width: auto;
  padding-left: 45px;
  background-color: #eee;
  width: 450px!ie7;
  padding-bottom: 20px!ie7;
  max-height: 600px;
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.