Builder Worker Unit - UQdeco2800/2022-studio-3 GitHub Wiki
Builders are a unit that are responsible for fixing and constructing buildings. We introduced a builder unit as a medium for "spending" the resources that were collected by the workers to fix buildings that were destroyed and deteriorated by enemy units.
A builder is created by BuilderFactory.java which uses WorkerFactory.java to make the worker. So, a Builder has the components from WorkerFactory as well. Here is how to create a Miner entity:
Entity builder = BuilderFactory.createBuilder();
Builders have 2 distinct components which are BuilderComponent
and BuildingFixComponent
. This component is added to Miner in order to distinguish the entity's type from other workers.
To check whether an entity is a Builder or not, we get the BuilderComponent of an entity and perform a check like the code below:
BuilderComponent builderComponent = entity.getComponent(BuilderComponent.class);
if((builderComponent != null) && (builderComponent.getIsBuilder())){
// Code
}
A builder has a component called WorkerInventoryComponent that holds all the amount of resources such as stone, metal, and wood that they have taken from the town hall, which is the central base to unload resources collected by the Miner and Forager units.
In the BuilderFixComponent
class, when a builder has collided with a building entity, onCollisionStart()
is triggered and if it is the town hall, they load resources and transfer some resources in the Town Hall's ResourceStatsComponent
to the Builder's WorkerInventoryComponent
.
If it is any other building, it checks whether that building entity needs fixing and also if the builder is carrying the required amount of resources for one round of fixing the building. If a builder doesn't have the required amount of resources (5 of each resource for now), then the builder will return to the town hall to load more resources. If the builder does one round of fixing, 5 of each resource will be deducted from their inventory and if they have insufficient resources for another round then they will go back to the base to load more resources for another round.
This 1 round of fixing results in a level up of a building by triggering the building's "levelUp"
event (logic implemented in the BuildingActions
component of the building) and also boosts its health from the CombatStatsComponent
by 10 hp.
Below is the code that presents the logic of how the resource collection works:
/**
* Fix building when the entity starts colliding with another entity.
* Fixes building if the target is a building.
* @param me The entity's fixture
* @param other The collided entity's fixture
*/
private void onCollisionStart(Fixture me, Fixture other) {
if (hitboxComponent.getFixture() != me) {
// Not triggered by hitbox, ignore
return;
}
if (!PhysicsLayer.contains(targetLayer, other.getFilterData().categoryBits)) {
// Doesn't match our target layer, ignore
return;
}
// target components
Entity target = ((BodyUserData) other.getBody().getUserData()).entity;
BuildingActions buildingActions = target.getComponent(BuildingActions.class);
CombatStatsComponent combatStatsComponent = target.getComponent(CombatStatsComponent.class);
ResourceStatsComponent resourceStatsComponent = target.getComponent(ResourceStatsComponent.class);
BaseComponent baseComponent = target.getComponent(BaseComponent.class);
// worker components
Entity collector = ((BodyUserData) me.getBody().getUserData()).entity;
BuilderComponent builderComponent = collector.getComponent(BuilderComponent.class);
WorkerInventoryComponent inventoryComponent = collector.getComponent(WorkerInventoryComponent.class);
// fix the building if the worker is a builder and the target is a building
if (buildingActions == null || combatStatsComponent == null || inventoryComponent == null || builderComponent == null) {
return;
}
if (baseComponent == null) {
// fix the building if the builder has the required resources
if (!combatStatsComponent.isMaxHealth() && (inventoryComponent.getStone() >= STONE_REQUIRED
&& inventoryComponent.getWood() >= WOOD_REQUIRED && inventoryComponent.getMetal() >= METAL_REQUIRED)) {
inventoryComponent.addWood(-WOOD_REQUIRED);
inventoryComponent.addStone(-STONE_REQUIRED);
inventoryComponent.addMetal(-METAL_REQUIRED);
combatStatsComponent.addHealth(FIX_AMOUNT);
if (combatStatsComponent.getMaxHealth() < combatStatsComponent.getHealth()) {
combatStatsComponent.setHealth(combatStatsComponent.getMaxHealth());
}
target.getEvents().trigger("levelUp");
logger.info("Building fixed");
}
// does not have the required resources to fix another building so return to base
returnToBase();
} else {
// collided with a base and should load resource for next fix
getResourcesFromBase(resourceStatsComponent);
}
}
For Builders, Its unit test might be identical to testing components.