mirror of
https://github.com/seemueller-io/yachtpit.git
synced 2025-09-08 22:46:45 +00:00
add map foundation
This commit is contained in:
@@ -63,6 +63,13 @@ systems = { path = "../systems" }
|
||||
components = { path = "../components" }
|
||||
wasm-bindgen = "0.2"
|
||||
web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Window"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
# Platform-specific tokio features
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
tokio = { version = "1.0", features = ["rt", "rt-multi-thread"] }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
tokio = { version = "1.0", features = ["rt"] }
|
||||
|
||||
# keep the following in sync with Bevy's dependencies
|
||||
winit = { version = "0.30", default-features = false }
|
||||
|
@@ -8,6 +8,7 @@ use bevy::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use systems::{VesselSystem, SystemInteraction, SystemStatus};
|
||||
use components::{VesselData, SystemIndicator, SystemDisplayArea};
|
||||
use crate::ui::{spawn_gps_map_window, GpsMapState};
|
||||
|
||||
/// Resource for managing all yacht systems
|
||||
#[derive(Resource)]
|
||||
@@ -120,7 +121,9 @@ fn update_all_systems(
|
||||
|
||||
/// System to handle interactions with system indicator buttons
|
||||
fn handle_system_indicator_interactions(
|
||||
mut commands: Commands,
|
||||
mut system_manager: ResMut<SystemManager>,
|
||||
mut gps_map_state: ResMut<GpsMapState>,
|
||||
mut interaction_query: Query<
|
||||
(&Interaction, &mut BackgroundColor, &SystemIndicator),
|
||||
(Changed<Interaction>, With<Button>),
|
||||
@@ -134,6 +137,12 @@ fn handle_system_indicator_interactions(
|
||||
&indicator.system_id,
|
||||
SystemInteraction::Select
|
||||
);
|
||||
|
||||
// If GPS system is selected, spawn the map window
|
||||
if indicator.system_id == "gps" {
|
||||
spawn_gps_map_window(&mut commands, &mut gps_map_state);
|
||||
}
|
||||
|
||||
*background_color = BackgroundColor(Color::linear_rgb(0.0, 0.3, 0.5));
|
||||
}
|
||||
Interaction::Hovered => {
|
||||
|
@@ -10,7 +10,7 @@ use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin};
|
||||
use bevy::prelude::*;
|
||||
use crate::core::{ActionsPlugin, SystemManagerPlugin};
|
||||
use crate::core::system_manager::SystemManager;
|
||||
use crate::ui::{LoadingPlugin, MenuPlugin};
|
||||
use crate::ui::{LoadingPlugin, MenuPlugin, GpsMapPlugin};
|
||||
use systems::{PlayerPlugin, setup_instrument_cluster, get_vessel_systems};
|
||||
|
||||
// See https://bevy-cheatbook.github.io/programming/states.html
|
||||
@@ -40,6 +40,7 @@ impl Plugin for GamePlugin {
|
||||
app.init_state::<GameState>().add_plugins((
|
||||
LoadingPlugin,
|
||||
MenuPlugin,
|
||||
GpsMapPlugin,
|
||||
ActionsPlugin,
|
||||
SystemManagerPlugin,
|
||||
PlayerPlugin,
|
||||
|
167
crates/yachtpit/src/ui/gps_map.rs
Normal file
167
crates/yachtpit/src/ui/gps_map.rs
Normal file
@@ -0,0 +1,167 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::window::Window;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Component to mark the GPS map window
|
||||
#[derive(Component)]
|
||||
pub struct GpsMapWindow;
|
||||
|
||||
/// Component to mark map tiles
|
||||
#[derive(Component)]
|
||||
pub struct MapTile {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub zoom: u8,
|
||||
}
|
||||
|
||||
/// Resource to manage the GPS map state
|
||||
#[derive(Resource, Default)]
|
||||
pub struct GpsMapState {
|
||||
pub window_id: Option<Entity>,
|
||||
pub center_lat: f64,
|
||||
pub center_lon: f64,
|
||||
pub zoom_level: u8,
|
||||
pub tile_cache: HashMap<String, Handle<Image>>,
|
||||
}
|
||||
|
||||
impl GpsMapState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
window_id: None,
|
||||
center_lat: 43.6377, // Default to Monaco coordinates from GPS system
|
||||
center_lon: -1.4497,
|
||||
zoom_level: 10,
|
||||
tile_cache: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin for GPS map functionality
|
||||
pub struct GpsMapPlugin;
|
||||
|
||||
impl Plugin for GpsMapPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<GpsMapState>()
|
||||
.add_systems(Update, (
|
||||
handle_gps_map_window_events,
|
||||
update_map_tiles,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// System to handle GPS map window events
|
||||
fn handle_gps_map_window_events(
|
||||
mut commands: Commands,
|
||||
mut gps_map_state: ResMut<GpsMapState>,
|
||||
windows: Query<Entity, With<Window>>,
|
||||
) {
|
||||
// For now, we'll keep this simple and just track the window
|
||||
// In a full implementation, we would handle window close events properly
|
||||
if let Some(map_window_id) = gps_map_state.window_id {
|
||||
// Check if the window still exists
|
||||
if windows.get(map_window_id).is_err() {
|
||||
gps_map_state.window_id = None;
|
||||
info!("GPS map window was closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// System to update map tiles
|
||||
fn update_map_tiles(
|
||||
mut commands: Commands,
|
||||
gps_map_state: Res<GpsMapState>,
|
||||
asset_server: Res<AssetServer>,
|
||||
map_tiles: Query<Entity, With<MapTile>>,
|
||||
) {
|
||||
if gps_map_state.window_id.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
// For now, we'll create a simple placeholder map
|
||||
// In a full implementation, this would fetch actual OSM tiles
|
||||
if map_tiles.is_empty() {
|
||||
spawn_placeholder_map(&mut commands, &asset_server);
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn a placeholder map with basic tiles
|
||||
fn spawn_placeholder_map(commands: &mut Commands, _asset_server: &Res<AssetServer>) {
|
||||
// Create a simple grid of colored rectangles to represent map tiles
|
||||
for x in -2..=2 {
|
||||
for y in -2..=2 {
|
||||
let color = if (x + y) % 2 == 0 {
|
||||
Color::linear_rgb(0.3, 0.7, 0.3) // Green for land
|
||||
} else {
|
||||
Color::linear_rgb(0.2, 0.4, 0.8) // Blue for water
|
||||
};
|
||||
|
||||
commands.spawn((
|
||||
Sprite {
|
||||
color,
|
||||
custom_size: Some(Vec2::new(256.0, 256.0)),
|
||||
..default()
|
||||
},
|
||||
Transform::from_translation(Vec3::new(
|
||||
x as f32 * 256.0,
|
||||
y as f32 * 256.0,
|
||||
0.0,
|
||||
)),
|
||||
MapTile {
|
||||
x,
|
||||
y,
|
||||
zoom: 10,
|
||||
},
|
||||
GpsMapWindow,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Add a marker for the vessel position
|
||||
commands.spawn((
|
||||
Sprite {
|
||||
color: Color::linear_rgb(1.0, 0.0, 0.0),
|
||||
custom_size: Some(Vec2::new(20.0, 20.0)),
|
||||
..default()
|
||||
},
|
||||
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0)),
|
||||
GpsMapWindow,
|
||||
));
|
||||
}
|
||||
|
||||
/// Function to spawn the GPS map window
|
||||
pub fn spawn_gps_map_window(
|
||||
commands: &mut Commands,
|
||||
gps_map_state: &mut ResMut<GpsMapState>,
|
||||
) {
|
||||
if gps_map_state.window_id.is_some() {
|
||||
info!("GPS map window already open");
|
||||
return;
|
||||
}
|
||||
|
||||
info!("Spawning GPS map window");
|
||||
|
||||
// Create a new window for the GPS map
|
||||
let window_entity = commands.spawn((
|
||||
Window {
|
||||
title: "GPS Navigation - OpenStreetMap".to_string(),
|
||||
resolution: (800.0, 600.0).into(),
|
||||
position: bevy::window::WindowPosition::Centered(bevy::window::MonitorSelection::Current),
|
||||
..default()
|
||||
},
|
||||
GpsMapWindow,
|
||||
)).id();
|
||||
|
||||
// Create a camera for the map window
|
||||
commands.spawn((
|
||||
Camera2d,
|
||||
Camera {
|
||||
target: bevy::render::camera::RenderTarget::Window(bevy::window::WindowRef::Entity(window_entity)),
|
||||
..default()
|
||||
},
|
||||
GpsMapWindow,
|
||||
));
|
||||
|
||||
gps_map_state.window_id = Some(window_entity);
|
||||
|
||||
info!("GPS map window spawned with entity: {:?}", window_entity);
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
pub mod loading;
|
||||
pub mod menu;
|
||||
pub mod gps_map;
|
||||
|
||||
pub use loading::LoadingPlugin;
|
||||
pub use menu::MenuPlugin;
|
||||
pub use gps_map::{GpsMapPlugin, spawn_gps_map_window, GpsMapState};
|
||||
|
Reference in New Issue
Block a user