Skip to main content 홈 크리에이터 johannesrabauer fxgl-skills fxgl-economy
fxgl-economy Implement inventory and trade/shop systems in FXGL — create typed Inventory objects, add/remove/query items, display inventory via InventoryListView, build a Shop with TradeItem buy/sell prices, open a ShopView or TradeView UI, implement buy and sell transactions, manage item stacks and capacity, and wire the shop to NPC collisions. Use this skill when adding an inventory system, item collection, a merchant shop, an upgrade store, or any economy mechanic.
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/JohannesRabauer/fxgl-skills --skill fxgl-economy명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills Add particle systems and visual effects to an FXGL game — configure ParticleEmitter with function-based setters (setVelocityFunction, setAccelerationFunction, setExpireFunction, setScaleFunction, setSpawnPointFunction); use built-in factory emitters (fire, explosion, smoke, rain); apply image-textured particles with multiplyColor / toColor; write custom per-particle physics via setControl; attach TrailParticleComponent for motion trails; apply SlowTimeEffect for bullet-time; apply WobbleEffect for screen-shake; stack multiple effects with EffectComponent; build fireworks displays. Use this skill when adding explosions, fire, smoke, rain, motion trails, impact bursts, bullet-time slow-motion, screen shake, or any particle-based visual polish.
Start a new FXGL project through a bounded Socratic discovery flow, then turn the answers into a docs-first starter specification with ADRs, an arc42-lite architecture summary, and Mermaid use-case diagrams before scaffolding the project itself. Continue using the same questioning approach for initialization choices, and require documentation updates plus automated tests for every implemented step.
Build a Breakout or Arkanoid style game in FXGL — control a paddle horizontally, keep a ball at constant speed, bounce it off walls, paddle, and bricks, load brick layouts from level data, angle the reflection based on paddle hit position, handle lives and bottom-drain loss, spawn falling power-ups, and finish the level when all breakable bricks are destroyed.
name fxgl-economy description Implement inventory and trade/shop systems in FXGL — create typed Inventory objects, add/remove/query items, display inventory via InventoryListView, build a Shop with TradeItem buy/sell prices, open a ShopView or TradeView UI, implement buy and sell transactions, manage item stacks and capacity, and wire the shop to NPC collisions. Use this skill when adding an inventory system, item collection, a merchant shop, an upgrade store, or any economy mechanic.
triggers ["inventory","shop","item","TradeItem","buy","sell","InventoryListView","ShopView","trade","merchant","store","collectible item","economy"] compatibility Java 17+, FXGL 21.x
category fxgl/economy tags ["fxgl","java","javafx","economy"] metadata {"author":"fxgl-skills","version":"1.0","fxgl-version":"21.1"} allowed-tools ["Read","Write","Edit","Bash"]
FXGL Inventory & Trade System
Define Your Item Type
public class Item implements Serializable {
private final String name;
private final String iconPath;
private final String description;
private int quantity;
public Item (String name, String iconPath, String description) {
this .name = name;
this .iconPath = iconPath;
this .description = description;
this .quantity = 1 ;
}
public String getName () { return name; }
public String getIconPath () { return iconPath; }
public String getDescription () { return description; }
public int getQuantity () { return quantity; }
public void setQuantity (int q) { this .quantity = q; }
@Override String { name; }
}
public
toString
()
return
Inventory API
Inventory<Item> playerInventory = new Inventory <>(20 );
boolean added = playerInventory.add(new Item ("Sword" , "sword.png" , "A sharp blade." ));
boolean removed = playerInventory.remove(swordItem);
boolean hasSword = playerInventory.contains(swordItem);
int slotCount = playerInventory.size();
boolean isFull = playerInventory.isFull();
ObservableList<Item> items = playerInventory.getItems();
playerInventory.setMaxCapacity(30 );
int max = playerInventory.getMaxCapacity();
Optional<Item> found = playerInventory.getItems().stream()
.filter(i -> i.getName().equals("Potion" ))
.findFirst();
playerInventory.getItems().forEach(item -> System.out.println(item.getName()));
InventoryListView — Display the Inventory InventoryListView<Item> listView = new InventoryListView <>(playerInventory);
listView.setCellFactory(lv -> new ListCell <>() {
@Override protected void updateItem (Item item, boolean empty) {
super .updateItem(item, empty);
if (empty || item == null ) {
setGraphic(null );
setText(null );
} else {
ImageView icon = new ImageView (getAssetLoader().loadTexture(item.getIconPath()).getImage());
icon.setFitWidth(32 ); icon.setFitHeight(32 );
Label name = new Label (item.getName() + (item.getQuantity() > 1 ? " x" + item.getQuantity() : "" ));
name.setTextFill(Color.WHITE);
setGraphic(new HBox (10 , icon, name));
}
}
});
listView.getSelectionModel().selectedItemProperty().addListener((obs, old, selected) -> {
if (selected != null ) showItemDetails(selected);
});
addUINode(listView, 50 , 50 );
Shop — Define Items for Sale
Shop<Item> merchantShop = new Shop <>();
merchantShop.addItem(new TradeItem <>(new Item ("Sword" , "sword.png" , "Sharp." ), 200 , 100 ));
merchantShop.addItem(new TradeItem <>(new Item ("Shield" , "shield.png" , "Sturdy." ), 150 , 75 ));
merchantShop.addItem(new TradeItem <>(new Item ("Potion" , "potion.png" , "Heals." ), 50 , 20 ));
Trade Logic — Buy & Sell
public boolean buyItem (TradeItem<Item> tradeItem) {
int price = tradeItem.getBuyPrice();
if (geti("gold" ) < price) {
showMessage("Not enough gold!" );
return false ;
}
if (playerInventory.isFull()) {
showMessage("Inventory full!" );
return false ;
}
inc("gold" , -price);
playerInventory.add(tradeItem.getItem());
play("sounds/purchase.wav" );
return true ;
}
public boolean sellItem (Item item) {
TradeItem<Item> shopEntry = merchantShop.getItems().stream()
.filter(t -> t.getItem().getName().equals(item.getName()))
.findFirst().orElse(null );
int sellPrice = shopEntry != null ? shopEntry.getSellPrice() : 10 ;
playerInventory.remove(item);
inc("gold" , +sellPrice);
play("sounds/sell.wav" );
return true ;
}
ShopView — Built-in Shop UI ShopView<Item> shopView = new ShopView <>(merchantShop, playerInventory);
shopView.getStylesheets().add("shop-style.css" );
public class ShopSubScene extends GameSubScene {
@Override
public void onOpen () {
ShopView<Item> view = new ShopView <>(merchantShop, playerInventory);
Button close = getUIFactoryService().newButton("Close Shop" , () ->
getSceneService().popSubScene());
VBox root = new VBox (20 , view, close);
root.setPadding(new Insets (20 ));
getRoot().getChildren().add(root);
}
}
Stacking Items (Quantity Management)
public void addOrStack (Item newItem) {
Optional<Item> existing = playerInventory.getItems().stream()
.filter(i -> i.getName().equals(newItem.getName()))
.findFirst();
if (existing.isPresent()) {
existing.get().setQuantity(existing.get().getQuantity() + newItem.getQuantity());
playerInventory.getItems().remove(existing.get());
playerInventory.getItems().add(existing.get());
} else {
playerInventory.add(newItem);
}
}
Collision-Triggered Shop
onCollisionBegin(EntityType.PLAYER, EntityType.MERCHANT_NPC, (player, merchant) -> {
if (shopSubScene == null ) {
shopSubScene = new ShopSubScene ();
}
getSceneService().pushSubScene(shopSubScene);
});
Saving Inventory State
@Override
public void writeSaveState (DataFile data) {
var inv = data.getBundle("inventory" );
inv.put("items" , new ArrayList <>(playerInventory.getItems()));
inv.put("gold" , geti("gold" ));
}
@Override
public void readSaveState (DataFile data) {
var inv = data.getBundle("inventory" );
List<Item> savedItems = inv.get("items" );
savedItems.forEach(item -> playerInventory.add(item));
set("gold" , inv.get("gold" ));
}
Gotchas
Item must implement Serializable if you save/load the inventory. All fields
(including nested objects like icons) must also be serializable. Avoid storing Node
or Texture objects directly on items — store file paths as Strings instead.
ObservableList from getItems() is live — modifications to it update the
InventoryListView automatically. Do not replace the list; add/remove from it directly.
Inventory capacity is enforced by add() — it returns false when full.
Always check the return value before assuming the item was added.
TradeItem.getBuyPrice() vs getSellPrice() — buy price is what the player pays;
sell price is what the player receives. The sell price is typically 40-60% of buy price.
ShopView uses the default toString() of your item for item names in the built-in
cells. Override toString() to return the item name or implement a custom cell factory.
InventoryListView does not auto-refresh when you mutate item properties (like quantity).
Force a refresh with listView.refresh() after mutating items already in the inventory.