Skip to content

Commit

Permalink
Rework tilemap and tileset loading, add EnemyConfig asset
Browse files Browse the repository at this point in the history
  • Loading branch information
lunacys committed Aug 23, 2024
1 parent 6f3c3c1 commit f6409a5
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 79 deletions.
2 changes: 1 addition & 1 deletion vs-assets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ tiled = "0.12"
thiserror = "1.0"
serde_json = "1.0"
serde = "1.0"
rand = "0.8.5"
rand = "0.8.5"
69 changes: 69 additions & 0 deletions vs-assets/src/enemies.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use bevy::{
asset::{io::Reader, Asset, AssetLoader, AsyncReadExt, LoadContext},
prelude::*,
reflect::TypePath,
};
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct SpawnWave {
pub from: u16,
pub to: u16,
pub spawn_time: u64,
}

#[derive(Debug, Asset, TypePath, Clone, Serialize, Deserialize)]
pub struct EnemyConfig {
pub param_list: Vec<EnemyParams>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnemyParams {
pub name: String,
pub dmg: i64,
pub hp: i64,
pub max_velocity: f32,
pub max_force: f32,
pub mass: f32,
pub asset_path: String,
pub is_elite: Option<bool>,
pub spawn_waves: Vec<SpawnWave>,
}

#[derive(Default)]
pub struct EnemyConfigLoader;

#[non_exhaustive]
#[derive(Debug, Error)]
pub enum EnemyConfigLoaderError {
#[error("Could not load config: {0}")]
Io(#[from] std::io::Error),
#[error("Could not parse JSON: {0}")]
JsonError(#[from] serde_json::Error),
}

impl AssetLoader for EnemyConfigLoader {
type Asset = EnemyConfig;
type Settings = ();
type Error = EnemyConfigLoaderError;

async fn load<'a>(
&'a self,
reader: &'a mut Reader<'_>,
_settings: &'a Self::Settings,
_load_context: &'a mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut json_str = String::new();

reader.read_to_string(&mut json_str).await?;

let obj = serde_json::from_str::<Vec<EnemyParams>>(&json_str)?;

Ok(EnemyConfig { param_list: obj })
}

fn extensions(&self) -> &[&str] {
&["json"]
}
}
3 changes: 2 additions & 1 deletion vs-assets/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod enemies;
pub mod plugin;
pub mod prefabs;
pub mod prelude;
pub mod rooms;
pub mod tilesheets;
pub mod prelude;
28 changes: 26 additions & 2 deletions vs-assets/src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use bevy::{asset::LoadedFolder, prelude::*};

use crate::{
enemies::EnemyConfig,
prelude::TsxTilesetAsset,
rooms::{MapAsset, RoomStore},
tilesheets::AssetTileSheet,
};
Expand All @@ -19,6 +21,7 @@ impl Plugin for GameAssetsPlugin {
fn build(&self, app: &mut App) {
app.init_state::<AssetLoadingState>();
app.insert_resource(RoomStore::default());
app.insert_resource(Configs::default());
app.add_systems(OnEnter(AssetLoadingState::LoadAssets), (start_loading,));
app.add_systems(
Update,
Expand All @@ -39,10 +42,16 @@ pub struct GameAssets {
pub capybara_elite_texture: Handle<Image>,
}

#[derive(Default, Resource)]
pub struct Configs {
pub enemy_config: Handle<EnemyConfig>,
}

#[derive(Default, Resource)]
pub struct GameAssetFolders {
pub tiles_folder: Handle<LoadedFolder>,
pub rooms_folder: Handle<LoadedFolder>,
pub tileset_main: Handle<TsxTilesetAsset>,
pub tiles_loaded: bool,
pub rooms_loaded: bool,
}
Expand Down Expand Up @@ -71,14 +80,22 @@ fn check_asset_folders(
}
}

fn start_loading(mut commands: Commands, asset_server: Res<AssetServer>) {
fn start_loading(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut configs: ResMut<Configs>,
) {
info!("Loading game asset folders");
let tiles_folder_handle = asset_server.load_folder("textures");
let rooms_folder_handle = asset_server.load_folder("rooms");
let tileset_main = asset_server.load("tilesheet.tsx");

configs.enemy_config = asset_server.load("configs/enemies.json");

let asset_folders = GameAssetFolders {
tiles_folder: tiles_folder_handle,
rooms_folder: rooms_folder_handle,
tileset_main,
..default()
};

Expand All @@ -94,6 +111,8 @@ fn setup_game_assets(
mut layouts: ResMut<Assets<TextureAtlasLayout>>,
rooms: Res<Assets<MapAsset>>,
mut room_store: ResMut<RoomStore>,
tilesets: Res<Assets<TsxTilesetAsset>>,
folders: Res<GameAssetFolders>,
) {
info!("Setting up game assets");

Expand All @@ -106,7 +125,12 @@ fn setup_game_assets(

let player_tilesheet = load_player(&asset_server, &mut layouts);

let tilesheet_main = AssetTileSheet::load_by_name("tilesheet", &asset_server, &mut layouts);
let tileset = tilesets.get(folders.tileset_main.id()).unwrap();
let tilesheet_main = AssetTileSheet::create_layout(
&tileset.tileset,
tileset.image_handle.as_ref().unwrap().clone_weak(),
&mut layouts,
);

let game_assets = GameAssets {
player_tilesheet,
Expand Down
23 changes: 19 additions & 4 deletions vs-assets/src/rooms.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use bevy::{
asset::{io::Reader, Asset, AssetLoader, LoadContext},
log::info,
prelude::*,
reflect::TypePath,
utils::HashMap,
Expand Down Expand Up @@ -184,9 +183,6 @@ impl AssetLoader for MapAssetLoader {
) -> Result<Self::Asset, Self::Error> {
let mut loader = tiled::Loader::new();

let path = format!("assets/{}", load_context.path().to_str().unwrap());
info!("Loading map: {:?}", path);

let map_id_str = load_context
.path()
.parent()
Expand All @@ -207,7 +203,26 @@ impl AssetLoader for MapAssetLoader {
.expect("Invalid room path (unable to convert to str)")
.to_string();

let cmd = std::env::var("CARGO_MANIFEST_DIR");

let assets_dir = std::path::Path::new("assets");
let path = match cmd {
Ok(dir) => std::path::Path::new(&dir)
.join(assets_dir)
.join(load_context.path()),
Err(_) => {
let cur_exe = std::env::current_exe().unwrap();
cur_exe
.as_path()
.parent()
.unwrap()
.join(assets_dir)
.join(load_context.path())
}
};

let map = loader.load_tmx_map(path)?;

Ok(MapAsset { name, map_id, map })
}

Expand Down
65 changes: 40 additions & 25 deletions vs-assets/src/tilesheets.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bevy::{asset::AssetLoader, prelude::*, sprite::TextureAtlasLayout, utils::HashMap};
use rand::{thread_rng, Rng};
use thiserror::Error;
use tiled::Tileset;

#[derive(Debug, Default, Clone, Asset, TypePath)]
pub struct AssetTileSheet {
Expand Down Expand Up @@ -41,18 +42,11 @@ impl AssetTileSheet {
None
}

pub fn load_by_name(
name: &str,
asset_server: &AssetServer,
pub fn create_layout(
tilesheet: &Tileset,
tilesheet_texture: Handle<Image>,
layouts: &mut Assets<TextureAtlasLayout>,
) -> Self {
info!("Loading tilesheet '{}.tsx'", name);

let mut loader = tiled::Loader::new();
let tilesheet = loader
.load_tsx_tileset(format!("assets/{}.tsx", name))
.unwrap_or_else(|_| panic!("could not read file '{}'.tsx", name));

// Setting up named tiles (tiles with non-empty type described in the tile sheet)
let mut named_tiles: HashMap<String, Vec<u32>> = HashMap::new();

Expand All @@ -66,14 +60,7 @@ impl AssetTileSheet {
}
}

//dbg!(&named_tiles);

let img = tilesheet.image.expect("Image must not be empty");

// tilesheet name and texture name must match, and we're not just taking img.source
// because tsx loader fucks up the path from being 'assets/textures/a.png'
// to 'assets/assets/textures/a.png'
let texture_handle = asset_server.load(format!("textures/{}.png", name));
let img = tilesheet.image.as_ref().expect("Image must not be empty");

let layout = TextureAtlasLayout::from_grid(
UVec2::new(tilesheet.tile_width, tilesheet.tile_height),
Expand All @@ -84,10 +71,10 @@ impl AssetTileSheet {
);
let layout_handle = layouts.add(layout);

AssetTileSheet {
name: name.to_string(),
Self {
name: tilesheet.name.clone(),
layout: layout_handle,
image: texture_handle,
image: tilesheet_texture,
named_tiles: Some(named_tiles),
}
}
Expand All @@ -96,6 +83,7 @@ impl AssetTileSheet {
#[derive(Asset, TypePath, Debug)]
pub struct TsxTilesetAsset {
pub tileset: tiled::Tileset,
pub image_handle: Option<Handle<Image>>,
}
#[derive(Default)]
pub struct TsxTilesetAssetLoader;
Expand All @@ -105,7 +93,7 @@ pub struct TsxTilesetAssetLoader;
pub enum TsxTilesetAssetLoaderError {
#[error("Could not load asset: {0}")]
Io(#[from] std::io::Error),
#[error("Could not load TMX map: {0}")]
#[error("Could not load TSX tileset: {0}")]
TmxError(#[from] tiled::Error),
}

Expand All @@ -121,11 +109,38 @@ impl AssetLoader for TsxTilesetAssetLoader {
load_context: &'a mut bevy::asset::LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut loader = tiled::Loader::new();
let path = format!("assets/{}", load_context.path().to_str().unwrap());
info!("Loading tileset: {:?}", path);

let cmd = std::env::var("CARGO_MANIFEST_DIR");
let assets_dir = std::path::Path::new("assets");
let path = match cmd {
Ok(dir) => std::path::Path::new(&dir)
.join(assets_dir)
.join(load_context.path()),
Err(_) => {
let cur_exe = std::env::current_exe().unwrap();
cur_exe
.as_path()
.parent()
.unwrap()
.join(assets_dir)
.join(load_context.path())
}
};

info!("Loading tileset: {:?}", path);
let tileset = loader.load_tsx_tileset(path)?;
Ok(TsxTilesetAsset { tileset })

let image_handle = if let Some(img) = &tileset.image {
let tileset_texture = load_context.load::<Image>(img.source.clone());
Some(tileset_texture)
} else {
None
};

Ok(TsxTilesetAsset {
tileset,
image_handle,
})
}

fn extensions(&self) -> &[&str] {
Expand Down
File renamed without changes.
Loading

0 comments on commit f6409a5

Please sign in to comment.