Sprint 4: Safehouse Overview - UQdeco2800/2021-studio-6 GitHub Wiki
Description
The safehouse is a safe haven for the player. Safehouse game area level is created in between every level throughout the game (except for the final game level). In between each level, the safehouse game level is designed to allow player to use golds accumulated to purchase items from the shopkeeper. The shop can essentially be grouped into 2 categories, the first being the design (styling) of the shop UI and the buying system (allowing player to buy an item which updates player data). Within the safehouse game area, player will not be able to attack or use any abilities which means that user will not be able to directly observe and tryout new weapons/abilities purchased and these can only be tested when player leaves safehouse. This is done to prevent player state from constantly needing to check and save player state at every point. Upon entering the safehouse, player will be positioned at the entrance of the safehouse and if player wishes to leave the safehouse, player can then work towards the door that is located at the top (north direction) of the the safehouse game area.
Shopkeeper NPC
Code implementation
Spawning
As an NPC the shopkeeper is implemented in the same general way as all NPC's within the game. It is initially spawned into the safehouse game area through calling the spawn method within the creation method in the SafehouseGameArea.java.
private Entity spawnShopKeeper() {
GridPoint2 SHOP_KEEPER_SPAWN = new GridPoint2(2, 7);
Entity shopKeeperNPC = FriendlyNPCFactory.createShopkeeperNPC();
spawnEntityAt(shopKeeperNPC, SHOP_KEEPER_SPAWN, true, true);
return shopKeeperNPC;
}
This method specifies the shopkeepers location behind the desk and uses the shopkeeper creation method from within FriendlyNPCFactory.java.
public static Entity createShopkeeperNPC() {
Entity shopkeeperNPC = new Entity()
.addComponent(new PhysicsComponent())
.addComponent(new ColliderComponent().setSensor(true).setLayer(PhysicsLayer.ITEM))
.addComponent(new ItemComponent(Items.SHOP, 1))
.addComponent(new TextureRenderComponent("images/safehouse/shopkeeper/shopkeeperSprite.png"));
shopkeeperNPC.getComponent(ColliderComponent.class).setAsBox(new Vector2(3, 3));
shopkeeperNPC.setScale(new Vector2(1.5f, 1.5f));
return shopkeeperNPC;
}
The creation method follows the same component additions as other NPCs (adding a physics component, texture and scaling) with the inclusion of an item component for item recognition in purchasing and a collider on the item layer so when the player enters the boundary box they automatically interact with the shop as they do with items (notably this collision box size is also increased so the player can interact from the other side of the desk).
Interactions
When the player collides with the shopkeeper it triggers the shop screen through an event in PlayerPickupComponent.java which triggers the creation of the shop screen in ShopMenuDisplay.java
if (ServiceLocator.getGameArea() != null && item.getItemType() != Items.SHOP) {
ServiceLocator.getGameArea().despawnEntity(target);
} else if (item.getItemType() == Items.SHOP) {
entity.getEvents().trigger("toggleShopBox");
}
Shop
Code implementation
The implementation shop UI can generally be categorized into 2 parts. The first being the organization of each elements on the UI itself - these are specifically related to the behavior of each element that can be seen by the user when the shop UI is toggled. These elements can be image buttons (which are used as images to better communicate item type in game), text buttons (that will trigger a chain of methods that are linked which then updates relevant data variables in the system to return appropriate feedback for user to observe and acknowledge that the user's action has been execute) and etc. The second part would be the buying system itself which is only triggered when the purchase button is clicked (button will dynamically be changed to equipped and disabled) by the user which will further be discussed in the sub section below. On a high level, the buying system does a number of checks which includes checking if player has the item clicked (image button that has item png allocated to it) and checking if player has sufficient amount of funds to purchase the selected item. If these conditions are met, a successful transaction will then occur.
Organization of shop UI (styling)
Based on the image above, there are 2 rows and 4 columns (only for the second row) which can be seen. The first row being the title of the table (SHOP) and the second row containing all relevant/required information a shop UI should have based on research. Within the second row, 4 separate columns can be seen. Each column is represented with a table to better organize content and to ensure code can easily be manipulated depending on user feedback. Every column is created via separate methods to better encapsulate relevant code for specific parts of the shop UI. The first column consist of the image of the mysterious shop keeper which is added to the main container via the method called addShopKeeperImageToTable()
. The second column is added via addItembuttonImagesToTable()
, third being addItemDescriptionToTable()
and the fourth being addPlayerInfoAndBuyingButtonToTable()
.
Each image button within the collection of image buttons created via the calling of addItembuttonImagesToTable()
method has a single event listener that waits for when if a button is clicked by user. This method is called updateItemDetails(String configFilename, Items itemType)
for which each image button would input a different configFilename and a dedicated itemType for the method to process and output onto the shop UI. This is how item description and title is displayed and change dynamically when a different image button item is clicked by the user. The method checks for if an image button is clicked and then processes the clicked image button to be displayed onto the shop UI and this is dynamically updated based on user clicks. Data displayed is obtained from the unique configFilename supplied by each image button (each image button will be linked to a different config file as each item is uniquely displayed with different name and description). It is worth mentioning that the description and name of item is displayed on the third column of the table. In addition to displaying the right data for each item clicked, the uncheckImageButton()
is also called to highlight the clicked image button and uncheck the previous item image button clicked previously - this is done to clearly indicate to user what item data is currently being displayed in the shop UI currently.
Within the forth column, relevant player information is also displayed for user's reference when thinking of purchasing items (amount of coins player currently has to purchase an item). These variables are created via the method - createPlayerInfoLabels
which gets calledwithin the addPlayerInfoAndBuyingButtonToTable()
method. This information is dynamically updated via the method called loadPlayerData()
which loads the most updated player state variables to be displayed on the shop UI for player's reference. In addition to the player data being updated (numerical data) the image of the player also dynamically updates - this is part of the incorporation of user feedback where users are keen in observing what armor they are currently wearing. This is implemented via the use of updateImagesVisilibility(int defenceLevel)
method which is launched in parallel with loadPlayerData()
which updates the image of the player on shop UI to provide feedback to user that a specific item (only applies to armor now) has been bought by the user. This method utilizes the Group class provided by libGDX which essentially has multiple images placed on top of one of another and it dynamically changes the visibility of specific images depending on the defence level of player currently. The final element is the purchase button for which user will click when attempting to purchase a clicked item. This will thoroughly be explained in the buying system of shop UI section below.
Buying system of shop UI (buying system)
Upon clicking a specific/relevant item image button on the shop UI for which player is interested in purchasing and equipping, the updatePurchaseButton()
will be called to check whether player is able to purchase the clicked item or not. The purchase button will be disabled if player has already been equipped with item clicked which is updated through the updatePurchaseButton()
method. If player does not have the selected item equipped (this can be melee weapons, armor or abilities), the button will not be disabled - allowing player to click the purchase button. Upon clicking the purchase button, isItemPurchasable()
method is then called. This method checks if player has sufficient amount of funds to purchase the selected item, if yes, the purchased item is updated via processPurchasedItem()
which updates player state and equip player with the purchased item and at the same time, setEquippedButton()
is also called to dynamically change the purchase button to equipped to provide user with feedback that an item has successfully been purchased. In addition to that, within processPurchasedItem()
, loadPlayerData
will also be called again to update the player data on amount of coins left after successful purchase of item selected in shop. If player does not have sufficient funds to purchase an item however, the button will not be changed and none of the previous mentioned processes will occur.