Newer
Older
use bevy::ecs::system::SystemParam;
use bevy::prelude::*;
use ldtk_rust::{EntityInstance, LayerInstance, Level, TileInstance};
// use crate::assets::level_index::LevelIndex;
use crate::assets::{LdtkProject, LevelIndex};
use crate::utils::{ActiveLevel, Indexer, SerdeClone};
use crate::{get_ldtk_tile_scale, px_to_grid};
#[derive(SystemParam)]
pub struct MapQuery<'w, 's> {
assets: Res<'w, Assets<LdtkProject>>,
active: Option<Res<'w, ActiveLevel>>,
index: Res<'w, LevelIndex>,
#[system_param(ignore)]
_e: PhantomData<&'s ()>,
}
pub struct TileRef<'a> {
pub tile: &'a TileInstance,
}
#[repr(C)]
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Default, Debug)]
pub enum TileFlip {
#[default]
None = 0,
Horizontal = 1,
Vertical = 2,
Both = 3,
}
impl TileFlip {
pub fn is_horizontal(&self) -> bool {
match self {
Self::None | Self::Vertical => false,
Self::Horizontal | Self::Both => true,
}
}
pub fn is_vertical(&self) -> bool {
match self {
Self::None | Self::Horizontal => false,
Self::Vertical | Self::Both => true,
}
pub fn new(tile: &'a TileInstance) -> Self {
TileRef { tile }
}
pub fn gid(&self) -> usize {
(self.tile.src[0] * self.tile.src[1]).unsigned_abs() as usize
}
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
pub fn get_flip(&self) -> TileFlip {
match self.tile.f {
1 => TileFlip::Horizontal,
2 => TileFlip::Vertical,
3 => TileFlip::Both,
_ => TileFlip::None,
}
}
}
impl<'a> Debug for TileRef<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TileRef")
.field("gid", &self.gid())
.field("tile.t", &self.tile.t)
.field("tile.d", &self.tile.d)
.field("tile.px", &self.tile.px)
.field("tile.src", &self.tile.src)
.finish()
}
}
pub struct InstanceRef<'a> {
pub entity: &'a EntityInstance,
}
impl<'a> InstanceRef<'a> {
pub fn get_type(&self) -> &'a String {
&self.entity.identifier
}
pub fn try_get_typed_id<T: FromStr>(&self) -> Result<T, T::Err> {
T::from_str(self.get_type().as_str())
}
pub fn property(&self, name: impl ToString) -> serde_json::Value {
let target = name.to_string();
for field in &self.entity.field_instances {
if field.identifier == target {
return field
.value
.as_ref()
.map(|v| v.clone())
.unwrap_or(serde_json::Value::Null);
}
}
serde_json::Value::Null
}
pub layer: &'a LayerInstance,
}
impl<'a> LayerRef<'a> {
pub fn new(idx: usize, indexer: Indexer, layer: &'a LayerInstance) -> Self {
LayerRef {
layer,
indexer,
idx,
}
}
pub fn has_tiles(&self) -> bool {
!(self.layer.auto_layer_tiles.is_empty() && self.layer.grid_tiles.is_empty())
}
pub fn for_each_tile(&self, mut cb: impl FnMut(i64, i64, TileRef)) {
self.layer
.grid_tiles
.iter()
.chain(self.layer.auto_layer_tiles.iter())
.for_each(|tile: &TileInstance| {
let (x, y) = match tile.px.as_slice() {
_ => {
return;
}
};
cb(x, y, TileRef::new(tile));
});
}
pub fn get_z_delta(&self) -> f32 {
(self.idx as f32) / 100.0
}
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
pub fn get_tile_at(
&self,
x: impl AsPrimitive<isize>,
y: impl AsPrimitive<isize>,
) -> Option<TileRef> {
let idx = self.indexer.index(x, y);
match self.layer.grid_tiles.is_empty() {
true => self
.layer
.auto_layer_tiles
.get(idx)
.map(|tile| TileRef::new(tile)),
false => self
.layer
.grid_tiles
.get(idx)
.map(|tile| TileRef::new(tile)),
}
}
/// Returns the inferred name of the tileset used for this layer. This is assumed to be the
/// name of the tileset file, without the preceding path segments or the file extension. Case
/// remains unchanged
pub fn infer_tileset_name(&self) -> Option<String> {
self.layer.tileset_rel_path.as_ref().and_then(|path| {
Path::new(path)
.file_stem()
.and_then(|stem| stem.to_str())
.map(String::from)
})
}
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
}
#[derive(Copy, Clone, Debug)]
pub struct CameraBounds {
pub left: f32,
pub top: f32,
pub bottom: f32,
pub right: f32,
}
impl CameraBounds {
pub fn get_min_x(&self, camera_width: f32) -> f32 {
self.left + (camera_width / 2.0) - (get_ldtk_tile_scale() / 2.0)
}
pub fn get_max_x(&self, camera_width: f32) -> f32 {
self.right - (camera_width / 2.0) - (get_ldtk_tile_scale() / 2.0)
}
pub fn get_min_y(&self, camera_height: f32) -> f32 {
self.bottom + (camera_height / 2.0) - (get_ldtk_tile_scale() / 2.0)
}
pub fn get_max_y(&self, camera_height: f32) -> f32 {
self.top - (camera_height / 2.0) - (get_ldtk_tile_scale() / 2.0)
}
}
impl<'w, 's> MapQuery<'w, 's> {
// --- We put our logic in static accessors because we might source a level other
// --- than the currently active one. 'active' methods are a convenience to
// --- call the static accessors on whatever the current level is
pub fn get_indexer_for(level: &Level) -> Indexer {
Indexer::new(px_to_grid(level.px_wid), px_to_grid(level.px_hei))
}
pub fn for_each_layer_of(level: &Level, mut cb: impl FnMut(LayerRef)) {
if let Some(layers) = level.layer_instances.as_ref() {
for layer in layers.iter().rev().enumerate() {
cb(LayerRef::new(
layer.0,
MapQuery::get_indexer_for(level),
layer.1,
));
}
}
}
pub fn get_entities_of(level: &Level) -> Vec<&EntityInstance> {
level
.layer_instances
.as_ref()
.map(|layers| {
layers
.iter()
.flat_map(|layer| layer.entity_instances.iter())
.collect()
})
.unwrap_or_default()
}
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
pub fn get_instance_refs_of(level: &Level) -> Vec<InstanceRef> {
level
.layer_instances
.as_ref()
.map(|layers| {
layers
.iter()
.flat_map(|layer| layer.entity_instances.iter())
.map(|inst| InstanceRef { entity: inst })
.collect()
})
.unwrap_or_default()
}
pub fn get_filtered_entities_of(
level: &Level,
entity_type: impl ToString,
) -> Vec<&EntityInstance> {
let e_type = entity_type.to_string();
match level.layer_instances.as_ref() {
Some(inst) => inst
.iter()
.flat_map(|layer| layer.entity_instances.iter())
.filter(|inst| inst.identifier == e_type)
.collect(),
None => Vec::new(),
}
}
pub fn get_owned_entities_of(level: &Level) -> Vec<EntityInstance> {
level
.layer_instances
.as_ref()
.map(|layers| {
layers
.iter()
.flat_map(|layer| layer.entity_instances.iter().map(|inst| inst.serde_clone()))
.collect()
})
.unwrap_or_default()
}
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
pub fn get_camera_bounds_of(level: &Level) -> CameraBounds {
CameraBounds {
left: 0.0,
top: level.px_hei as f32,
bottom: 0.0,
right: level.px_wid as f32,
}
}
pub fn get_active_level(&self) -> Option<&Level> {
self.active
.as_ref()
.and_then(|index| self.index.get(&index.map))
}
pub fn get_entities(&self) -> Vec<&EntityInstance> {
self.get_active_level()
.map(|level| MapQuery::get_entities_of(level))
.unwrap_or_default()
}
pub fn get_camera_bounds(&self) -> Option<CameraBounds> {
self.get_active_level().map(MapQuery::get_camera_bounds_of)
}
pub fn for_each_layer(&self, mut cb: impl FnMut(LayerRef)) {
if let Some(level) = self.get_active_level() {
Self::for_each_layer_of(level, cb);
}
}
}