示例#1
0
    public static float EvaluateState(GameState gameState, HexTileController htc)
    {
        //Data is going into a MinQ, smaller number is better
        float inAttackRange   = 0; //Bounis if you can attack characters
        float distanceToEnemy = 0; //Minimise this
        float enemyCanAttack  = 0; //Minimise this (large is bad)

        foreach (Character c in gameState.playerChars)
        {
            float distance = htc.FindHexDistance(gameState.selfTile.Position, c.gameCharacter.position);
            //If you can attack this player character
            if (distance <= gameState.selfChar.stats.range)
            {
                //Bigger number is better, (you are subtracting this later)
                // You want to be able to attack the player, but only just. (Incase you have a longer range then them).
                // The enemy has a range of 5, you are 5 tiles away (and can attack) = good (1)
                // The enemy has a range of 5, you are 1 tile away = worst (.2)
                // The enemy has a range of 2, you are 3 tiles away = great (1.5)
                inAttackRange += distance / c.stats.range;
            }
            else if (distance <= c.stats.range)
            {
                //If the enemy can attack you, but you can't attack them, this is bad
                //Only slight penality, don't want the AI to be scared
                enemyCanAttack += .25f;
            }
            distanceToEnemy += distance;
        }
        //This is a MinQ, smaller is better!!!!

        /* Minimise distance to enemys (get into attack range),
         * subtract inAttackRange(you get bounises for being able to attack a character)
         * */
        return(distanceToEnemy - inAttackRange + enemyCanAttack);
    }
示例#2
0
    public static List <int> GreedySearch(HexTile start, HexTile end, HexTileController htc)
    {
        List <HexTile> closeSet = new List <HexTile>();
        PriorityQueue  fringe   = new PriorityQueue();

        fringe.Push((start, new List <int>()), 0);

        int sentinel = 200;

        //Greedy search is limited to 200 iterations to find goal
        while (fringe.HasNext() && sentinel > 0)
        {
            (HexTile state, List <int> actions) = fringe.Pop();
            if (state.Position.Equals(end.Position))
            {
                return(actions);
            }
            if (!closeSet.Contains(state))
            {
                closeSet.Add(state);
            }

            int action = 0;
            foreach (HexTile nextState in state.nexts)
            {
                //Check if the next tile is the goal state,
                // if it is, allow the AI to step onto it
                bool validMove = false;
                if (nextState != null)
                {
                    if (nextState.HoldingObject == null && !nextState.IsObstacle)
                    {
                        validMove = true;
                    }
                    else if (nextState.Position.Equals(end.Position))
                    {
                        validMove = true;
                    }
                }
                if (validMove)
                {
                    List <int> newActions = new List <int>();
                    foreach (int i in actions)
                    {
                        newActions.Add(i);
                    }
                    newActions.Add(action);
                    float cost = htc.FindHexDistance(nextState.Position, end.Position);
                    fringe.Push((nextState, newActions), cost);
                }

                action++;
            }
            sentinel--;
        }
        return(new List <int>()
        {
        });
    }
示例#3
0
    public void Update()
    {
        MoveHighlight();



        /*
         * foreach (HexTile ht in surrounding)
         *  ht.setHighlight(false);
         * surrounding = hexTileController.FindRadius(hexTile, 2);
         *
         * foreach(HexTile ht in surrounding)
         *  ht.setHighlight(true);
         */

        testCount = hexTileController.FindHexDistance(Vector3.zero, hexTile.Position);
    }
示例#4
0
    public bool Execute()
    {
        // Debug.Log(takenby+" is attacking "+space+" with a " + type.ToString() + " attack.");

        //check if tile is in attack range
        //get tile
        int totaldistance = htc.FindHexDistance(takenby.gameCharacter.position, space);

        //check if tile is in range
        if (totaldistance > this.range)
        {
            //failed to take action so return false and allow something else to happen
            return(false);
        }
        //*****Added by Spencer ******
        takenby.ActionTakenThisTurn = true;

        Debug.Log(takenby + " attacks " + space);
        Attack();
        return(true);
    }
示例#5
0
    public static MiniAction DecideAction(GameState gameState, HexTileController htc)
    {
        MoveDebug md           = GameObject.FindGameObjectWithTag("MoveDebug").GetComponent <MoveDebug>();
        int       attackRadius = gameState.selfChar.stats.range;

        // **** Spencer Notes ******

        /*  If you can attack, do
         *  Else evaluate all the locations you could possible move to,
         *  then take the largest and move to it
         */
        //If this character is the hacker, find best possible place to put the attack
        if (gameState.selfChar.characterclass == CharacterClass.HACKER)
        {
            List <HexTile> attackRange  = htc.FindRadius(gameState.selfTile, attackRadius);
            PriorityQueue  attackFringe = new PriorityQueue();
            md.ClearAll();
            foreach (HexTile hex in attackRange)
            {
                GameState gs    = new GameState(gameState.aiChars, gameState.playerChars, hex, gameState.selfChar);
                float     value = EvaluateAOEAttackState(gs, htc);
                md.SetText(hex, value);
                //If this attack will do more damage to yourself, don't add it to the list
                if (value < -1)
                {
                    attackFringe.Push((hex, null), value);
                }
            }
            //If there is nothing in the list (No good attacks) Move intead
            if (attackFringe.HasNext())
            {
                ((HexTile attackHex, List <int> a), float value) = attackFringe.PopWithVal();
                //If this attack only did damage to 1 character (or 1 more than your own chars)

                /* *** Come back if you have more time ****
                 * if (value <= gameState.selfChar.stats.attackdmg)
                 * {
                 *  //Find see if there is a better place to attack and move to that spot
                 *
                 * }*/
                return(new MiniAttack()
                {
                    type = "AOEAttack", attackLocation = attackHex.Position
                });
            }
        }
        else if (gameState.selfChar.characterclass == CharacterClass.PSYONIC)
        {
            Character needestChar     = null;
            Character cantReachChar   = null;
            float     cantReachHealth = 1;
            float     leastHealth     = 1;
            foreach (Character character in gameState.aiChars)
            {
                if (character.CompareTo(gameState.selfChar) != 0)
                {
                    int   distance = htc.FindHexDistance(gameState.selfChar.gameCharacter.position, character.gameCharacter.position);
                    float health   = character.stats.health / character.stats.maxHealth;
                    //If you can heal the character, and the health is less than 1
                    if (health < leastHealth)
                    {
                        if (distance <= attackRadius)
                        {
                            leastHealth = health;
                            needestChar = character;
                        }
                        else
                        {
                            cantReachHealth = health;
                            cantReachChar   = character;
                        }
                    }
                }
            }
            if (leastHealth < 1)
            {
                return(new MiniAttack()
                {
                    type = "Attack", toAttack = needestChar
                });
            }
            else if (cantReachHealth < 1)
            {
                //If there is a character in need that you can't reach, move towards it
                Debug.Log("Healer Moving towards " + cantReachChar.name);
                HexTile toMovTo = MoveTowards(cantReachChar, gameState, htc, true);
                return(new MiniMove()
                {
                    type = "Move", Dest = toMovTo
                });
            }
            else
            {
                //Can't heal yourself*******
                //Move towards the Ranger
                Character target = GetCharacter(gameState.aiChars, CharacterClass.RANGED);
                if (target != null)
                {
                    HexTile toMovTo = MoveTowards(target, gameState, htc, true);
                    return(new MiniMove()
                    {
                        type = "Move", Dest = toMovTo
                    });
                }
                target = GetCharacter(gameState.aiChars, CharacterClass.HACKER);
                if (target != null)
                {
                    HexTile toMovTo = MoveTowards(target, gameState, htc, true);
                    return(new MiniMove()
                    {
                        type = "Move", Dest = toMovTo
                    });
                }
                target = GetCharacter(gameState.aiChars, CharacterClass.MELEE);
                if (target != null)
                {
                    HexTile toMovTo = MoveTowards(target, gameState, htc, true);
                    return(new MiniMove()
                    {
                        type = "Move", Dest = toMovTo
                    });
                }
                //No other characters but you exist, await the sweet release of death
                return(new MiniMove()
                {
                    type = "Move", Dest = gameState.selfTile
                });
            }
        }
        else
        {
            Character weakestChar = null;
            Character deadChar    = null;
            float     leastHealth = int.MaxValue;
            foreach (Character character in gameState.playerChars)
            {
                int distance = htc.FindHexDistance(gameState.selfChar.gameCharacter.position, character.gameCharacter.position);

                if (distance <= attackRadius)
                {
                    //If your attack would kill this character, target this one above all else
                    if ((Mathf.Max(0, character.stats.health - gameState.selfChar.stats.attackdmg) / character.stats.maxHealth) <= 0)
                    {
                        deadChar = character;
                    }
                    if ((character.stats.health / character.stats.maxHealth) < leastHealth)
                    {
                        leastHealth = (character.stats.health / character.stats.maxHealth);
                        weakestChar = character;
                    }
                }
            }
            //Attack the soon to be dead character if it can
            if (deadChar != null)
            {
                return(new MiniAttack()
                {
                    type = "Attack", toAttack = deadChar
                });
            }
            if (weakestChar != null)
            {
                return(new MiniAttack()
                {
                    type = "Attack", toAttack = weakestChar
                });
            }
        }

        // **** Spencer Notes ******

        /* Could not find anything to attack so move to the best possible location
         */

        List <HexTile>               possibleMoves  = htc.FindRadius(gameState.selfTile, gameState.selfChar.stats.speed);
        List <Character>             allChars       = gameState.aiChars.Concat(gameState.playerChars).ToList();
        List <(HexTile, List <int>)> possibleMoves2 = ValidateRadius(gameState.selfTile, possibleMoves, gameState.selfChar.stats.speed, allChars, htc);

        //possibleMoves = ValidateRadius(gameState.selfTile, possibleMoves, gameState.selfChar.stats.speed, allChars, htc);
        possibleMoves = new List <HexTile>();
        foreach ((HexTile hex, List <int> path) in possibleMoves2)
        {
            possibleMoves.Add(hex);
        }
        PriorityQueue fringe = new PriorityQueue();

        foreach (HexTile hex in possibleMoves)
        {
            GameState gs = new GameState(gameState.aiChars, gameState.playerChars, hex, gameState.selfChar);
            fringe.Push((hex, null), EvaluateState(gs, htc));
        }

        if (!fringe.HasNext())
        {
            //No avialable moves, move to self
            return(new MiniMove()
            {
                type = "Move", Dest = gameState.selfTile
            });
        }
        (HexTile state, List <int> actions) = fringe.Pop();
        return(new MiniMove()
        {
            type = "Move", Dest = state
        });
    }
示例#6
0
    public static HexTile MoveTowards(Character target, GameState gameState, HexTileController htc, bool runFromEnemy = false)
    {
        //choose the tile you want to move to, either the character directly, or a tile next to the character that is away from the enemy
        HexTile targetTile = htc.FindHex(target.gameCharacter.position);

        if (runFromEnemy)
        {
            List <HexTile> tilesAroundTarget = htc.FindRadius(targetTile, 1);
            int            farthest          = 0;
            foreach (HexTile hexTile in tilesAroundTarget)
            {
                if (!hexTile.IsObstacle && hexTile.HoldingObject == null)
                {
                    //Find distance to all player characters
                    int newDist = 0;
                    foreach (Character c in gameState.playerChars)
                    {
                        newDist += htc.FindHexDistance(hexTile.Position, c.gameCharacter.position);
                    }
                    //You want the distance to the player to be largest
                    if (newDist > farthest)
                    {
                        farthest   = newDist;
                        targetTile = hexTile;
                    }
                }
            }
        }
        List <int> moves = GreedySearch(gameState.selfTile, targetTile, htc);

        //If run from enemy is false, your target in ON a character, so remove that last step
        if (!runFromEnemy)
        {
            //Remove the last step (the one on the distination character)
            if (moves.Count > 0)
            {
                moves.RemoveAt(moves.Count - 1);
            }
        }

        Debug.Log("Psyonic wants to move ...");
        foreach (int i in moves)
        {
            Debug.Log(i);
        }
        Debug.Log("To get to " + target.name);

        //If you were already right next to the target, don't go anywhere
        if (moves.Count == 0)
        {
            return(gameState.selfTile);
        }
        //Only keep the number of steps that you are allowed to move
        //Starting hex is your own
        HexTile hex = gameState.selfTile;

        //Repet until you hit your step count, or you run out of moves
        for (int i = 0; i < Mathf.Min(gameState.selfChar.stats.speed, moves.Count); i++)
        {
            //Get the neighbor that the path tells you too
            hex = hex.nexts[moves[i]];
        }
        return(hex);
    }