From bee1573e3d072b62cb7a24e3a5050ea53b2b3d0a Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 3 Jul 2026 10:16:36 +0300 Subject: [PATCH] Images of plates creating and drawing --- src/collision_automation.rs | 16 ++++ src/collision_world.rs | 24 ++--- src/main.rs | 3 +- src/plate_automation.rs | 5 +- src/seed_automation.rs | 5 +- src/subplate_automation.rs | 182 +++++++++++++++++++++++++++++------- 6 files changed, 175 insertions(+), 60 deletions(-) create mode 100644 src/collision_automation.rs diff --git a/src/collision_automation.rs b/src/collision_automation.rs new file mode 100644 index 0000000..c30d814 --- /dev/null +++ b/src/collision_automation.rs @@ -0,0 +1,16 @@ +use bevy::prelude::*; +use crate::collision_world::CollisionWorld; +use crate::hex_table::HexTable; +use crate::table::Table; + +#[derive(Component)] +pub struct Plate{ + +} +#[derive(Component)] +pub struct CollisionAutomation { + pub world: CollisionWorld, + pub view: Table, + pub border: HexTable, +} + diff --git a/src/collision_world.rs b/src/collision_world.rs index 4b7ab39..6d39638 100644 --- a/src/collision_world.rs +++ b/src/collision_world.rs @@ -2,28 +2,18 @@ use bevy::prelude::*; #[derive(Clone)] pub struct CollisionWorld { - bodies: Vec> + pub(crate) bodies: Vec> } #[derive(Clone)] pub struct CollisionBody { - value: T, - offset: Vec2, - border: Vec, - forces: Vec, - resistance: f32, + pub(crate) value: T, + pub(crate) position: Vec2, + pub(crate) border: Vec, + pub(crate) forces: Vec, + pub(crate) mass: f32, } impl CollisionWorld { - pub fn new(parts: Vec<(Vec, T)>) -> CollisionWorld { - Self{ - bodies: parts.iter().map(|(border, id)| {CollisionBody{ - value: id.clone(), - offset: Vec2::ZERO, - forces: vec![Vec2::ZERO; border.len()], - border: border.clone(), - resistance: 1.0, - }}).collect(), - } - } + } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c6243a9..646121b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,7 @@ mod seed_automation; mod subplate_automation; mod table; mod collision_world; +mod collision_automation; use crate::subplate_automation::HexMatrixView; use crate::table::{Table}; @@ -56,7 +57,7 @@ fn setup(mut commands: Commands, mut images: ResMut>) { commands.spawn((shape, automation, Moving)); - let seeded_rng = ChaCha8Rng::seed_from_u64(rand::random()); + let seeded_rng = ChaCha8Rng::seed_from_u64(0); commands.insert_resource(SeededRng(seeded_rng)); let mut hex_image = Image::default(); diff --git a/src/plate_automation.rs b/src/plate_automation.rs index 69b71bc..96703cf 100644 --- a/src/plate_automation.rs +++ b/src/plate_automation.rs @@ -4,7 +4,7 @@ use crate::SeededRng; use bevy::asset::Assets; use bevy::image::Image; use bevy::input::ButtonInput; -use bevy::prelude::{Commands, Component, Entity, KeyCode, Query, Res, ResMut, Single, Sprite}; +use bevy::prelude::*; use rand::RngExt; use rand_chacha::ChaCha8Rng; use rayon::iter::IndexedParallelIterator; @@ -21,14 +21,13 @@ pub fn update_automation_view( let (sprite, automation) = query.into_inner(); let image = automation.world.get_image_data(); - // images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); commands.entity(request.into_inner().1).despawn(); } pub fn update_automation( - mut query: Single<(&mut PlateAutomation, Entity)>, + query: Single<(&mut PlateAutomation, Entity)>, mut seeded_rng: ResMut, keys: Res>, mut commands: Commands, diff --git a/src/seed_automation.rs b/src/seed_automation.rs index 5b900fd..ffb0097 100644 --- a/src/seed_automation.rs +++ b/src/seed_automation.rs @@ -4,7 +4,7 @@ use crate::SeededRng; use bevy::asset::Assets; use bevy::image::Image; use bevy::input::ButtonInput; -use bevy::prelude::{Commands, Component, Entity, KeyCode, Query, Res, ResMut, Single, Sprite}; +use bevy::prelude::*; use rand::RngExt; use rand_chacha::ChaCha8Rng; @@ -18,12 +18,11 @@ pub fn update_automation_view( let image = automation.world.get_image_data(); - // images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); } pub fn update_automation( - mut query: Single<(&mut SeedAutomation, Entity)>, + query: Single<(&mut SeedAutomation, Entity)>, mut seeded_rng: ResMut, keys: Res>, mut commands: Commands) { diff --git a/src/subplate_automation.rs b/src/subplate_automation.rs index 22606bf..3b9ff2d 100644 --- a/src/subplate_automation.rs +++ b/src/subplate_automation.rs @@ -1,13 +1,12 @@ +use crate::collision_world::{CollisionBody, CollisionWorld}; use crate::hex_table::HexTable; use crate::table::{IntoImage, Table}; -use crate::SeededRng; -use bevy::asset::Assets; +use crate::{Moving, SeededRng}; +use bevy::asset::{Assets, RenderAssetUsages}; use bevy::image::Image; use bevy::input::ButtonInput; -use bevy::prelude::{ - Commands, Component, Entity, KeyCode, Query, Res, ResMut, Single, Sprite, - With, -}; +use bevy::prelude::*; +use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat}; use rand::RngExt; use rand_chacha::ChaCha8Rng; use std::collections::HashMap; @@ -22,7 +21,6 @@ pub fn update_automation_view( let (sprite, automation) = query.into_inner(); let image = automation.world.get_image_data(); - // images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); commands.entity(request.into_inner().1).despawn(); @@ -30,35 +28,33 @@ pub fn update_automation_view( pub fn update_automation( query: Single<(&mut SubPlateAutomation, Entity)>, - hex_query: Single<&mut HexMatrixBuild>, + mut hex_query: Single<&mut HexMatrixBuild>, mut seeded_rng: ResMut, keys: Res>, mut commands: Commands, + mut images: ResMut>, ) { - let (mut automation, _entity) = query.into_inner(); + let (mut automation, entity) = query.into_inner(); if keys.just_pressed(KeyCode::Space) || keys.all_pressed([KeyCode::Space, KeyCode::ShiftLeft]) { let random = &mut seeded_rng.0; automation.next(random); commands.spawn(ViewRedrawRequest); - } if keys.just_pressed(KeyCode::AltLeft) { let random = &mut seeded_rng.0; - for _ in 0..16 { - automation.seed(random); + for i in 1..=16 { + automation.seed(random, i * 8); } commands.spawn(ViewRedrawRequest); - } if keys.just_pressed(KeyCode::AltRight) { automation.smooth(); commands.spawn(ViewRedrawRequest); - } if keys.just_pressed(KeyCode::KeyS) { @@ -66,9 +62,130 @@ pub fn update_automation( } if keys.just_pressed(KeyCode::KeyF) { - automation.calculate_front_lines(&mut commands, hex_query, &automation); - + automation.calculate_front_lines(&mut commands, &mut hex_query, &automation); } + + if keys.just_pressed(KeyCode::Enter) { + // commands.entity(entity).despawn(); + create_collision_world(commands, &automation, &hex_query, images); + } +} + +fn create_collision_world( + mut commands: Commands, + query: &Mut, + hex_query: &Single<&mut HexMatrixBuild>, + mut images: ResMut>, +) { + println!("Switching to CollisionAutomation"); + let mut colors = query.world.data.clone(); + colors.sort(); + colors.dedup(); + colors.remove(0); + let mut territories = vec![Vec::<(usize, usize)>::new(); colors.len()]; + let mut borders = vec![Vec::::new(); colors.len()]; + for x in 0..query.world.side { + for y in 0..query.world.side { + let color = *query.world.get_dim(x, y); + if color == 0 { + continue; + } + + let index = colors.iter().position(|v| *v == color).unwrap(); + territories[index].push((x, y)); + } + } + + for x in 0..hex_query.hex_matrix.dimensions.0 { + for y in 0..hex_query.hex_matrix.dimensions.1 { + let color = *query.world.get_dim(x, y); + if color == 0 { + continue; + } + + let index = colors.iter().position(|v| *v == color).unwrap(); + let coordinates = hex_query.hex_matrix.get_offset_of(x, y); + borders[index].push(Vec2::new(coordinates.0, coordinates.1)); + } + } + let plates_data = territories + .iter() + .map(|v| { + let center = v + .iter() + .map(|(x, y)| Vec2::new(*x as f32, *y as f32)) + .collect::>() + .into_iter() + .sum::() + / v.len() as f32; + + let xs = v.iter().map(|(x, y)| *x).collect::>(); + let ys = v.iter().map(|(x, y)| *y).collect::>(); + let max_x = *xs.iter().max().unwrap(); + let max_y = *ys.iter().max().unwrap(); + let min_x = *xs.iter().min().unwrap(); + let min_y = *ys.iter().min().unwrap(); + let mut image = Image::new_fill( + Extent3d { + width: (max_x - min_x) as u32 + 1, + height: (max_y - min_y) as u32 + 1, + depth_or_array_layers: 1, + }, + TextureDimension::D2, + &[0, 0, 0, 0], + TextureFormat::Rgba8UnormSrgb, + RenderAssetUsages::default(), + ); + + let size = image.size(); + + v.into_iter().for_each(|(x, y)| { + let position = ((*x - min_x) as u32, (*y - min_y) as u32); + + image + .set_color_at(position.0, position.1, Color::WHITE) + .unwrap(); + }); + + let image_offset = Vec2::new(min_x as f32, min_y as f32); + + (v.len(), image_offset, image, Vec2::ZERO) + }) + .collect::>(); + + let mut world = CollisionWorld { bodies: vec![] }; + + let mut parts = Vec::with_capacity(plates_data.len()); + for index in 0..plates_data.len() { + let (mass, center, image, offset) = plates_data.get(index).unwrap(); + let image_handle = images.add(image.clone()); + + let view = commands + .spawn(( + Transform::from_xyz(offset.x, offset.y, 0.0), + Sprite::from_image(image_handle), + )) + .id(); + + let size = image.size(); + + let mut entity = commands.spawn((Transform::from_xyz(center.x + size.x as f32 / 2.0, -center.y - size.y as f32 / 2.0, 0.0),)); + entity.add_child(view); + let entity_id = entity.id(); + + parts.push(entity_id); + + let col_body = CollisionBody { + value: colors[index], + position: *center, + border: borders[index].clone(), + forces: vec![], + mass: *mass as f32, + }; + + world.bodies.push(col_body); + } + commands.spawn((Transform::default(), Moving)).add_children(parts.as_slice()); } #[derive(Component)] @@ -80,7 +197,6 @@ impl SubPlateAutomation { fn next(&mut self, rng: &mut ChaCha8Rng) { let time = Instant::now(); - for index in 0..self.world.side * self.world.side { let current_color = *self.world.get(index); if current_color == 0 || current_color != u8::MAX { @@ -129,7 +245,7 @@ impl SubPlateAutomation { } } - fn seed(&mut self, rng: &mut ChaCha8Rng) { + fn seed(&mut self, rng: &mut ChaCha8Rng, value: u8) { let len = (self.world.side * self.world.side) as f32; loop { let index = (rng.random::() * len) as usize; @@ -137,7 +253,7 @@ impl SubPlateAutomation { continue; } - self.world.set(index, rng.random::()); + self.world.set(index, value); break; } } @@ -145,7 +261,7 @@ impl SubPlateAutomation { fn calculate_front_lines( &self, commands: &mut Commands, - mut hex_query: Single<&mut HexMatrixBuild>, + mut hex_query: &mut Single<&mut HexMatrixBuild>, automation: &SubPlateAutomation, ) { let table = &mut hex_query.hex_matrix; @@ -161,15 +277,14 @@ impl SubPlateAutomation { for x in 0..table.dimensions.0 { for y in 0..table.dimensions.1 { let color = table.get_dim(x, y); - if *color == 0 { continue; } + if *color == 0 { + continue; + } let around = table.around(x, y); if around.iter().all(|x1| *x1 == around[0]) { table_copy.set_dim(x, y, 0); - }else { - let new_color = (color).overflowing_add(128_u8).0; - - table_copy.set_dim(x, y, new_color); - + } else { + table_copy.set_dim(x, y, *color); } } } @@ -205,28 +320,24 @@ pub fn setup_hex_matrix( mut commands: Commands, mut images: ResMut>, ) { - let entity = request_query.into_inner().1; let automation = automation_query.into_inner(); commands.entity(entity).despawn(); println!("Seed hex matrix"); - let resolution = automation.world.side / 2; + let resolution = automation.world.side / 4; - let hex_table = HexTable::new(resolution, 0, 2.0); + let hex_table = HexTable::new(resolution, 0, 4.0); let image = hex_table.get_image_data(); let sprite = view_query.into_inner(); - // images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); - commands.spawn( - HexMatrixBuild { - hex_matrix: hex_table, - }, - ); + commands.spawn(HexMatrixBuild { + hex_matrix: hex_table, + }); } pub fn update_hex_matrix_view( @@ -244,7 +355,6 @@ pub fn update_hex_matrix_view( let sprite = view_query.into_inner(); - // images.remove(sprite.image.id()); images.insert(sprite.image.id(), image).unwrap(); } #[derive(Component)]