In this recipe, we'll create an inventory screen, which is very common, mostly in RPGs. To do this, we'll use the Droppable
and Draggable
components in Nifty and create an InventoryItem
class to help us differentiate different the types of items (and hence, where they can be attached). This time, we'll use both XML to create the static components and the Java Builder interface to build the inventory (or backpack) slots. The reason is that in many games, the amount of inventory a character has varies.
We begin by creating the controls, which are the key components of this method. This can be done by performing the following four steps:
inventoryControls.xml
, with the <nifty-controls>
tag.<controlDefinition name="itemSlot">
with the following content:<control name="droppable" backgroundColor="#fff5" width="64px" height="64px" margin="1px" childLayout="center"/>
<controlDefinition name="item" >
.<control name="draggable" backgroundColor="#aaaf" width="64px" height="64px" childLayout="center" valign="top"> <text id="#itemLabel" text="" color="#000f" valign="center" width="100%" style="nifty-label"/> </control>
Next, we can turn our attention to the screen itself. It can be created by performing the following five steps:
inventoryControls.xml
file is loaded with <useControls>
.<screen>
element with a link to our controller file:<screen id="inventoryScreen" controller="gui.controller.InventoryScreenController">
<layer>
element:<layer id="layer0" childLayout="center" backgroundColor="#0000">
<layer>
element, we need a <panel>
element that will contain the rest of our layout:<panel id="inventoryPanel" childLayout="horizontal">
itemSlots
:<panel id="inventorySlots" childLayout="horizontal"/>
The following screenshot shows us the dynamically created item slots:
After this, we create a simple representation of a humanoid with two hands and feet, using the itemSlot
control. We use align
and childLayout
to make the components appear where we want them to.
<panel id="characterPanel" childLayout="vertical">
<panel id="character" backgroundColor="#000f" childLayout="center" align="center" valign="top"> <control name="itemSlot" id="Head"/> </panel>
<panel id="hands" backgroundColor="#000f" childLayout="horizontal" width="25%" align="center" valign="bottom"> <control name="itemSlot" id="HandLeft" align="left" /> <panel width="*" height="1px"/> <control name="itemSlot" id="HandRight" align="right" /> </panel>
itemSlot
for the legs/feet:<panel id="legs" backgroundColor="#000f" childLayout="horizontal" align="center" valign="bottom"> <control name="itemSlot" id="Foot"/> </panel>
With the XML elements done, we can turn to the Java code. The following nine steps are necessary:
InventoryItem
. This has an enum (enumeration) for different body parts: head, hand, foot, and a name.Controller
class, InventoryScreenController
, and have it extend NiftyController
; also, implement DroppableDropFilter
.InventoryItems
, with the name as the key. It can be called itemMap
.bind
method should be overridden, and in here, we should find different DropControls
in the InventoryScreen
and add this class as a filter using the following code:screen.findNiftyControl("HandLeft", Droppable.class).addFilter(this);
Now, we can generate the item slots in the inventory in a 5 x 5 grid.
ControlBuilder
for the itemSlot controls and PanelBuilder
to make columns that will contain five itemSlots each.for
loop to iterate five times over the following block:panelBuilder = new PanelBuilder("") {{ id("inventoryColumn"+posX); childLayoutVertical(); }}; panelBuilder.build(nifty, screen, screen.findElementByName("inventorySlots"));
for
loop, we run another for
loop, generating the five item slots for that column:slotBuilder = new ControlBuilder("itemSlot") {{ id("itemSlot"+index); }}; Element e = slotBuilder.build(nifty, screen, screen.findElementByName("inventoryColumn"+posY));
e.findNiftyControl("itemSlot"+index, Droppable.class).addFilter(this);
itemSlot
, we should check whether it's allowed, and we can do it with the following lines of code:InventoryItem item = itemMap.get(drgbl.getId()); if(drpbl1.getId().startsWith(item.getType().name()) || drpbl1.getId().startsWith("itemSlot")){ return true;
With the item slots done, we can generate some items for testing.
for
loop to create 10 InventoryItems
with different types and names.ControlBuilder
and the item control we defined earlier, as shown in the following code:itemBuilder = new ControlBuilder("item") {{ id("item"+index); visibleToMouse(true); }}; Element e = itemBuilder.build(nifty, screen, screen.findElementByName("itemSlot"+index)); e.findElementByName("#itemLabel").getRenderer(TextRenderer.class).setText(item.getName());
The Java Builder interface we use to create item slots takes a while to get used to, but it's a really powerful tool when we have the need to create nifty elements dynamically. In this case, we still use a predefined control. This saves us a couple of lines of code and allows someone else than a coder to edit the layout and style of the component since it's exposed in the XML file.
By default, a Droppable
control will always accept the Draggable
control that is being dropped. The accept
method in DroppableDropFilter
enables us to define what should be accepted or not. It's illustrated in this recipe by only accepting InventoryItems
of a certain type. The method parameters for the accept method can be described, as the first Droppable
is the control that the draggable
control is being picked up from. The Draggable
control is the item that is being moved. The second Droppable
control is the target where Draggable
has been dropped.
3.133.134.17