-
Notifications
You must be signed in to change notification settings - Fork 25
/
3d_columns.rs
138 lines (129 loc) · 4.03 KB
/
3d_columns.rs
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
use bevy::{
color::palettes::css::{WHITE, YELLOW},
prelude::*,
render::{mesh::Indices, render_asset::RenderAssetUsages, render_resource::PrimitiveTopology},
time::common_conditions::on_timer,
};
use hexx::{shapes, *};
use std::{collections::HashMap, time::Duration};
/// World size of the hexagons (outer radius)
const HEX_SIZE: Vec2 = Vec2::splat(1.0);
/// World space height of hex columns
const COLUMN_HEIGHT: f32 = 10.0;
/// Map radius
const MAP_RADIUS: u32 = 20;
/// Animation time step
const TIME_STEP: Duration = Duration::from_millis(100);
pub fn main() {
App::new()
.insert_resource(AmbientLight {
brightness: 200.0,
..default()
})
.add_plugins(DefaultPlugins)
.add_systems(Startup, (setup_camera, setup_grid))
.add_systems(Update, animate_rings.run_if(on_timer(TIME_STEP)))
.run();
}
#[derive(Debug, Resource)]
struct Map {
entities: HashMap<Hex, Entity>,
highlighted_material: Handle<StandardMaterial>,
default_material: Handle<StandardMaterial>,
}
#[derive(Debug, Default, Resource)]
struct HighlightedHexes {
ring: u32,
hexes: Vec<Hex>,
}
/// 3D Orthogrpahic camera setup
fn setup_camera(mut commands: Commands) {
let transform = Transform::from_xyz(0.0, 60.0, 60.0).looking_at(Vec3::ZERO, Vec3::Y);
commands.spawn(Camera3dBundle {
transform,
..default()
});
let transform = Transform::from_xyz(60.0, 60.0, 00.0).looking_at(Vec3::ZERO, Vec3::Y);
commands.spawn(DirectionalLightBundle {
transform,
..default()
});
}
/// Hex grid setup
fn setup_grid(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let layout = HexLayout {
hex_size: HEX_SIZE,
..default()
};
// materials
let default_material = materials.add(Color::Srgba(WHITE));
let highlighted_material = materials.add(Color::Srgba(YELLOW));
// mesh
let mesh = hexagonal_column(&layout);
let mesh_handle = meshes.add(mesh);
let entities = shapes::hexagon(Hex::ZERO, MAP_RADIUS)
.map(|hex| {
let pos = layout.hex_to_world_pos(hex);
let id = commands
.spawn(PbrBundle {
transform: Transform::from_xyz(pos.x, hex.length() as f32 / 2.0, pos.y),
mesh: mesh_handle.clone(),
material: default_material.clone(),
..default()
})
.id();
(hex, id)
})
.collect();
commands.insert_resource(Map {
entities,
highlighted_material,
default_material,
});
}
fn animate_rings(
mut commands: Commands,
map: Res<Map>,
mut highlighted_hexes: Local<HighlightedHexes>,
) {
// Clear highlighted hexes materials
for entity in highlighted_hexes
.hexes
.iter()
.filter_map(|h| map.entities.get(h))
{
commands
.entity(*entity)
.insert(map.default_material.clone());
}
highlighted_hexes.ring += 1;
if highlighted_hexes.ring > MAP_RADIUS {
highlighted_hexes.ring = 0;
}
highlighted_hexes.hexes = Hex::ZERO.ring(highlighted_hexes.ring).collect();
// Draw a ring
for h in &highlighted_hexes.hexes {
if let Some(e) = map.entities.get(h) {
commands.entity(*e).insert(map.highlighted_material.clone());
}
}
}
/// Compute a bevy mesh from the layout
fn hexagonal_column(hex_layout: &HexLayout) -> Mesh {
let mesh_info = ColumnMeshBuilder::new(hex_layout, COLUMN_HEIGHT)
.without_bottom_face()
.center_aligned()
.build();
Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::RENDER_WORLD,
)
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices)
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs)
.with_inserted_indices(Indices::U16(mesh_info.indices))
}