A flexible pin/charm system for Bevy games, inspired by Hollow Knight's charm system. This crate provides a complete framework for equippable items that modify entity components and behavior.
- Easy Pin Definition: Create pins with a single macro that handles registration automatically
- Flexible Component System: Pins can add any Bevy component to entities
- Inventory Management: Track discovered and owned pins
- Equipment System: Equip/unequip pins with notch cost limitations
- Overpin Mode: Allow equipping pins beyond normal capacity (like Hollow Knight's overcharm)
- Interactive UI: Navigate and manage pins with keyboard controls
- Auto-Discovery: Pins can be enabled/disabled and discovered dynamically
Add to your Cargo.toml:
[dependencies]
bevy_pins = "0.1.1"
bevy = "0.17.2"First, create the components that your pins will add to entities:
use bevy::prelude::*;
#[derive(Component, Default, Debug)]
struct SpeedBoost {
multiplier: f32,
}
#[derive(Component, Default, Debug)]
struct HealthBoost {
extra_health: i32,
}Use the create_pins! macro to define multiple pins at once:
use bevy_pins::*;
create_pins!(
SwiftPin {
name: "Swift Soul",
description: "Increases movement speed by 50%",
enabled: true,
cost: 2,
image_path: "textures/swift_pin.png",
component: SpeedBoost
},
HealthPin {
name: "Lifeblood Heart",
description: "Grants 2 extra health masks",
enabled: true,
cost: 3,
component: HealthBoost
}
);fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(PinsPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
// Register all pins (call this after create_pins!)
register_all_pins();
// Spawn an entity with the pin system
commands.spawn((
PinsHolder::new(11), // 11 notch slots
Name::new("Player"),
));
}fn example_system(
mut inventory_events: MessageWriter<AddPinToInventoryEvent>,
mut equip_events: MessageWriter<EquipPinEvent>,
player_query: Query<Entity, With<PinsHolder>>,
) {
let player = player_query.single();
// Add pin to inventory
inventory_events.write(AddPinToInventoryEvent {
pin_id: PinId::new::<SwiftPin>(),
});
// Equip the pin
equip_events.write(EquipPinEvent {
entity: player,
pin_id: PinId::new::<SwiftPin>(),
});
}The create_pins! macro supports these fields:
name: Display name of the pindescription: Description text shown in UIenabled: Whether the pin appears in the game (allows hiding pins)cost: Notch cost to equip the pinimage_path: Path to the pin's image asset (optional - defaults totextures/{PinName}.png)component: The Bevy component type this pin adds to entities
The system provides several events for managing pins:
AddPinToInventoryEvent/RemovePinFromInventoryEvent: Manage inventoryEquipPinEvent/UnequipPinEvent: Equip/unequip pinsOverpinToggleEvent: Toggle overpin mode
When the pin UI is open (press Tab):
- Arrow Keys: Navigate between pins
- Enter: Equip/unequip selected pin
- Tab: Close UI
- C: Clear all equipped pins
- Up/Down: Switch between equipped pins and pin grid sections
PinInventory: Tracks owned pinsPinEquipmentState: Tracks equipped pins per entityPinRegistry: Registry of all available pinsPinUIState: UI navigation state
PinsHolder: Add to entities that can equip pinsEquippedPin: Information about equipped pins- Pin-specific components (defined by you)
Like Hollow Knight's overcharm system, entities can equip pins beyond their normal capacity:
- Automatically enabled after 6 failed equip attempts
- Allows equipping high-cost pins with limited slots
- Visual indicators show overpinned status
- Auto-disables when pins are unequipped and capacity is restored
Pins can be enabled/disabled and discovered dynamically:
// Pins with enabled: false won't appear in the registry
create_pins!(
SecretPin {
name: "Secret Ability",
description: "A hidden pin",
enabled: false, // Won't appear until enabled
cost: 1,
component: SecretComponent
}
);Check out examples/demo.rs for a complete working example that demonstrates:
- Pin definition and registration
- Inventory management
- UI interaction
- Component effects
- Overpin functionality
Run with:
cargo run --example demoThis project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2024 Piotr Świercz [email protected]