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コマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?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.