forked from octotep/bevy_crossterm
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathassets.rs
147 lines (127 loc) · 5 KB
/
assets.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
139
140
141
142
143
144
145
146
147
use bevy::prelude::*;
use bevy_crossterm::prelude::*;
use bevy::log::LogPlugin;
use bevy_asset::LoadedUntypedAsset;
use std::default::Default;
#[derive(Clone, States, Default, Eq, PartialEq, Hash, Debug)]
enum GameState {
#[default]
Loading,
Running,
}
// PRO TIP: _technically_ since Sprite's are just created using strings, an easier way to load them from an external
// file is just:
//static TITLE_TEXT: &str = include_str!("assets/demo/title.txt");
// then just:
//sprites.add(Sprite::new(TITLE_TEXT));
// and boom, you have yourself a sprite in the asset system.
// That's nice and easy - don't have to worry about async, don't need to distribute files alongside your exe.
// But then you can't take advantage of hot reloading, and plus it only works for sprites. StyleMaps have to go through
// the AssetServer if you want to load them from an external file.
pub fn main() {
// Window settings must happen before the crossterm Plugin
let mut settings = CrosstermWindowSettings::default();
settings.set_title("Assets example");
App::new()
.insert_resource(settings)
.add_plugins(bevy_app::ScheduleRunnerPlugin::run_loop(
std::time::Duration::from_millis(50),
))
.add_plugins(
DefaultPlugins
.set(TaskPoolPlugin {
task_pool_options: TaskPoolOptions::with_num_threads(1),
})
.set(LogPlugin {
filter: "off".into(),
level: bevy::log::Level::ERROR,
..default()
}),
)
.add_plugins(CrosstermPlugin)
.init_state::<GameState>()
.add_systems(OnEnter(GameState::Loading), default_settings)
.add_systems(OnEnter(GameState::Loading), load_assets)
.add_systems(Update, check_for_loaded)
.add_systems(OnEnter(GameState::Running), create_entities)
.run();
}
static ASSETS: &[&str] = &["demo/title.txt", "demo/title.stylemap"];
#[derive(Resource)]
struct CrosstermAssets(Vec<Handle<LoadedUntypedAsset>>);
fn default_settings(mut cursor: ResMut<Cursor>) {
cursor.hidden = true;
}
// This is a simple system that loads assets from the filesystem
fn load_assets(mut commands: Commands, asset_server: Res<AssetServer>) {
// Load the assets we want
let mut handles = Vec::new();
for asset in ASSETS {
handles.push(asset_server.load_untyped(*asset));
}
commands.insert_resource(CrosstermAssets(handles));
}
// This function exists solely because bevy's asset loading is async.
// We need to wait until all assets are loaded before we do anything with them.
fn check_for_loaded(
asset_server: Res<AssetServer>,
handles: Res<CrosstermAssets>,
mut next_state: ResMut<NextState<GameState>>,
) {
let mut all_done = true;
for handle in handles.0.iter() {
let data = asset_server.load_state(handle);
match data {
bevy::asset::LoadState::NotLoaded | bevy::asset::LoadState::Loading => {
all_done = false;
break;
}
bevy::asset::LoadState::Loaded => {}
bevy::asset::LoadState::Failed => {
panic!("This is an example and should not fail")
}
}
}
if all_done {
next_state.set(GameState::Running);
}
}
// Now that we're sure the assets are loaded, spawn a new sprite into the world
fn create_entities(
mut commands: Commands,
window: Query<&CrosstermWindow>,
asset_server: Res<AssetServer>,
mut sprites: ResMut<Assets<Sprite>>,
mut stylemaps: ResMut<Assets<StyleMap>>,
) {
// I want to center the title, so i needed to wait until it was loaded before I could actually access
// the underlying data to see how wide the sprite is and do the math
let title_handle = asset_server.get_handle("demo/title.txt").unwrap();
let title_sprite = sprites
.get(&title_handle)
.expect("We waited for asset loading");
let window = window.single();
let center_x = window.x_center() as i32 - title_sprite.x_center() as i32;
let center_y = window.y_center() as i32 - title_sprite.y_center() as i32;
commands.spawn(SpriteBundle {
sprite: title_handle.clone(),
position: Position::with_xy(center_x, center_y),
stylemap: asset_server.get_handle("demo/title.stylemap").unwrap(),
..Default::default()
});
let text = Sprite::new(
"You may freely change demo/title.txt and demo/title.stylemap,\n\
bevy_crossterm will automatically reload changed assets and redraw affected sprites.",
);
let center_x = window.x_center() as i32 - text.x_center() as i32;
let center_y = window.y_center() as i32 - text.y_center() as i32;
let text = sprites.add(text);
let color = stylemaps.add(StyleMap::default());
// Spawn two sprites into the world
commands.spawn(SpriteBundle {
sprite: text,
position: Position::with_xy(center_x, center_y + 6),
stylemap: color.clone(),
..Default::default()
});
}