Add panning, zooming, and info box
011cd40da8b4a8ae3324d1b0cf6f216641d44225
This commit is contained in:
parent
6774fcd2fa
commit
26d3e9b4a6
7 changed files with 179 additions and 29 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -427,6 +427,15 @@ dependencies = [
|
||||||
"glam",
|
"glam",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bevy_pancam"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ebc698de3f4e824a67f517fe9cca35f08d5fdaab99ed8e141102c582768fc62"
|
||||||
|
dependencies = [
|
||||||
|
"bevy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_pbr"
|
name = "bevy_pbr"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
@ -2645,6 +2654,7 @@ name = "worlds-sim-rust"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
|
"bevy_pancam",
|
||||||
"save",
|
"save",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ resolver = "2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = ["save/debug"]
|
debug = ["save/debug"]
|
||||||
render = ["bevy/bevy_asset", "bevy/bevy_winit", "bevy/render", "save/render"]
|
render = ["bevy/bevy_asset", "bevy/bevy_winit", "bevy/render", "save/render", "dep:bevy_pancam"]
|
||||||
default = ["render", "debug"]
|
default = ["render", "debug"]
|
||||||
|
|
||||||
[dependencies.save]
|
[dependencies.save]
|
||||||
|
@ -15,3 +15,7 @@ path = "save"
|
||||||
[dependencies.bevy]
|
[dependencies.bevy]
|
||||||
version = "0.8"
|
version = "0.8"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.bevy_pancam]
|
||||||
|
version = "0.6.1"
|
||||||
|
optional = true
|
|
@ -4,7 +4,9 @@ use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy::{math::Vec3A, prelude::Vec2, utils::default};
|
// TODO: Logging doesn't seem to work here? Figure out why and fix
|
||||||
|
|
||||||
|
use bevy::{log::info, math::Vec3A, prelude::Vec2, utils::default};
|
||||||
use noise::{NoiseFn, Perlin, Seedable};
|
use noise::{NoiseFn, Perlin, Seedable};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
@ -145,11 +147,14 @@ impl World {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_continents(&mut self) {
|
fn generate_continents(&mut self) {
|
||||||
|
info!("Generating continents");
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let width = self.width as f32;
|
let width = self.width as f32;
|
||||||
let height = self.height as f32;
|
let height = self.height as f32;
|
||||||
|
|
||||||
for i in 0..Self::NUM_CONTINENTS {
|
for i in 0..Self::NUM_CONTINENTS {
|
||||||
|
info!("{}/{}", i, Self::NUM_CONTINENTS);
|
||||||
|
|
||||||
self.continent_offsets[i as usize].x = rng
|
self.continent_offsets[i as usize].x = rng
|
||||||
.gen_range(width * i as f32 * 2.0 / 5.0..width * (i as f32 + 2.0) * 2.0 / 5.0)
|
.gen_range(width * i as f32 * 2.0 / 5.0..width * (i as f32 + 2.0) * 2.0 / 5.0)
|
||||||
.repeat(width);
|
.repeat(width);
|
||||||
|
@ -159,6 +164,7 @@ impl World {
|
||||||
self.continent_widths[i as usize] =
|
self.continent_widths[i as usize] =
|
||||||
rng.gen_range(Self::CONTINENT_MIN_WIDTH_FACTOR..Self::CONTINENT_MAX_WIDTH_FACTOR);
|
rng.gen_range(Self::CONTINENT_MIN_WIDTH_FACTOR..Self::CONTINENT_MAX_WIDTH_FACTOR);
|
||||||
}
|
}
|
||||||
|
info!("Done generating continents");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn continent_modifier(&self, x: usize, y: usize) -> f32 {
|
fn continent_modifier(&self, x: usize, y: usize) -> f32 {
|
||||||
|
@ -195,6 +201,7 @@ impl World {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_altitude(&mut self) -> Result<(), CartesianError> {
|
fn generate_altitude(&mut self) -> Result<(), CartesianError> {
|
||||||
|
info!("Generating altitude");
|
||||||
self.generate_continents();
|
self.generate_continents();
|
||||||
|
|
||||||
const RADIUS_1: f32 = 0.5;
|
const RADIUS_1: f32 = 0.5;
|
||||||
|
@ -212,6 +219,8 @@ impl World {
|
||||||
for y in 0..self.terrain.len() {
|
for y in 0..self.terrain.len() {
|
||||||
let alpha = (y as f32 / self.height as f32) * PI;
|
let alpha = (y as f32 / self.height as f32) * PI;
|
||||||
|
|
||||||
|
info!("{}/{}", y, self.terrain.len());
|
||||||
|
|
||||||
for x in 0..self.terrain[y].len() {
|
for x in 0..self.terrain[y].len() {
|
||||||
let beta = (x as f32 / self.width as f32) * TAU;
|
let beta = (x as f32 / self.width as f32) * TAU;
|
||||||
|
|
||||||
|
@ -250,6 +259,7 @@ impl World {
|
||||||
self.terrain[y][x].altitude = Self::calculate_altitude(raw_altitude);
|
self.terrain[y][x].altitude = Self::calculate_altitude(raw_altitude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info!("Done generating altitude");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,9 @@ impl WorldManager {
|
||||||
pub fn get_world(&self) -> Option<&World> {
|
pub fn get_world(&self) -> Option<&World> {
|
||||||
self.world.as_ref()
|
self.world.as_ref()
|
||||||
}
|
}
|
||||||
|
pub fn world(&self) -> &World {
|
||||||
|
self.get_world().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_world(&mut self) -> Result<&World, WorldGenError> {
|
pub fn new_world(&mut self) -> Result<&World, WorldGenError> {
|
||||||
let seed = random();
|
let seed = random();
|
||||||
|
@ -142,7 +145,7 @@ impl WorldManager {
|
||||||
let mut shade_value = 1.0;
|
let mut shade_value = 1.0;
|
||||||
|
|
||||||
while shade_value > altitude / World::MAX_ALTITUDE {
|
while shade_value > altitude / World::MAX_ALTITUDE {
|
||||||
shade_value -= 0.1;
|
shade_value -= 0.05;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color::rgb(shade_value, shade_value, shade_value)
|
Color::rgb(shade_value, shade_value, shade_value)
|
||||||
|
|
158
src/main.rs
158
src/main.rs
|
@ -32,7 +32,9 @@
|
||||||
#![warn(unused_results)]
|
#![warn(unused_results)]
|
||||||
#![warn(variant_size_differences)]
|
#![warn(variant_size_differences)]
|
||||||
|
|
||||||
mod world_plugins;
|
mod plugins;
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
app::App,
|
app::App,
|
||||||
|
@ -42,7 +44,7 @@ use bevy::{
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::{AssetServer, Assets},
|
asset::{AssetServer, Assets},
|
||||||
core_pipeline::core_2d::Camera2dBundle,
|
core_pipeline::core_2d::{Camera2d, Camera2dBundle},
|
||||||
ecs::{
|
ecs::{
|
||||||
change_detection::ResMut,
|
change_detection::ResMut,
|
||||||
component::Component,
|
component::Component,
|
||||||
|
@ -50,24 +52,31 @@ use bevy::{
|
||||||
system::{Commands, Query, Res},
|
system::{Commands, Query, Res},
|
||||||
},
|
},
|
||||||
hierarchy::BuildChildren,
|
hierarchy::BuildChildren,
|
||||||
|
prelude::Vec2,
|
||||||
render::{
|
render::{
|
||||||
|
camera::{Camera, RenderTarget},
|
||||||
color::Color,
|
color::Color,
|
||||||
render_resource::{
|
render_resource::{
|
||||||
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
|
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
|
||||||
},
|
},
|
||||||
texture::{Image, ImageSettings},
|
texture::{Image, ImageSettings},
|
||||||
},
|
},
|
||||||
|
sprite::{Sprite, SpriteBundle},
|
||||||
|
text::Text,
|
||||||
|
transform::components::GlobalTransform,
|
||||||
ui::{
|
ui::{
|
||||||
entity::{ButtonBundle, ImageBundle, NodeBundle, TextBundle},
|
entity::{ButtonBundle, NodeBundle, TextBundle},
|
||||||
widget::Button,
|
widget::Button,
|
||||||
AlignItems, FocusPolicy, Interaction, JustifyContent, PositionType, Size, Style, UiColor,
|
AlignItems, FocusPolicy, Interaction, JustifyContent, PositionType, Size, Style, UiColor,
|
||||||
UiImage, UiRect, Val,
|
UiRect, Val,
|
||||||
},
|
},
|
||||||
utils::default,
|
utils::default,
|
||||||
window::{CursorIcon, WindowDescriptor, Windows},
|
window::{CursorIcon, WindowDescriptor, Windows},
|
||||||
winit::WinitSettings,
|
winit::WinitSettings,
|
||||||
};
|
};
|
||||||
use world_plugins::WorldPlugins;
|
#[cfg(feature = "render")]
|
||||||
|
use plugins::PanCam;
|
||||||
|
use plugins::WorldPlugins;
|
||||||
use save::*;
|
use save::*;
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
|
@ -78,17 +87,33 @@ fn refresh_world_texture(images: &mut Assets<Image>, world_manager: &WorldManage
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
#[derive(Component, Default)]
|
#[derive(Component)]
|
||||||
struct RainfallButton;
|
struct RainfallButton;
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
#[derive(Component, Default)]
|
#[derive(Component)]
|
||||||
struct TemperatureButton;
|
struct TemperatureButton;
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
#[derive(Component, Default)]
|
#[derive(Component)]
|
||||||
struct ContoursButton;
|
struct ContoursButton;
|
||||||
|
|
||||||
|
#[cfg(feature = "render")]
|
||||||
|
#[derive(Component)]
|
||||||
|
struct InfoPanel;
|
||||||
|
|
||||||
|
#[cfg(feature = "render")]
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct CursorMapPosition {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
impl Display for CursorMapPosition {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("x: {}, y: {}", self.x, self.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const NORMAL_BUTTON: Color = Color::rgb(0.15, 0.15, 0.15);
|
const NORMAL_BUTTON: Color = Color::rgb(0.15, 0.15, 0.15);
|
||||||
const HOVERED_BUTTON: Color = Color::rgb(0.25, 0.25, 0.25);
|
const HOVERED_BUTTON: Color = Color::rgb(0.25, 0.25, 0.25);
|
||||||
const PRESSED_BUTTON: Color = Color::rgb(0.35, 0.60, 0.35);
|
const PRESSED_BUTTON: Color = Color::rgb(0.35, 0.60, 0.35);
|
||||||
|
@ -191,6 +216,59 @@ fn handle_contours_button(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "render")]
|
||||||
|
fn update_cursor_map_position(
|
||||||
|
mut cursor_map_position: ResMut<'_, CursorMapPosition>,
|
||||||
|
transform: Query<'_, '_, (&Camera, &GlobalTransform), With<Camera2d>>,
|
||||||
|
windows: Res<'_, Windows>,
|
||||||
|
world_manager: Res<'_, WorldManager>,
|
||||||
|
) {
|
||||||
|
let (camera, transform) = transform.single();
|
||||||
|
|
||||||
|
let window = match camera.target {
|
||||||
|
RenderTarget::Window(window_id) => windows.get(window_id).unwrap(),
|
||||||
|
RenderTarget::Image(_) => windows.primary(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(screen_position) = window.cursor_position() {
|
||||||
|
let window_size = Vec2::new(window.width(), window.height());
|
||||||
|
|
||||||
|
// GPU coordinates [-1..1]
|
||||||
|
let ndc = (screen_position / window_size) * 2.0;
|
||||||
|
|
||||||
|
// Matrix to reverse camera transform
|
||||||
|
let ndc_to_world = transform.compute_matrix() * camera.projection_matrix().inverse();
|
||||||
|
|
||||||
|
let world_position =
|
||||||
|
ndc_to_world.project_point3(ndc.extend(-1.0)).truncate() / WORLD_SCALE as f32;
|
||||||
|
|
||||||
|
cursor_map_position.x = world_position.x.round() as i32;
|
||||||
|
cursor_map_position.y = world_manager.world().height - world_position.y.round() as i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "render")]
|
||||||
|
fn update_info_panel(
|
||||||
|
cursor_position: Res<'_, CursorMapPosition>,
|
||||||
|
world_manager: Res<'_, WorldManager>,
|
||||||
|
mut text: Query<'_, '_, &mut Text, With<InfoPanel>>,
|
||||||
|
) {
|
||||||
|
let world = world_manager.world();
|
||||||
|
text.single_mut().sections[0].value = if cursor_position.x >= 0
|
||||||
|
&& cursor_position.x < world.width
|
||||||
|
&& cursor_position.y >= 0
|
||||||
|
&& cursor_position.y < world.height
|
||||||
|
{
|
||||||
|
let cell = &world.terrain[cursor_position.y as usize][cursor_position.x as usize];
|
||||||
|
format!(
|
||||||
|
"Mouse position: {}\nAltitude: {}\nRainfall: {}\nTemperature: {}",
|
||||||
|
*cursor_position, cell.altitude, cell.rainfall, cell.temperature
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!("Mouse position: {}\nOut of bounds", *cursor_position)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "render")]
|
#[cfg(feature = "render")]
|
||||||
fn generate_graphics(
|
fn generate_graphics(
|
||||||
mut commands: Commands<'_, '_>,
|
mut commands: Commands<'_, '_>,
|
||||||
|
@ -198,7 +276,13 @@ fn generate_graphics(
|
||||||
mut world_manager: ResMut<'_, WorldManager>,
|
mut world_manager: ResMut<'_, WorldManager>,
|
||||||
asset_server: Res<'_, AssetServer>,
|
asset_server: Res<'_, AssetServer>,
|
||||||
) {
|
) {
|
||||||
let world = world_manager.get_world().unwrap();
|
use bevy::ui::AlignSelf;
|
||||||
|
|
||||||
|
let world = world_manager.world();
|
||||||
|
let custom_sprite_size = Vec2 {
|
||||||
|
x: (WORLD_SCALE * world.width) as f32,
|
||||||
|
y: (WORLD_SCALE * world.height) as f32,
|
||||||
|
};
|
||||||
|
|
||||||
let image_handle = images.add(Image {
|
let image_handle = images.add(Image {
|
||||||
data: world_manager.world_color_bytes(),
|
data: world_manager.world_color_bytes(),
|
||||||
|
@ -219,7 +303,17 @@ fn generate_graphics(
|
||||||
});
|
});
|
||||||
world_manager.image_handle_id = image_handle.id;
|
world_manager.image_handle_id = image_handle.id;
|
||||||
|
|
||||||
_ = commands.spawn_bundle(Camera2dBundle::default());
|
_ = commands
|
||||||
|
.spawn_bundle(Camera2dBundle::default())
|
||||||
|
.insert(PanCam::default());
|
||||||
|
_ = commands.spawn_bundle(SpriteBundle {
|
||||||
|
texture: images.get_handle(world_manager.image_handle_id),
|
||||||
|
sprite: Sprite {
|
||||||
|
custom_size: Some(custom_sprite_size),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
..default()
|
||||||
|
});
|
||||||
_ = commands
|
_ = commands
|
||||||
.spawn_bundle(NodeBundle {
|
.spawn_bundle(NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
|
@ -230,15 +324,33 @@ fn generate_graphics(
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.with_children(|root_node| {
|
.with_children(|root_node| {
|
||||||
_ = root_node.spawn_bundle(ImageBundle {
|
_ = root_node
|
||||||
|
.spawn_bundle(NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
size: Size::new(Val::Percent(100.0), Val::Auto),
|
// align_items: AlignItems::FlexEnd,
|
||||||
|
align_self: AlignSelf::FlexEnd,
|
||||||
|
padding: UiRect::all(Val::Px(2.0)),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
image: UiImage(image_handle),
|
color: Color::rgba(1.0, 1.0, 1.0, 0.05).into(),
|
||||||
|
focus_policy: FocusPolicy::Pass,
|
||||||
..default()
|
..default()
|
||||||
|
})
|
||||||
|
.with_children(|info_panel| {
|
||||||
|
_ = info_panel
|
||||||
|
.spawn_bundle(TextBundle {
|
||||||
|
text: Text::from_section(
|
||||||
|
"Info Panel",
|
||||||
|
bevy::text::TextStyle {
|
||||||
|
font: asset_server.load("JuliaMono.ttf"),
|
||||||
|
font_size: 15.0,
|
||||||
|
color: Color::WHITE,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
.insert(InfoPanel);
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = root_node
|
_ = root_node
|
||||||
.spawn_bundle(NodeBundle {
|
.spawn_bundle(NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
|
@ -264,7 +376,7 @@ fn generate_graphics(
|
||||||
color: NORMAL_BUTTON.into(),
|
color: NORMAL_BUTTON.into(),
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(RainfallButton::default())
|
.insert(RainfallButton)
|
||||||
.with_children(|button| {
|
.with_children(|button| {
|
||||||
_ = button.spawn_bundle(TextBundle {
|
_ = button.spawn_bundle(TextBundle {
|
||||||
text: bevy::text::Text::from_section(
|
text: bevy::text::Text::from_section(
|
||||||
|
@ -289,7 +401,7 @@ fn generate_graphics(
|
||||||
color: NORMAL_BUTTON.into(),
|
color: NORMAL_BUTTON.into(),
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(TemperatureButton::default())
|
.insert(TemperatureButton)
|
||||||
.with_children(|button| {
|
.with_children(|button| {
|
||||||
_ = button.spawn_bundle(TextBundle {
|
_ = button.spawn_bundle(TextBundle {
|
||||||
text: bevy::text::Text::from_section(
|
text: bevy::text::Text::from_section(
|
||||||
|
@ -314,7 +426,7 @@ fn generate_graphics(
|
||||||
color: NORMAL_BUTTON.into(),
|
color: NORMAL_BUTTON.into(),
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
.insert(ContoursButton::default())
|
.insert(ContoursButton)
|
||||||
.with_children(|button| {
|
.with_children(|button| {
|
||||||
_ = button.spawn_bundle(TextBundle {
|
_ = button.spawn_bundle(TextBundle {
|
||||||
text: bevy::text::Text::from_section(
|
text: bevy::text::Text::from_section(
|
||||||
|
@ -332,6 +444,7 @@ fn generate_graphics(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const WORLD_SCALE: i32 = 3;
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
let mut manager = WorldManager::new();
|
let mut manager = WorldManager::new();
|
||||||
|
@ -344,16 +457,19 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// Use nearest-neighbor rendering for cripsier pixels
|
// Use nearest-neighbor rendering for cripsier pixels
|
||||||
.insert_resource(ImageSettings::default_nearest())
|
.insert_resource(ImageSettings::default_nearest())
|
||||||
.insert_resource(WindowDescriptor {
|
.insert_resource(WindowDescriptor {
|
||||||
width: (2 * world.width) as f32,
|
width: (WORLD_SCALE * world.width) as f32,
|
||||||
height: (2 * world.height) as f32,
|
height: (WORLD_SCALE * world.height) as f32,
|
||||||
title: String::from("World-RS"),
|
title: String::from("World-RS"),
|
||||||
resizable: true,
|
resizable: true,
|
||||||
..default()
|
..default()
|
||||||
})
|
})
|
||||||
|
.insert_resource(CursorMapPosition::default())
|
||||||
.add_startup_system(generate_graphics)
|
.add_startup_system(generate_graphics)
|
||||||
.add_system(handle_rainfall_button)
|
.add_system(handle_rainfall_button)
|
||||||
.add_system(handle_temperature_button)
|
.add_system(handle_temperature_button)
|
||||||
.add_system(handle_contours_button);
|
.add_system(handle_contours_button)
|
||||||
|
.add_system(update_cursor_map_position)
|
||||||
|
.add_system(update_info_panel);
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "render"))]
|
#[cfg(not(feature = "render"))]
|
||||||
{
|
{
|
||||||
|
@ -375,7 +491,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.insert_resource(manager).add_plugins(WorldPlugins).run();
|
app.add_plugins(WorldPlugins).insert_resource(manager).run();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
4
src/plugins/mod.rs
Normal file
4
src/plugins/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
pub(crate) mod world_plugins;
|
||||||
|
pub(crate) use world_plugins::WorldPlugins;
|
||||||
|
|
||||||
|
pub(crate) use bevy_pancam::PanCam;
|
|
@ -22,6 +22,8 @@ impl PluginGroup for WorldPlugins {
|
||||||
input::InputPlugin, render::RenderPlugin, sprite::SpritePlugin, text::TextPlugin,
|
input::InputPlugin, render::RenderPlugin, sprite::SpritePlugin, text::TextPlugin,
|
||||||
transform::TransformPlugin, ui::UiPlugin, window::WindowPlugin, winit::WinitPlugin,
|
transform::TransformPlugin, ui::UiPlugin, window::WindowPlugin, winit::WinitPlugin,
|
||||||
};
|
};
|
||||||
|
use bevy_pancam::PanCamPlugin;
|
||||||
|
|
||||||
_ = group
|
_ = group
|
||||||
.add(TransformPlugin::default())
|
.add(TransformPlugin::default())
|
||||||
// hierarchy
|
// hierarchy
|
||||||
|
@ -34,7 +36,8 @@ impl PluginGroup for WorldPlugins {
|
||||||
.add(CorePipelinePlugin::default())
|
.add(CorePipelinePlugin::default())
|
||||||
.add(SpritePlugin::default())
|
.add(SpritePlugin::default())
|
||||||
.add(TextPlugin::default())
|
.add(TextPlugin::default())
|
||||||
.add(UiPlugin::default());
|
.add(UiPlugin::default())
|
||||||
|
.add(PanCamPlugin::default());
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "render"))]
|
#[cfg(not(feature = "render"))]
|
||||||
{
|
{
|
Loading…
Reference in a new issue