Homework 6: Hero Agents

[Updated 3/09/15 -- grading criteria added]

A Multiplayer Online Battle Arena (MOBA) is a form of Real Time Strategy game in which the player controls a powerful agent called the "Hero" in a world populated with simple, weak, fully computer-controlled agents called "Minions." In this assignment, we will implement the decision-making for Minion agents.

A MOBA has two teams. Each team has a base, which is protected by a number of towers. The goal is to destroy the opponent's base. In MOBAs, bases periodically spawn Minion agents, who automatically attack the enemy towers and bases. Towers and bases can defend themselves; they target Minions before targeting Heros. Thus Minions provide cover for Heros, who are much more powerful.

In this version of a MOBA, Heros have a number of special properties that make them more powerful than Minions:

In this assignment, you will implement the AI for a Hero agent in a world similar to a MOBA. However, we will substantially change the rules so we can focus on Hero AI without all the complications of a MOBA. In this game, there are no towers and each team has a maximum of three minions at any given time. The minions wander aimlessly, but shoot at Heroes if they ever get too close. Heros must hunt each other, and the game is scored by how much damage one Hero does to another Hero.

We will build off your previous navigation mesh and path network generation solution from homework 2 and your previous A* implementation from homework 4.

Hero decision-making can be anything, but in a MOBA, typically the Hero focuses on gaining extra powers so it can take out enemy Minions at a faster rate. Eventually, a Hero will be powerful enough to quickly take down towers and bases. Since towers and bases target Minions before targeting Heros, it is beneficial for Heros to protect friendly Minions and use them for cover. By targeting enemy Minions, a Hero can make it harder for the enemy Hero to take cover. Heros may engage each other from time to time to disrupt opponent advantage.

However, in this assignment, we will only focus on the Hero vs. Hero aspects of a MOBA. You will implement a Finite State Machine (FSM) for Hero agents. The base Hero class has a state machine built into it and each state is an object that implements the behavior of the agent in that state by telling the agent what to do and where to go. Specifically, states have code in their execute() functions that act as the "brain" of the Hero, instructing it what to do at every tick of the game. The Hero agent class will automatically start off in an Idle state. You must implement at least three other states, and modify the Idle state to immediately transition to one of the other states you have implemented.

In Hero vs. Hero combat, the best solution is to focus on strategy. Heros have many properties (listed above) that make for interesting trade-offs when deciding what behavior to execute. Examples of strategic decisions include: hunting the enemy Hero, hunting Minions to increase level, using a longer-ranged shooting attack versus a limited-range area effect attack, retreating to the base to heal, hiding from the enemy Hero, hiding from Minions, etc.

The bases will automatically spawn Minion agents, up to a maximum of three. If a Hero dies, it will immediately respawn at the base, but the level will be reset.

Both teams will use the same Minion agent AI, which wanders the map to random places. Minions will shoot at Heros if they are within firing range.

The game score is computed as the cummulative amount of damage one Hero has done to the other Hero. You must implement Hero AI that can result in a higher score than the opponent.


What you need to know

Please consult previous homework instructions for background on the Game Engine. In addition to the information about the game engine provided there, the following are new elements you need to know about.

Because the object hierarchy is complex, here is a documentation of how all the object types relate (updated for Homework 6):

Agent

Three things are newly relevant to this assignment. (1) Agents have hitpoints. (2) Agents can be part of a team. (3) Agents can shoot in the direction they are facing.

Member variables:

Member functions:

Note: To effectively shoot at something, first turn the agent to face the target (or to the point the agent wishes to fire at) with turnToFace() and then call shoot().

StateMachine

A StateMachine implements the generic functionality of a Finite State Machine. In this assignment, StateMachine is one of the base classes of Minions, thus every Minion is a StateMachine. StateMachines know what the current state is and tell the current state to execute at every update.

Member variables:

Member functions:

Note: A StateMachine will not change states to any type of state that is not listed in StateMachine.states.

State

An abstract base class for all states in a StateMachine. States are more than symbols. Each state has an execute() function that gets called every tick of the game and controls the behavior of the agent.

Member variables:

Member functions:

For exectute() to control the agent, it must make call-backs via the agent member variables. For example, if the behavior of a state is to make the agent shoot, the execute() function can call self.agent.shoot(). To change states, call back to self.agent.changeState().

When changeState() is called, arguments can be passed to the new state when it is initialized. The constructor for the base State class takes a number of arguments, as a list. But it doesn't know what they are meant to be. Constructors for sub-classes can look at the arguments passed in through args and pick out the relevant information and store it or compute with it. For example, one might want a Taunt state, and pass in an argument for the thing to be taunted. For example: the agent could call self.changeState(Taunt, enemyagent). Even though the Taunt sub-class is expecting an argument, it will just be passed in to the constructor as args[0]. Use parseArgs(args) to capture the parameter and use it. For example:

StateAgent

A StateAgent is a sub-class of Agent and StateMachine. Use getStateType() to determine what state the agent is in.

VisionAgent

A VisionAgent is a sub-class of StateAgent. VisionAgent is given a viewangle, a number of degrees that the agent can see. Every tick, the VisionAgent asks the GameWorld what it can see, based on its view angle, and maintains a list of visible Movers (agents, bullets, towers, and bases). For this assignment, Minions have a view angle of 360 degrees, meaning they can see everything around them irrespective of what direction they are facing.

Member variables:

Member functions:

MOBAAgent

A sub-class of VisionAgent (and hence also a StateAgent and a StateMachine), specialized for the MOBA. MOBAAgents do two noteworthy things. First, MOBAAgents die whenever they collide with an Obstacle. Second, they can compute a list of points in navigable space in the even that the agent needs to choose a point to move to without worrying about whether that point is inside an Obstacle (the agent will still have to figure out if it can actually move there).

Additionally, new to this homework, MOBAAgents keep track of the agent that last did damage to them, and have a level, which is used to compute maximum hitpoints and amount of damage they can do.

Member variables:

Member functions:

Hero

Abstract base class, which is a sub-type of MOBAAgent, and thus is a State Machine.

In this assignment, the Hero can dodge, use an area effect attack, be healed by bases, and level-up whenever it kills another agent of any type.

Member variables:

Member functions:

MOBABullet

A special Bullet class for the MOBA. MOBABullets differ from regular bullets in that they are range-limited.

There are four sub-classes of MOBABullet: SmallBullet, BigBullet, BaseBullet, and TowerBullet. These bullets are specific to Minions, Heros, Bases, and Towers, respectively and do different amounts of damage.

Base

Each team in a MOBA has a Base. Bases spawn minions at regular intervals as long as the maximum number of minions allowed at any given time has not been reached. Bases cannot be damaged as long as there are towers present on the same team. Bases can heal Heros---if a Hero touches a base, it's hitpoints are restored to maximum value.

Member variables:

Member functions:

MOBAWorld

A special type of GameWorld for MOBAs. MOBAWorld is a type of GatedWorld. The MOBAWorld keeps track of bases and towers, in addition to NPCs, Bullets, and the agent.

New to this assignment: the MOBAWorld keeps track of the score for each team.

Member variables:

Member functions:


Instructions

To complete this assignment, you must implement Hero AI. Write at least three State classes, and modify the Idle state class to transition to these customized states.

Use your solution to homework 2 to generate a navigation mesh and a corresponding path network. The instructor can provide you with a default solution if necessary. You may also wish to use any path smoothing operations from homework 3 or homework 4. Use your A* implementation from homework 4. The instructor can provide you with a default solution in necessary.

To run the project code, use runhero.py to run your MyHero against an opponent that also implements the same MyHero:

Use runmobacompetition.py to run any two hero agents against each other:

BaselineHero is a bare-bones implementation of Hero AI that you can use to test against. BaselineHero agents simply navigate to the nearest Hero and starts shooting. BaselineHero2 will return to the base for healing if it takes too much damage. BaselineHero3 uses a more sophisticated strategy that will not be revealed.

The following steps are required to complete the assignment.

Step 1: Copy your myCreatePathNetwork function from homework 2.

Step 2: Copy your astarnavigator.py from homework 4. Copy mynavigatorhelpers.py functions from homework 3 or homework 4.

Step 3: Implement at least three classes in MyHero.py that sub-class from State. Implement their enter(), exit(), execute(), and constructors as necessary. You must create at least three states (in addition to Idle).

Step 4: Modify the execute() function in the Idle class in MyHero.py. MyHero automatically start in the Idle state. The main purpose of the Idle class is to transition to another state.

Step 5: Modify the constructor of MyHero in MyHero.py to add any new states to self.states. States cannot be executed unless they are in self.states. Make sure you do not remove Idle from the list of states.


Grading

These games have a score. Each team receives one point for every point of damage done by a Hero agent to another Hero agent. Your MyHero agent will be tested against three baseline agents (described above).

For pragmatic reasons, games will be limited to 5000 ticks. As a rule of thumb, this should be less than 5 minutes on most computers.


Hints

The player-controlled character is a GhostAgent, which can move through walls without being obstruted. Baseline Heros and Minions will not target GhostAgents. If you change the player-controlled character to a Hero in runhero.py or runherocompetition.py, then you will be able to dodge by pressing 'j' (for jump), and use the area effect attack by pressing 'a'.

Use agent.getVisible() and agent.getVisibleType() to figure out what the agent can shoot at.

Remember, an agent shoots in the direction it is facing, so use agent.turnToFace(enemy) before agent.shoot().

Implement a smart dodging algorithm that figures out which direction to dodge to avoid an incoming bullet (use getVisibleType(Bullet) to see bullets) and not jump into obstacles.

Implement leading shots so you can shoot ahead to where an enemy will be instead of where they are at the time the bullet is released.

If the Hero is hunting an opponent Minion or Hero, consider having the Hero go to where the enemy is also going.

Do not kill the enemy base--there is no strategic advantage in doing so. If you kill the base, the enemy Hero will not respawn and you will not be able to get more points.


Submission

To submit your solution, upload your modified MyHero.py, plus mycreatepathnetwork, mynavigationhelpers.py, and astarnavigator.py if you wish to use your own solutions.

You should not modify any other files in the game engine.

DO NOT upload the entire game engine.