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.

How to create a Builder

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();

Components that only owned by Builder

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
}

How Builder Fixes a Building

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);    
        }
    }

Performed Unit test for Builder

For Builders, Its unit test might be identical to testing components.

⚠️ **GitHub.com Fallback** ⚠️