use std::collections::HashMap; use std::fs; use bevy::sprite::MaterialMesh2dBundle; use bevy::{core_pipeline::smaa::SmaaSpecializedRenderPipelines, prelude::*}; use bevy::{prelude::*, scene::ScenePlugin}; // use bevy_editor_pls::EditorPlugin; use bevy_rapier2d::prelude::{Collider, *}; use readformat::{readf, readf1}; use crate::game::WORLD_DEPTH; use crate::parallax::{parallax, Parallax}; use crate::AppState; use super::player::PlayerSpawnOneshot; use super::{PLAYER_DEPTH, PLAYER_SIZE_FRACTION}; #[derive(Component)] struct Block; #[derive(Resource, Default, Clone, Copy)] pub struct PlayerCoords { pub x: f32, pub y: f32, pub block_size: f32, } impl PlayerCoords { pub fn get_collider(&self) -> Collider { let size = 0.5; Collider::round_cuboid(size, size, 2.0) // Collider::cuboid(size, size) } } impl From for Transform { fn from(val: PlayerCoords) -> Self { let PlayerCoords { x, y, block_size } = val; Transform { translation: Vec3 { x, y, z: PLAYER_DEPTH, }, scale: Vec3::splat(val.block_size * PLAYER_SIZE_FRACTION), ..Default::default() } } } pub(super) fn scene_plugin(app: &mut App) { // app.add_plugins(EditorPlugin::default()); // app.add_systems(, ) app.add_systems(Startup, (import_text_world,)); } #[derive(Default, Resource)] pub struct WorldInfo { pub block_size: f32, pub blocks: Vec<(String, String)>, pub spawnpoints: Vec<(usize, usize)>, } pub(super) fn import_text_world( mut commands: Commands, assets: Res, mut meshes: ResMut>, mut materials: ResMut>, mut player_spawn_oneshot: Res, ) { let world_string = fs::read_to_string("assets/world.txt").expect("need a world to load"); let [info_string, links_string, world_string] = &readf("header\n{}\nlinks\n{}\nblocks\n{}", &world_string) .expect("world does not have sections")[..] else { unreachable!() }; let mut wi = WorldInfo::default(); let mut parallax_info = Parallax::default(); for line in info_string.lines() { let [name, val] = &readf(" {} = {}", line).expect("invalid line in info section")[..] else { unreachable!() }; match name.as_str() { "block-size" => wi.block_size = val.parse().unwrap(), "parallax.offset" => parallax_info.offset = val.parse().unwrap(), "parallax.size" => { parallax_info.size = { let x = readf("{}x{}", val).unwrap(); Vec2::new(x[0].parse().unwrap(), x[1].parse().unwrap()) } } "parallax.tiles" => parallax_info.tiles = val.parse().unwrap(), "parallax.tex" => parallax_info.tex = val.clone(), "parallax.factor" => parallax_info.factor = val.parse().unwrap(), "parallax.factor.y" => parallax_info.y_factor = val.parse().unwrap(), "parallax.depth" => parallax_info.depth = val.parse().unwrap(), "parallax.enable" => { if val == "true" { parallax( &mut commands, &mut materials, &mut meshes, &assets, parallax_info.clone(), ) } } x if x.starts_with(".") => { let x = readf1(".{}", x).unwrap(); wi.blocks.push((x, val.to_owned())); } x => panic!("invalid setting {x}"), } } for (current_y, line) in world_string.lines().rev().enumerate() { let mut i = 0; // try to match every defined block 'a: while i < line.len() { if line[i..].starts_with(" ") { i += 1; continue; } for possible_block in wi.blocks.iter() { if line[i..].starts_with(possible_block.0.as_str()) { let len = possible_block.0.len(); let (tex, collider) = if let Some(s) = possible_block.1.strip_prefix("_") { (s.to_owned(), false) } else { (possible_block.1.to_owned(), true) }; let (tex, fixed) = if let Some(s) = tex.strip_prefix("~") { (s.to_owned(), false) } else { (tex, true) }; let x = i as f32 * wi.block_size; let y = current_y as f32 * wi.block_size; if tex == "[player]" { commands.insert_resource(PlayerCoords { x, y, block_size: wi.block_size, }); commands.run_system(player_spawn_oneshot.0); } else if tex == "[spawn]" { wi.spawnpoints.push((i, current_y)); } else { spawn_block( &mut commands, &mut meshes, &mut materials, &assets, tex, (x, y, len, wi.block_size), (collider, fixed), ); } println!("spawned {possible_block:?} at {x}, {y}"); i += len; continue 'a; } } panic!("unknown block in at {i},{current_y}"); } } wi.spawnpoints.sort_by(|a, b| a.0.cmp(&b.0)); println!("{:?}", wi.spawnpoints); commands.insert_resource(wi); } fn spawn_block( commands: &mut Commands, meshes: &mut ResMut>, materials: &mut ResMut>, assets: &Res, tex: String, (x, y, len, block_size): (f32, f32, usize, f32), (collider, fixed): (bool, bool), ) { let mut command = commands.spawn(( Block, MaterialMesh2dBundle { mesh: meshes .add(Rectangle::new(block_size * len as f32, block_size)) .into(), material: materials.add(assets.load(tex)), transform: Transform::from_xyz( x + block_size * ((len as f32 - 1.) / 2.), y, if fixed { WORLD_DEPTH } else { WORLD_DEPTH - 0.01 }, ), ..Default::default() }, )); if collider { command.insert(( if fixed { RigidBody::Fixed } else { RigidBody::Dynamic }, if fixed { Collider::cuboid(block_size / 2. * len as f32, block_size / 2.1) } else { Collider::ball(block_size / 2.) }, AdditionalMassProperties::Mass(1.0), Velocity::default(), )); } }