Task 2: Extend the Arbitration Graph
Extend the arbitration graph with the ChaseGhost behavior component.
Context
With our next behavior component ready to go, we need to think about integrating it into our arbitration graph.
For this purpose, we need to modify the PacmanAgent class to include the ChaseGhost behavior component we implemented in the previous task.
Integrating a new behavior component into the arbitration graph is as simple as instantiating it and adding it as a new option to one of the arbitrators.
Since right now there is just one arbitrator – a priority arbitrator – the choice is simple.
We just need to worry about the order in which the options are assigned to the arbitrator.
Should chasing a ghost have a higher priority than avoiding a ghost or vice versa?
Goal
Integrate the ChaseGhost behavior component into the arbitration graph defined in the PacmanAgent class.
Instructions
- Take a look at how the other behavior components are defined in
include/demo/pacman_agent.hpp. - Add the
ChaseGhostbehavior component as a new member of thePacmanAgentclass and initialize it in the constructor. - Extend the
PacmanAgentparameter struct to include the parameters for theChaseGhostbehavior component. - Add a new option to the priority arbitrator.
- Run the game, take a look at the new arbitration graph and observe how Pac-Man behaves.
Solution
Click here to expand the solution
Include the header of the ChaseGhost behavior component in include/demo/pacman_agent.hpp:
#include "chase_ghost_behavior.hpp"
Add the ChaseGhost behavior component as a new member of the PacmanAgent class:
private:
ChaseGhostBehavior::Ptr chaseGhostBehavior_;
Extend the PacmanAgent parameter struct to include the parameters for the ChaseGhost behavior component:
struct Parameters {
AvoidGhostBehavior::Parameters avoidGhostBehavior;
// Add the parameters for the ChaseGhost behavior component
ChaseGhostBehavior::Parameters chaseGhostBehavior;
MoveRandomlyBehavior::Parameters moveRandomlyBehavior;
};
In the constructor of the PacmanAgent class, initialize the ChaseGhost behavior component and add it to the priority arbitrator.
The invocation condition of ChaseGhost is a subset of the AvoidGhost invocation condition. Therefore, it only makes sense to add ChaseGhost with higher priority than (i.e. before) the AvoidGhost behavior component:
explicit PacmanAgent(const entt::Game& game) : parameters_{}, environmentModel_{game} {
avoidGhostBehavior_ = std::make_shared<AvoidGhostBehavior>(parameters_.avoidGhostBehavior);
// Initialize the ChaseGhost behavior component
chaseGhostBehavior_ = std::make_shared<ChaseGhostBehavior>(parameters_.chaseGhostBehavior);
eatClosestDotBehavior_ = std::make_shared<EatClosestDotBehavior>();
moveRandomlyBehavior_ = std::make_shared<MoveRandomlyBehavior>(parameters_.moveRandomlyBehavior);
rootArbitrator_ = std::make_shared<PriorityArbitrator>("Pac-Man");
// Add the ChaseGhost behavior component to the priority arbitrator (before the AvoidGhost behavior component!)
rootArbitrator_->addOption(chaseGhostBehavior_, PriorityArbitrator::Option::Flags::Interruptable);
rootArbitrator_->addOption(avoidGhostBehavior_, PriorityArbitrator::Option::Flags::Interruptable);
rootArbitrator_->addOption(eatClosestDotBehavior_, PriorityArbitrator::Option::Flags::Interruptable);
rootArbitrator_->addOption(moveRandomlyBehavior_, PriorityArbitrator::Option::Flags::Interruptable);
}