# Bevy Pins
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.
## Features
- **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
## Quick Start
Add to your `Cargo.toml`:
```toml
[dependencies]
bevy_pins = "0.1.1"
bevy = "0.17.2"
```
## Basic Usage
### 1. Define Your Components
First, create the components that your pins will add to entities:
```rust
use bevy::prelude::*;
#[derive(Component, Default, Debug)]
struct SpeedBoost {
multiplier: f32,
}
#[derive(Component, Default, Debug)]
struct HealthBoost {
extra_health: i32,
}
```
### 2. Create Pins
Use the `create_pins!` macro to define multiple pins at once:
```rust
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
}
);
```
### 3. Set Up Your App
```rust
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"),
));
}
```
### 4. Add Pins to Inventory and Equip
```rust
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>(),
});
}
```
## Pin Definition Options
The `create_pins!` macro supports these fields:
- `name`: Display name of the pin
- `description`: Description text shown in UI
- `enabled`: Whether the pin appears in the game (allows hiding pins)
- `cost`: Notch cost to equip the pin
- `image_path`: Path to the pin's image asset (optional - defaults to `textures/{PinName}.png`)
- `component`: The Bevy component type this pin adds to entities
## Events
The system provides several events for managing pins:
- `AddPinToInventoryEvent` / `RemovePinFromInventoryEvent`: Manage inventory
- `EquipPinEvent` / `UnequipPinEvent`: Equip/unequip pins
- `OverpinToggleEvent`: Toggle overpin mode
## UI Controls
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
## Resources
- `PinInventory`: Tracks owned pins
- `PinEquipmentState`: Tracks equipped pins per entity
- `PinRegistry`: Registry of all available pins
- `PinUIState`: UI navigation state
## Components
- `PinsHolder`: Add to entities that can equip pins
- `EquippedPin`: Information about equipped pins
- Pin-specific components (defined by you)
## Advanced Features
### Overpin Mode
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
### Pin Discovery
Pins can be enabled/disabled and discovered dynamically:
```rust
// 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
}
);
```
## Example
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:
```bash
cargo run --example demo
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Copyright (c) 2024 Piotr Ćwiercz <tajo48@proton.me>