Crafting System Code Implementation Sprint Two - UQdeco2800/2022-studio-2 GitHub Wiki

Introduction

At this stage, the code implementation of the production system is divided into two main parts, the first part is refining the production system and logic "and the" production display ", specifically how visual resources are connected to the game while also processing player input. The second part is calibrating with inventory, the third part is calibrating with weapons. The fourth part is pause Screen.

In Sprint Two, the programming team decided to build the foundation, which means that the basic logic for each class has been implemented. For example, the main purpose is to successfully craft a basic sword. "Show Animation", in this phase will be the initial completion of the interaction with the player. For example, if the player makes a sword, a picture of the weapon being made will be shown. All weapons can be made and are shown in pictures. It is also possible to put weapons that are made to play into the player's backpack

You'll also design some basic unit tests to test some basic cases.

Materials Factory

Implemented by @lyphng

In order to integrate the crafting menu with the inventory system, all craftable materials were made into an entity. This is because the inventory only stores Entity types, however it will be useful for future sprints as we have discussed the possibility of obtaining them from the map or npcs. Below is an example of the initialisation of materials in MaterialFactory.

public static Entity createGold() {
        Entity gold = new Entity();
        gold.addComponent(new TextureRenderComponent("images/Crafting-assets-sprint1/materials/gold.png"));
        gold.setEntityType(EntityTypes.GOLD);
        gold.setEntityType(EntityTypes.CRAFTABLE);
        return gold;
    }

The image file path was added as a component to allow it to be called automatically instead of manually. Each item was added to EntityTypes as well as type "CRAFTABLE" to differentiate them from other entities.

Crafting Menu

Implemented by @lyphng

The OpenCraftingMenu method initialises an inventoryComponent and adds materials to it for testing purposes since the inventory system isn't fully integrated into the game as of this sprint.

The GetInventory method has been changed completely since the first sprint. In the first sprint our main focus was on the appearance of the menu so the materials and crafting process were all hardcoded in. However in this sprint, we moved our focus to the functionality of the crafting system. It will loop through every item in the inventory and check if the item has type CRAFTABLE.

for (Entity item : inventory) {
      if (item.checkEntityType(EntityTypes.CRAFTABLE)) {

If it does, the material will be initialised as an ImageButton.

material = new ImageButton(materialDrawable);

If the player presses on any material, it will be removed from the inventory and an ImageButton of the material will be initialised in one of the boxes on the right side (box 1 is default, box 2 if box 1 is full).

if (boxes[0] == null) {
              clearMaterials();
              materialTexture = new Texture(item.getComponent(TextureRenderComponent.class).getTexturePath());
              materialTextureRegion = new TextureRegion(materialTexture);
              materialDrawable = new TextureRegionDrawable(materialTextureRegion);
              firstToCraft = new ImageButton(materialDrawable);
              firstToCraft.setSize(50, 50);
              firstToCraft.setPosition(craftMenu.getX() + 481, craftMenu.getY() + 230);
              stage.addActor(firstToCraft);
              addToBoxes(checkType(item));
              inventoryComponent.removeItem(checkType(item));
              firstToCraft.addListener(new ChangeListener() {
                @Override
                public void changed(ChangeEvent event, Actor actor) {
                  disposeFirstBox();
                  clearBoxes(1);
                  addToInventory(checkType(item));
                  getInventory();
                }
              });
              getInventory();
            }

This process is repeated for box 2. The items that were added also have an event listener where it will be added back to the inventory and in the inventory display if it is clicked.

The checkType method checks whether an entity has a material type and returns the material type associated with it.

private EntityTypes checkType(Entity entity) {
    EntityTypes result = null;
    if (entity.checkEntityType(EntityTypes.GOLD)) {
      result = EntityTypes.GOLD;
    }

The addToInventory method takes an entity type and adds an instance of the entity with that type into the inventoryComponent.

private void addToInventory(EntityTypes type) {
    if (type == EntityTypes.GOLD) {
      inventoryComponent.addItem(MaterialFactory.createGold());
    }

The displayCatOne and displayCatTwo methods display the catalogue pages when the catalogue button is clicked. They will also spawn the button to switch between the two catalogue screens and move the exit button's Z index above its current Z index so the player can still click on it.

private void displayCatOne() {
    disposeMaterials();
    catOneMenu = new Image(new Texture(Gdx.files.internal
            ("images/Crafting-assets-sprint1/crafting table/crafting_catalogue_1.png")));
    catOneMenu.setSize(883.26f, 500);
    catOneMenu.setPosition(Gdx.graphics.getWidth() / 2 - catOneMenu.getWidth() / 2,
            Gdx.graphics.getHeight() / 2 - catOneMenu.getHeight() / 2);
    craftingGroup.addActor(catOneMenu);
    exitButton.setZIndex(catOneMenu.getZIndex() + 1);
    buttonTexture = new Texture(Gdx.files.internal
            ("images/Crafting-assets-sprint1/widgets/inventory_button.png"));
    buttonTextureRegion = new TextureRegion(buttonTexture);
    buttonDrawable = new TextureRegionDrawable(buttonTextureRegion);
    inventoryButton = new ImageButton(buttonDrawable);
    inventoryButton.setSize(146, 146);
    inventoryButton.setPosition(craftMenu.getX() + 150, craftMenu.getY() + 301);
    inventoryButton.addListener(new ChangeListener() {
      @Override
      public void changed(ChangeEvent event, Actor actor) {
        disposeCatOne();
        getInventory();
      }
    });
    craftingGroup.addActor(inventoryButton);
    buttonTexture = new Texture(Gdx.files.internal
            ("images/Crafting-assets-sprint1/widgets/catalogue_2_button.png"));
    buttonTextureRegion = new TextureRegion(buttonTexture);
    buttonDrawable = new TextureRegionDrawable(buttonTextureRegion);
    catTwoButton = new ImageButton(buttonDrawable);
    catTwoButton.setSize(60, 60);
    catTwoButton.setPosition(craftMenu.getX() + 110, craftMenu.getY() + 159);
    catTwoButton.addListener(new ChangeListener() {
      @Override
      public void changed(ChangeEvent event, Actor actor) {
        disposeCatOne();
        displayCatTwo();
      }
    });
    craftingGroup.addActor(catTwoButton);
  }

When the exit button is pressed, all components of the crafting menu will be removed from the stage. The following methods remove the corresponding actors from the stage.

private void disposeCatOne()
private void disposeCatTwo()
private void disposeMaterials()
private void disposeFirstBox()
private void disposeSecondBox()
public void disposeCraftingMenu()

This method clears the actors completely so they no longer exist after the method call. This is done so the materials can be refreshed instead of continuing to exist.

private void clearMaterials()

ForestGameArea interaction

Implemented by @lyphng

Some small features were also changed from sprint 1 because it conflicted with Map team's code. The crafting table no longer spawns randomly on the map and instead spawns at (15, 15). The OpenCraftingComponent will then check whether the distance to the player's position is < 3 when testing to open the crafting menu.

public void spawnCraftingTable() {
    Entity craftingTable = ObstacleFactory.createCraftingTable();
    spawnEntityAt(craftingTable, new GridPoint2(15, 15), true, false);
  }
if (entity.getCenterPosition().dst(15, 15) < 3 && craftingStatus == false)

The getCraftArea method in ServiceLocator also gets the GameArea instance rather than the ForestGameArea instance. This is so the code can be more generic and work regardless of whether the ForestGameArea exists.

public static void registerCraftArea(GameAreaDisplay area){
    craftArea = area;
  }

public static GameAreaDisplay getCraftArea() {
    return craftArea;
  }

Implement by@rkoll55

public static List<MeleeConfig> canBuild(List<Materials> inventoryContents){
        List<MeleeConfig> possibleWeapons = getPossibleWeapons();
        List<MeleeConfig> buildables = new ArrayList<>();
        List<String> inventory = new ArrayList<>();

        for (Materials materials: inventoryContents){
            inventory.add(materials.toString());
        }

        for (int i = 0 ; i < possibleWeapons.size(); i++){

            Map<Materials,Integer> materialValues = possibleWeapons.get(i).materials;

            Boolean buildable = true;

            for (Map.Entry<Materials,Integer> entry : materialValues.entrySet()) {

                String mapname = entry.toString().split("=")[0];

                if (!inventory.contains(mapname)) {
                    buildable = false;
                }

            }
            if (buildable)
                buildables.add(possibleWeapons.get(i));
        }
        return buildables;
    }
public static Entity damageToWeapon(MeleeConfig weapon){
        double dam = weapon.damage;
        switch ((int) Math.floor(dam)){
            case 7:
                return WeaponFactory.createDagger();

            case 9:
                return WeaponFactory.createDaggerTwo();

            case 26:
                return WeaponFactory.createSwordLvl2();

            case 5:
                return WeaponFactory.createDumbbell();

            case 25:
                return WeaponFactory.createTridentLvl2();

            case 35:
                return WeaponFactory.createHerraAthenaDag();

            default:
                return WeaponFactory.createPlunger();
        }
    }

Methods in the background logic of the code have been updated to read from the public weapons JSON file created by the weapons class. This allows for dynamic integration with the weapons system and their entities. Methods read from the JSON file and convert the config to a weapon using the weapons factory class.

The display weapon method takes is called by the boxes class if a weapon build is possible and makes a new image with the textures from that entity. It sets a custom size and position that ensures it fits well within the box. Once craft is clicked an event handler listening for the button will add said weapon to the users' inventory and dispose both the materials and the weapon from the screen. This choice was done as having potential non craftable weapons in the crafting inventory may confuse the user.

private void displayWeapon(MeleeConfig item) { Entity newItem = CraftingLogic.damageToWeapon(item); currentWeapon = newItem; String image = newItem.getComponent(TextureRenderComponent.class).getTexturePath(); weapon = new Image(new Texture(Gdx.files.internal(image))); if (Math.floor(item.damage) == 25){ weapon.setSize(60, 60); weaponType = "Trident"; weapon.setPosition(craftMenu.getX() + 650, craftMenu.getY() + 220); } else { weapon.setSize(200, 200); weapon.setPosition(craftMenu.getX() + 600, craftMenu.getY() + 150); } numcrafted += 1; craftingGroup.addActor(weapon); }


Listener that adds a weapon to the users' inventory and clears the screen.


craftButton.addListener(new ChangeListener() {

      // Method to add item to players inventory
      @Override
      public void changed(ChangeEvent event, Actor actor) {
        if (weapon != null) {
          disposeFirstBox();
          disposeSecondBox();
          ForestGameArea area = (ForestGameArea) ServiceLocator.getGameArea();
          inventoryComponent.addItem(currentWeapon);
          weapon.remove();
          weapon = null;
          clearBoxes(0);
  

More information/javadoc go to crafting branch, under crafting package.

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