Esempio n. 1
0
        // --------------------------------------------------------------------------------------------
        public override void Execute(Game game, Action OnComplete)
        {
            Card      card      = Card.GetCard(cardId);
            BoardTile boardTile = game.board.GetTile(coord);

            card.Owner.PlayCard(card, boardTile);
        }
Esempio n. 2
0
        // --------------------------------------------------------------------------------------------
        public void OnDragFromUnitView(UnitView unitView, Vector2 prevDragPosition, Vector2 dragDelta)
        {
            if (_selectedUnit != null && unitView.Unit != _selectedUnit)
            {
                return;
            }

            if (_game.board.RaycastToPlane(_game.gameCamera.ScreenPointToRay(prevDragPosition + dragDelta), out Vector3 worldPos))
            {
                BoardTile boardTile = _game.board.GetBoardTileAtPosition(worldPos);
                if (boardTile != null && boardTile != _prevBoardTile)
                {
                    _prevBoardTile = boardTile;
                }
            }

            if (_pathSelectionView.IsBuilt)
            {
                _pathSelectionView.PathTo(_prevBoardTile);
            }

            if (_useSkillView.IsBuilt)
            {
                _useSkillView.TargetTowardTile(_prevBoardTile);
            }
        }
Esempio n. 3
0
        // --------------------------------------------------------------------------------------------
        public static List <BoardTile> GetPlayableTiles(Game game, Player owner, CardData cardData)
        {
            List <BoardTile> toReturn = new List <BoardTile>();

            if (cardData.energyRequired > owner.Energy)
            {
                // return empty list because this card is too expensive to be palyed.
                return(toReturn);
            }

            if (!string.IsNullOrEmpty(cardData.useSkillId))
            {
                return(Skill.GetTargetableTiles(AppManager.Config.GetSkillData(cardData.useSkillId), game, owner.Hero));
            }

            if (!string.IsNullOrEmpty(cardData.spawnUnitId))
            {
                UnitData unitData = AppManager.Config.GetUnitData(cardData.spawnUnitId);
                for (int x = 0; x < game.board.width; x++)
                {
                    for (int y = 0; y < game.board.height; y++)
                    {
                        BoardTile boardTile = game.board.GetTile(x, y);
                        if (Unit.CanSpawnOnTile(unitData, boardTile, owner.Hero))
                        {
                            toReturn.Add(boardTile);
                        }
                    }
                }

                return(toReturn);
            }

            return(toReturn);
        }
Esempio n. 4
0
        // --------------------------------------------------------------------------------------------
        public static List <BoardTile> GetTargetableTiles(SkillData skillData, Game game, Unit user)
        {
            List <BoardTile> toReturn = new List <BoardTile>();

            for (int x = 0; x < game.board.width; x++)
            {
                for (int y = 0; y < game.board.height; y++)
                {
                    BoardTile boardTile = game.board.GetTile(x, y);
                    if (boardTile == null)
                    {
                        continue;
                    }

                    if (!IsTileValidTarget(skillData, user, boardTile))
                    {
                        continue;
                    }

                    if ((boardTile.Coord - user.BoardTile.Coord).ManhattanDistance > skillData.range)
                    {
                        continue;
                    }

                    toReturn.Add(boardTile);
                }
            }

            return(toReturn);
        }
Esempio n. 5
0
 // --------------------------------------------------------------------------------------------
 public void HighlightBoardTile(IntVector2 coord)
 {
     if (BoardTileView.TryGetView(this.GetTile(coord), out BoardTileView view))
     {
         view.SetHighlight(BoardTileView.EHighlight.Neutral);
         HighlightedTile = view.BoardTile;
     }
 }
Esempio n. 6
0
        // --------------------------------------------------------------------------------------------
        public override void Destroy()
        {
            base.Destroy();

            _owner.PlayerTurnStarted -= Player_PlayerTurnStarted;
            _owner.PlayerTurnEnded   -= Player_PlayerTurnEnded;

            BoardTile?.SetOccupant(null);
            BoardTile = null;
        }
Esempio n. 7
0
        // --------------------------------------------------------------------------------------------
        public void ClearAllBoardTileHighlights()
        {
            foreach (BoardTile boardTile in _tiles)
            {
                if (BoardTileView.TryGetView(boardTile, out BoardTileView boardTileView))
                {
                    boardTileView.SetHighlight(BoardTileView.EHighlight.None);
                }
            }

            HighlightedTile = null;
        }
Esempio n. 8
0
        // --------------------------------------------------------------------------------------------
        public static bool CanSpawnOnTile(UnitData unitData, BoardTile boardTile, Unit spawnFrom)
        {
            if (boardTile.Occupant != null)
            {
                return(false);
            }

            if ((boardTile.Coord - spawnFrom.BoardTile.Coord).ManhattanDistance > 1)
            {
                return(false);
            }

            return(true);
        }
Esempio n. 9
0
        // --------------------------------------------------------------------------------------------
        public void PathTo(BoardTile boardTile)
        {
            // return when no unit has been set
            if (unit == null)
            {
                return;
            }

            // return it is not the selected unit's owner's turn
            if (unit.Owner.playerIndex != _game.CurrentPlayer.playerIndex)
            {
                CurrentPath = null;
                return;
            }

            if (CurrentPath == null || CurrentPath.Length == 0)
            {
                CurrentPath = new[] { unit.BoardTile.Coord };
            }

            int alreadyContainsTileAtIndex = -1;

            for (int i = 0; i < CurrentPath.Length; i++)
            {
                if (CurrentPath[i].Equals(boardTile.Coord))
                {
                    alreadyContainsTileAtIndex = i;
                    break;
                }
            }
            if (alreadyContainsTileAtIndex >= 0)
            {
                // if the path already contains this tile, backtrack to it and set the currentPath to that
                IntVector2[] backtrackedPath = new IntVector2[alreadyContainsTileAtIndex + 1];
                for (int i = 0; i <= alreadyContainsTileAtIndex; i++)
                {
                    backtrackedPath[i] = CurrentPath[i];
                }
                CurrentPath = Board.RemoveDuplicates(backtrackedPath);
            }
            else
            {
                // the path does not contain this tile, so lets try to find the best path to it
                for (int backtrackIndex = CurrentPath.Length - 1; backtrackIndex >= 0; backtrackIndex--)
                {
                    // backtrack along our CurrentPath until we find a coord that has a valid path to the target
                    IntVector2[] upToBacktrackIndex = new List <IntVector2>(CurrentPath).GetRange(0, backtrackIndex + 1).ToArray();
                    int          cost = _game.board.CalculateCostForPath(unit, upToBacktrackIndex);
                    if (_game.board.TryGetBestPathForUnit(unit, CurrentPath[backtrackIndex], boardTile.Coord, cost, out IntVector2[] backtrackAppend))
Esempio n. 10
0
        // --------------------------------------------------------------------------------------------
        private Unit PlaceUnit(UnitData unitData, BoardTile boardTile)
        {
            Unit unit = new Unit(unitData, _game, this);

            unit.OccupyBoardTile(boardTile, true);

            // when placed, face the center of the board
            // TODO: is this the default behavior? should the player be able to choose the initial facing direction?
            unit.SetFacing(Unit.VectorToFacing(_game.board.CenterPos - unit.Transform.position), false);

            unit.OnTookDamage += OnUnitTookDamage;

            _units.Add(unit);

            return(unit);
        }
Esempio n. 11
0
        // --------------------------------------------------------------------------------------------
        public List <BoardTile> GetAffectedTiles(Unit.EFacing facing, IntVector2 startCoord)
        {
            BoardTile        startTile = _game.board.GetTile(startCoord);
            List <BoardTile> toReturn  = new List <BoardTile>();

            switch (_skillData.areaType)
            {
            case SkillData.EAreaType.Single:
                toReturn.Add(startTile);
                break;

            default:
                throw new NotImplementedException($"GetTargetTiles not implemented for areaType {_skillData.areaType}");
            }

            return(toReturn);
        }
Esempio n. 12
0
        // --------------------------------------------------------------------------------------------
        public void OnPointerDownOverUnitView(UnitView unitView)
        {
            _selectedUnit           = unitView.Unit;
            _pathSelectionView.unit = _selectedUnit;
            _useSkillView.unit      = _selectedUnit;
            _prevBoardTile          = unitView.Unit.BoardTile;

            if (_selectedUnit.CanMove && !_pathSelectionView.IsBuilt)
            {
                // only show the UnitPathSelectionView if the unit can move
                _pathSelectionView.Render(AppManager.Transform);
            }
            if (_selectedUnit.CanUseSkill && !_useSkillView.IsBuilt)
            {
                // only show the UnitUseSkillView if the unit can use its skill
                _useSkillView.Render(AppManager.Transform);
            }
        }
Esempio n. 13
0
        // --------------------------------------------------------------------------------------------
        public Board(Game game, int width, int height) : base("Board")
        {
            _game       = game;
            this.width  = width;
            this.height = height;

            _tiles = new BoardTile[width, height];
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    BoardTile boardTile = new BoardTile(x, y);
                    AddChild(boardTile);
                    _tiles[x, y] = boardTile;
                }
            }

            _groundPlane = new Plane(Vector3.up, Vector3.zero);
        }
Esempio n. 14
0
        // --------------------------------------------------------------------------------------------
        public void OccupyBoardTile(BoardTile newTile, bool asChild)
        {
            // do this check so that OccupyBoardTile can be called arbitrarily without re-occupying the same boardtile
            if (BoardTile != newTile)
            {
                // leave the current tile, if it exists
                BoardTile?.SetOccupant(null);

                // set the new tile, then add this unit as an occupant
                BoardTile = newTile;
                newTile.SetOccupant(this);
            }

            if (asChild)
            {
                // parent the unit to the tile and zero out its local position
                newTile.AddChild(this);
                LocalPosition = Vector3.zero;
            }
        }
Esempio n. 15
0
        // --------------------------------------------------------------------------------------------
        public static void Create(BoardTile boardTile, InstantiateDelegate callback)
        {
            AppManager.AssetManager.Load(AssetPaths.Prefabs.BoardTileView, (bool successful, GameObject payload) =>
            {
                if (successful)
                {
                    GameObject viewGo = Instantiate(payload, boardTile.Transform, false);

                    BoardTileView view = viewGo.GetComponent <BoardTileView>();
                    view.BoardTile     = boardTile;
                    view._highlight    = EHighlight.None;

                    view.SetMaterial();

                    _boardTileToView.Add(boardTile, view);

                    callback(view);
                }
            });
        }
Esempio n. 16
0
        // --------------------------------------------------------------------------------------------
        public override bool IsValid(Game game)
        {
            Card      card      = Card.GetCard(cardId);
            BoardTile boardTile = game.board.GetTile(coord);

            if (boardTile == null)
            {
                return(false);
            }

            if (!card.CanPlayOnTile(boardTile))
            {
                return(false);
            }

            if (card.energyRequired > card.Owner.Energy)
            {
                return(false);
            }

            return(true);
        }
Esempio n. 17
0
        // --------------------------------------------------------------------------------------------s
        public void PlayCard(Card card, BoardTile targetTile)
        {
            _energy = Mathf.Clamp(_energy - card.energyRequired, 0, _energyCap);

            if (!string.IsNullOrEmpty(card.cardData.spawnUnitId))
            {
                PlaceUnit(AppManager.Config.GetUnitData(card.cardData.spawnUnitId), targetTile);
            }
            if (!string.IsNullOrEmpty(card.cardData.useSkillId))
            {
                throw new NotImplementedException("haven't implemented playing cards with useSkillId");
            }

            if (_hand.ContainsCard(card))
            {
                _hand.DiscardCard(card);
            }

            _discardPile.Add(card);

            PlayerPlayedCard?.Invoke(this, new PlayerEventArgs(this));
        }
Esempio n. 18
0
        // --------------------------------------------------------------------------------------------
        public void TargetTowardTile(BoardTile boardTile)
        {
            // return if it is not the unit's owner's turn
            if (unit.Owner.playerIndex != _game.CurrentPlayer.playerIndex)
            {
                return;
            }

            // set CurrentlyTargeting to null and try to set it
            CurrentlyTargeting = null;
            int closestDistance = int.MaxValue;

            foreach (BoardTile targetableTile in _targetableTiles)
            {
                int distance = (boardTile.Coord - targetableTile.Coord).ManhattanDistance;
                if (distance > 1)
                {
                    continue;
                }

                if (distance < closestDistance)
                {
                    closestDistance    = distance;
                    CurrentlyTargeting = targetableTile;
                }
            }

            GameObject.SetActive(CurrentlyTargeting != null);

            if (CurrentlyTargeting == null)
            {
                return;
            }

            Unit.EFacing facing = Unit.VectorToFacing(CurrentlyTargeting.LocalPosition - unit.BoardTile.LocalPosition);
            LocalRotation = Unit.FacingToRotation(facing);
            LocalPosition = unit.BoardTile.LocalPosition + (LocalRotation * (Vector3.right * Offset.x)) + new Vector3(0f, Offset.y, 0f);
        }
Esempio n. 19
0
        // --------------------------------------------------------------------------------------------
        public static bool IsTileValidTarget(SkillData skillData, Unit user, BoardTile tile)
        {
            switch (skillData.target)
            {
            case SkillData.ETarget.Ally:
                return(tile.Occupant?.IsAllyOf(user) ?? false);

            case SkillData.ETarget.Enemy:
                return(tile.Occupant?.IsEnemyOf(user) ?? false);

            case SkillData.ETarget.Tile:
                return(true);

            case SkillData.ETarget.Self:
                return(tile == user.BoardTile);

            case SkillData.ETarget.None:
                return(false);

            default:
                Debug.LogError($"CanTargetTile not implemented for {skillData.target}");
                return(false);
            }
        }
Esempio n. 20
0
        // --------------------------------------------------------------------------------------------
        public void Move(IntVector2[] path, bool animate, Action onComplete)
        {
            if (!CanMove)
            {
                Debug.LogError($"Unit {id} cannot move");
                return;
            }

            _onMoveComplete = () =>
            {
                onComplete?.Invoke();
                _onMoveComplete = null;
            };

            HasMoved = true;

            if (animate)
            {
                if (_moveAnim != null)
                {
                    Debug.LogError("move anim in progress!");
                    return;
                }

                _moveAnim = new TofuAnimation();

                Parent.RemoveChild(this, false);

                for (int i = 1; i < path.Length; i++)
                {
                    Vector3 fromPos = _game.board.GetTile(path[i - 1]).Transform.position;
                    Vector3 toPos   = _game.board.GetTile(path[i]).Transform.position;
                    float   time    = (toPos - fromPos).magnitude / _data.travelSpeed;

                    if (i != 1)
                    {
                        // we don't need to call Then() on the first loop
                        _moveAnim.Then();
                    }

                    _moveAnim.Execute(() =>
                    {
                        SetFacing(VectorToFacing(toPos - fromPos), false);
                    })
                    .Value01(time, EEaseType.Linear, (float newValue) =>
                    {
                        Transform.position = Vector3.LerpUnclamped(fromPos, toPos, newValue);

                        Ray ray           = new Ray(Transform.position + Vector3.up, Vector3.down);
                        RaycastHit[] hits = Physics.RaycastAll(ray, 2f);
                        for (int j = 0; j < hits.Length; j++)
                        {
                            BoardTileView boardTileView = hits[j].collider.GetComponentInParent <BoardTileView>();
                            if (boardTileView == null)
                            {
                                continue;
                            }
                            if (boardTileView.BoardTile != BoardTile)
                            {
                                OccupyBoardTile(boardTileView.BoardTile, false);
                            }

                            break;
                        }
                    });
                }

                _moveAnim.Then()
                .Execute(() =>
                {
                    StopOnTile();
                })
                .Play();
            }
            else
            {
                for (int i = 0; i < path.Length; i++)
                {
                    BoardTile boardTile = _game.board.GetTile(path[i]);
                    StopOnTile();
                }

                _onMoveComplete?.Invoke();
            }
        }
Esempio n. 21
0
 // --------------------------------------------------------------------------------------------
 private void UseSkillOnBoardTile(BoardTile boardTile, Action onComplete)
 {
     throw new NotImplementedException();
 }
Esempio n. 22
0
        // --------------------------------------------------------------------------------------------
        /// <summary>
        /// Finds the best path for a unit to a target coordinate using A*
        /// </summary>
        public bool TryGetBestPathForUnit(Unit unit, IntVector2 startCoord, IntVector2 targetCoord, int movementExhausted, out IntVector2[] bestPath)
        {
            bestPath = new IntVector2[0];
            if (movementExhausted >= unit.MoveRange)
            {
                // return empty array if we've already exahusted the list
                return(false);
            }

            // A* implementation for best path
            HashSet <IntVector2AsAStarNode> open   = new HashSet <IntVector2AsAStarNode>();
            HashSet <IntVector2AsAStarNode> closed = new HashSet <IntVector2AsAStarNode>();

            open.Add(new IntVector2AsAStarNode
            {
                coord    = startCoord,
                previous = null,
                f        = 0,
                g        = 0,
                h        = 0,
            });

            int moveRange = unit.MoveRange - movementExhausted;

            bool succeeded = false;

            while (open.Count > 0)
            {
                List <IntVector2AsAStarNode> openAsList = new List <IntVector2AsAStarNode>(open);
                // sort the open list ascending by f value
                openAsList.Sort((IntVector2AsAStarNode a, IntVector2AsAStarNode b) =>
                {
                    return(a.f.CompareTo(b.f));
                });

                // set the current node to the node with the least f
                IntVector2AsAStarNode currentNode = openAsList[0];

                closed.Add(openAsList[0]);
                open.Remove(currentNode);

                if (currentNode.coord.Equals(targetCoord)) // remember to use .Equals() instead of == becuase these are not the same object
                {
                    bestPath  = currentNode.ToPath();
                    succeeded = true;
                    break;
                }

                List <BoardTile> nextBoardTiles = new List <BoardTile>();
                BoardTile        northTile      = GetTile(currentNode.coord.x, currentNode.coord.y + 1);
                if (northTile != null)
                {
                    nextBoardTiles.Add(northTile);
                }
                BoardTile southTile = GetTile(currentNode.coord.x, currentNode.coord.y - 1);
                if (southTile != null)
                {
                    nextBoardTiles.Add(southTile);
                }
                BoardTile eastTile = GetTile(currentNode.coord.x + 1, currentNode.coord.y);
                if (eastTile != null)
                {
                    nextBoardTiles.Add(eastTile);
                }
                BoardTile westTile = GetTile(currentNode.coord.x - 1, currentNode.coord.y);
                if (westTile != null)
                {
                    nextBoardTiles.Add(westTile);
                }
                foreach (BoardTile boardTile in nextBoardTiles)
                {
                    // check if we've already visited this coord
                    bool isClosed = false;
                    foreach (IntVector2AsAStarNode closedNode in closed)
                    {
                        isClosed |= closedNode.coord.Equals(boardTile.Coord);
                    }
                    if (isClosed)
                    {
                        continue;
                    }

                    // create a new node to add to the open list
                    IntVector2AsAStarNode childNode = new IntVector2AsAStarNode();
                    childNode.coord    = boardTile.Coord;
                    childNode.previous = currentNode;
                    childNode.g        = currentNode.g + boardTile.GetMoveCostForUnit(unit);
                    childNode.h        = (boardTile.Coord - targetCoord).ManhattanDistance;
                    childNode.f        = childNode.g + childNode.h;

                    // we can't look at tiles that are beyond a unit's move range or that are occupied by some other unit
                    if (childNode.g > moveRange || (boardTile.Occupant != null && boardTile.Occupant != unit))
                    {
                        continue;
                    }

                    // check if we've visited this coord but now we have a better path to it
                    bool foundBetterPath = false;
                    bool haveVisited     = false;
                    foreach (IntVector2AsAStarNode openNode in open)
                    {
                        if (!openNode.coord.Equals(childNode.coord))
                        {
                            continue;
                        }

                        haveVisited = true;

                        if (openNode.f < childNode.f)
                        {
                            continue;
                        }

                        // we've found a better node!
                        openNode.g        = childNode.g;
                        openNode.h        = childNode.h;
                        openNode.f        = childNode.f;
                        openNode.previous = childNode.previous;
                        foundBetterPath   = true;
                    }

                    if (!haveVisited || !foundBetterPath)
                    {
                        open.Add(childNode);
                    }
                }
            }

            if (bestPath.Length == 0)
            {
                // if we haven't found a best path, then there's no way the unit could move to the target
                // instead, return the best path to the node closest to the target
                List <IntVector2AsAStarNode> toCullFromClosed = new List <IntVector2AsAStarNode>();
                foreach (IntVector2AsAStarNode closedNode in closed)
                {
                    if (closedNode.g != moveRange)
                    {
                        toCullFromClosed.Remove(closedNode);
                    }
                }
                foreach (IntVector2AsAStarNode toRemove in toCullFromClosed)
                {
                    closed.Remove(toRemove);
                }

                List <IntVector2AsAStarNode> closedAsList = new List <IntVector2AsAStarNode>(closed);
                closedAsList.Sort((IntVector2AsAStarNode a, IntVector2AsAStarNode b) =>
                {
                    return(a.f.CompareTo(b.f));
                });

                bestPath = closedAsList[0].ToPath();
            }

            return(succeeded);
        }
Esempio n. 23
0
        // --------------------------------------------------------------------------------------------
        private void HighlightBoardTilesForUnitMoveRecursive(Unit unit, Dictionary <BoardTile, int> visitedToCost, BoardTile current, int cost)
        {
            if (current == null)
            {
                return;
            }

            if (current.Occupant != null && current.Occupant != unit)
            {
                return;
            }

            if (cost > unit.MoveRange)
            {
                return;
            }

            if (visitedToCost.ContainsKey(current))
            {
                int previousCost = visitedToCost[current];
                if (cost < previousCost)
                {
                    visitedToCost[current] = cost;
                }
                else
                {
                    // we've alredy visited this tile and it was cheaper then, so we're done
                    return;
                }
            }
            else
            {
                visitedToCost.Add(current, cost);
            }

            if (BoardTileView.TryGetView(current, out BoardTileView view))
            {
                view.SetHighlight(BoardTileView.EHighlight.Move);
            }

            BoardTile northTile = GetTile(current.xCoord, current.yCoord + 1);

            if (northTile != null)
            {
                HighlightBoardTilesForUnitMoveRecursive(unit, visitedToCost, northTile, cost + northTile.GetMoveCostForUnit(unit));
            }

            BoardTile southTile = GetTile(current.xCoord, current.yCoord - 1);

            if (southTile != null)
            {
                HighlightBoardTilesForUnitMoveRecursive(unit, visitedToCost, southTile, cost + southTile.GetMoveCostForUnit(unit));
            }

            BoardTile eastTile = GetTile(current.xCoord + 1, current.yCoord);

            if (eastTile != null)
            {
                HighlightBoardTilesForUnitMoveRecursive(unit, visitedToCost, eastTile, cost + eastTile.GetMoveCostForUnit(unit));
            }

            BoardTile westTile = GetTile(current.xCoord - 1, current.yCoord);

            if (westTile != null)
            {
                HighlightBoardTilesForUnitMoveRecursive(unit, visitedToCost, westTile, cost + westTile.GetMoveCostForUnit(unit));
            }
        }
Esempio n. 24
0
 public void OnSkillTargetSelected(Unit unit, Unit.EFacing facing, BoardTile target)
 {
     QueueAction(new UseSkillAction(CurrentPlayer.playerIndex, unit.id, facing, target.Coord), () => { });
 }
Esempio n. 25
0
 // --------------------------------------------------------------------------------------------
 public bool IsTileValidTarget(BoardTile tile)
 {
     return(IsTileValidTarget(_skillData, _user, tile));
 }
Esempio n. 26
0
 // --------------------------------------------------------------------------------------------
 public static bool CanPlayOnTile(Game game, Player owner, CardData cardData, BoardTile boardTile)
 {
     return(GetPlayableTiles(game, owner, cardData).Contains(boardTile));
 }
Esempio n. 27
0
 // --------------------------------------------------------------------------------------------
 public bool CanPlayOnTile(BoardTile boardTile)
 {
     return(GetPlayableTiles().Contains(boardTile));
 }
Esempio n. 28
0
 // --------------------------------------------------------------------------------------------
 public bool IsAdjacentTo(BoardTile other)
 {
     return((Coord - other.Coord).ManhattanDistance == 1);
 }
Esempio n. 29
0
 // --------------------------------------------------------------------------------------------
 public static bool TryGetView(BoardTile boardTile, out BoardTileView view)
 {
     return(_boardTileToView.TryGetValue(boardTile, out view));
 }