1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#![allow(unused_variables)]
use bevy::prelude::*;
use bevy_uniform_grid_2d::prelude::*;
#[rustfmt::skip]
fn main() {
App::new()
// Add default pluugins
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
resolution: bevy::window::WindowResolution::new(800., 800.),
title: "Minimal Example".to_string(),
present_mode: bevy::window::PresentMode::Immediate, // Disable VSync to show max FPS
..default()
}),
..default()
}))
// Add grid plugin. `debug` toggles grid lines (default is false).
//
// The plugin is generic over `Player`. Anything with this component
// will get added to the grid. This allows you to create multiple grids
// for distinct purposes.
//
// The below creates a square 600x600 grid with the bottom left at the origin
.add_plugins(UniformGrid2dPlugin::<Player>::default().debug(true)
// Size of the grid (units are grid cells)
.dimensions(UVec2::splat(30))
// Size of each grid cell (units are world-space coordinates)
.spacing(Vec2::splat(20.))
// You can anchor the grid somewhere specific (default is the origin)
// .anchor(Vec2::new(23.4, 10.1))
)
.add_systems(Startup, setup)
.add_systems(Update, handle_grid_changes)
.add_systems(Update, movement)
.add_systems(Update, update_ui)
.run();
}
#[derive(Component)]
struct Player;
#[derive(Component)]
struct GridCellUI;
fn setup(mut commands: Commands) {
// Add a camera
commands.spawn((Camera2d, Transform::from_xyz(300., 300., 0.)));
commands.spawn((
// Add a sprite so we can visualize the entity
Sprite {
color: Color::WHITE,
custom_size: Some(Vec2::splat(10.0)),
..default()
},
// A `Transform` is required to translate a position into a grid coordinate
Transform::from_xyz(300., 300., 0.),
// Player marker for movement and grid
Player,
));
// Add UI for grid cell display
commands
.spawn(Node {
position_type: PositionType::Absolute,
top: Val::Px(10.0),
left: Val::Px(10.0),
padding: UiRect::all(Val::Px(8.0)),
..default()
})
.with_children(|parent| {
parent.spawn((
Text::new("Grid Cell: N/A"),
TextFont {
font_size: 24.0,
..default()
},
TextColor(Color::WHITE),
GridCellUI,
));
});
}
fn handle_grid_changes(
grid: Res<Grid<Player>>,
// The current grid cell of an entity is synced to `GridCell`
grid_cells: Query<&GridCell<Player>>,
mut events: EventReader<GridEvent>,
) {
// Events are emitted any time an entity enters, leaves, or changes which grid cell it's in
for event in events.read() {
// The grid `operation` can be `Insert`, `Remove`, or `Update`
info!("{}", event);
if let GridOperation::Update { from, to } = event.operation {
// Here we are checking all the entities in neighboring grid cells
// whenever the entity in question changes the cell it's in
for neighbor_entity in grid.iter_neighbors(to) {
// ... attack neighbors?
}
}
}
}
// Move with WASD
fn movement(
mut transform: Query<&mut Transform, With<Player>>,
keyboard: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
) {
let mut position = transform.single_mut().unwrap();
let t = time.delta_secs();
let up = keyboard.any_pressed([KeyCode::KeyW]);
let down = keyboard.any_pressed([KeyCode::KeyS]);
let left = keyboard.any_pressed([KeyCode::KeyA]);
let right = keyboard.any_pressed([KeyCode::KeyD]);
let x = -(left as i8) + right as i8;
let y = -(down as i8) + up as i8;
let mut move_delta = Vec2::new(x as f32, y as f32);
if move_delta != Vec2::ZERO {
move_delta /= move_delta.length();
move_delta *= t * 100.;
}
position.translation += move_delta.extend(0.);
}
// Display current grid cell
fn update_ui(
player_query: Query<&Transform, With<Player>>,
mut ui_query: Query<&mut Text, With<GridCellUI>>,
grid: Res<Grid<Player>>,
) {
if let (Ok(transform), Ok(mut text)) = (player_query.single(), ui_query.single_mut()) {
match grid.world_to_grid(transform.translation) {
Ok(cell) => {
**text = format!("Grid Cell: ({}, {})", cell.x, cell.y);
}
Err(_) => {
**text = "Grid Cell: Out of bounds".to_string();
}
}
}
}