diff --git a/assets/world.txt b/assets/world.txt index b4b7a73..7929770 100644 --- a/assets/world.txt +++ b/assets/world.txt @@ -1,3 +1,15 @@ info section - + block-size = 60 + .P = [player] + .T = Blockgrau.png + .E = erdblock.png + .G = _grasblock.png world section + +TT +TTT P +TTTTTTTTTEEEGGGGGGGGGEGGGGGGEGGGE +TTTTTTTTTTEEEEEEEEEEEEEEEEEEEEEEE +TTTTTTTEEEEEEEEEEEEEEEEEEEEEEEEEE +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE diff --git a/src/game.rs b/src/game.rs index 2960436..2ef6a37 100644 --- a/src/game.rs +++ b/src/game.rs @@ -9,6 +9,8 @@ mod player; mod scene; mod set; +pub const WORLD_DEPTH: f32 = 0.5; + pub fn game_plugin(app: &mut App) { app.add_plugins((player_plugin, scene_plugin)); } diff --git a/src/game/scene.rs b/src/game/scene.rs index c61802b..f436ab7 100644 --- a/src/game/scene.rs +++ b/src/game/scene.rs @@ -1,32 +1,106 @@ +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::*; -use readformat::readf; +use bevy_rapier2d::prelude::{Collider, *}; +use readformat::{readf, readf1}; +use crate::game::WORLD_DEPTH; use crate::AppState; +#[derive(Component)] +struct Block; + 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)] pub struct WorldInfo { block_size: f32, + blocks: Vec<(String, String)>, } -pub(super) fn import_text_world(mut commands: Commands, assets: Res) { +pub(super) fn import_text_world( + mut commands: Commands, + assets: Res, + mut meshes: ResMut>, + mut materials: ResMut>, +) { let world_string = fs::read_to_string("assets/world.txt").expect("need a world to load"); let [info_string, world_string] = &readf("info section\n{}\nworld section\n{}", &world_string) .expect("world does not have sections")[..] else { - panic!("world does not have sections"); + unreachable!() }; + let mut wi = WorldInfo::default(); for line in info_string.lines() { - readf("{} = {}", &line); + 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(), + 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 x = i as f32 * wi.block_size; + let y = current_y as f32 * wi.block_size; + let mut command = commands.spawn(( + Block, + MaterialMesh2dBundle { + mesh: meshes + .add(Rectangle::new(wi.block_size * len as f32, wi.block_size)) + .into(), + material: materials.add(assets.load(tex)), + transform: Transform::from_xyz(x, y, WORLD_DEPTH), + ..Default::default() + }, + )); + if collider { + command.insert(( + RigidBody::Fixed, + Collider::cuboid(wi.block_size / 2.0 * len as f32, wi.block_size / 2.0), + Velocity::default(), + )); + } + println!("spawned {possible_block:?} at {x}, {y}"); + + i += len; + continue 'a; + } + } + panic!("unknown block in at {i},{current_y}"); + } } }