From 1d22c11cde12798dbbda9ec80e9999831786bffd Mon Sep 17 00:00:00 2001 From: tuxmain Date: Thu, 25 Aug 2022 19:55:34 +0200 Subject: [PATCH] Levels stored outside program --- Cargo.lock | 14 ++++ Cargo.toml | 2 + assets/game.levels.json | 119 ++++++++++++++++++++++++++ src/levels.rs | 180 ++++++++++++++++++++++++++++++---------- src/levels/game_over.rs | 61 -------------- src/levels/level0.rs | 50 ----------- src/levels/level1.rs | 58 ------------- src/levels/level2.rs | 72 ---------------- src/levels/level3.rs | 59 ------------- src/main.rs | 12 +-- 10 files changed, 280 insertions(+), 347 deletions(-) create mode 100644 assets/game.levels.json delete mode 100644 src/levels/game_over.rs delete mode 100644 src/levels/level0.rs delete mode 100644 src/levels/level1.rs delete mode 100644 src/levels/level2.rs delete mode 100644 src/levels/level3.rs diff --git a/Cargo.lock b/Cargo.lock index 3ddac41..f26df36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -316,6 +316,18 @@ dependencies = [ "rodio", ] +[[package]] +name = "bevy_common_assets" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f7be9ee39085d8319d5cd853447b0b5c4f8b4bfd647aec91e2bd996e9db67ef" +dependencies = [ + "anyhow", + "bevy", + "serde", + "serde_json", +] + [[package]] name = "bevy_core" version = "0.8.1" @@ -898,6 +910,7 @@ version = "0.1.0" dependencies = [ "bevy", "bevy-inspector-egui", + "bevy_common_assets", "bevy_rapier2d", "cpal 0.14.0", "crossbeam-channel", @@ -905,6 +918,7 @@ dependencies = [ "rand", "rand_distr", "rapier2d", + "serde", "ticktock", ] diff --git a/Cargo.toml b/Cargo.toml index f50dc6f..df12e56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,12 +7,14 @@ edition = "2021" [dependencies] bevy = "0.8.1" +bevy_common_assets = { version = "0.3.0", features = ["json"] } bevy-inspector-egui = "0.12.1" bevy_rapier2d = "0.16.2" crossbeam-channel = "0.5.6" rand = "0.8.5" rand_distr = "0.4.3" rapier2d = "0.14.0" +serde = { version = "1.0.144", features = ["derive"] } [target."cfg(not(target_arch = \"wasm32\"))".dependencies] cpal = "0.14.0" diff --git a/assets/game.levels.json b/assets/game.levels.json new file mode 100644 index 0000000..549c17b --- /dev/null +++ b/assets/game.levels.json @@ -0,0 +1,119 @@ +{ + "levels": [ + { + "comment": "Movement tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]} + ], + "characters": [ + {"pos": [0, -192], "color": [1,0,0,1]}, + {"pos": [-128, -192], "color": [0,1,0,1]}, + {"pos": [128, -192], "color": [0,0,1,1]} + ], + "absorbing_filters": [], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Combine the colors to synthetize a white light.\nUse arrows to move." + } + ] + }, + { + "comment": "Switch tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]}, + {"pos": [128, 256], "size": [96, 16]} + ], + "characters": [ + {"pos": [0, -192], "color": [0,1,0,1]}, + {"pos": [-128, -192], "color": [1,0,0,1]}, + {"pos": [128, 320], "color": [0,0,1,1]} + ], + "absorbing_filters": [], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Press Tab to switch." + } + ] + }, + { + "comment": "Absorbing filter tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]}, + {"pos": [0, -128], "size": [800, 16]} + ], + "characters": [ + {"pos": [-128, -192], "color": [1,0.64,0,1]}, + {"pos": [128, -192], "color": [0,0.37,1,1]} + ], + "absorbing_filters": [ + { + "pos": [0, -192], + "size": [16, 112], + "color": [1,0,0,1] + } + ], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Press R to reset." + } + ] + }, + { + "comment": "Rotating filter tutorial", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]} + ], + "characters": [ + {"pos": [0, -192], "color": [1,0,0,1]}, + {"pos": [-128, -192], "color": [1,0,0,1]}, + {"pos": [128, -192], "color": [1,0,0,1]} + ], + "absorbing_filters": [], + "rotating_filters": [ + { + "pos": [0, -64], + "angle": 45 + } + ], + "texts": [ + { + "pos": [0, 0], + "font_size": 32, + "text": "Let's rotate the hue!" + } + ] + }, + { + "comment": "Game over", + "platforms": [ + {"pos": [0, -256], "size": [800, 16]} + ], + "characters": [ + {"pos": [0, -64], "color": [1,0,0,1]} + ], + "absorbing_filters": [], + "rotating_filters": [], + "texts": [ + { + "pos": [0, 128], + "font_size": 48, + "text": "Thank you for playing!" + }, + { + "pos": [0, 0], + "font_size": 32, + "text": "There is no more light to combine." + } + ] + } + ] +} \ No newline at end of file diff --git a/src/levels.rs b/src/levels.rs index ad217e1..c131e63 100644 --- a/src/levels.rs +++ b/src/levels.rs @@ -1,14 +1,9 @@ #![allow(clippy::too_many_arguments)] -mod game_over; -mod level0; -mod level1; -mod level2; -mod level3; - use crate::game::*; -use bevy::prelude::*; +use bevy::{prelude::*, reflect::TypeUuid}; +use serde::{Deserialize, Serialize}; pub fn setup_level( level_startup_event: &mut EventWriter, @@ -35,51 +30,152 @@ pub fn post_setup_level( mut level_startup_event: EventReader, asset_server: Res, audio: Res>, + stored_levels_assets: Res>, + stored_levels_handle: Res>, ) { for _ in level_startup_event.iter() { if let Some(level_id) = current_level.0 { - match level_id.0 { - 0 => level0::setup( + if let Some(stored_level) = stored_levels_assets + .get(&stored_levels_handle) + .unwrap() + .levels + .get(level_id.0 as usize) + { + spawn_stored_level( &mut commands, - &mut meshes, &character_meshes, - &mut materials, - &audio, - &asset_server, - ), - 1 => level1::setup( - &mut commands, &mut meshes, - &character_meshes, &mut materials, - &audio, &asset_server, - ), - 2 => level2::setup( - &mut commands, - &mut meshes, - &character_meshes, - &mut materials, &audio, - &asset_server, - ), - 3 => level3::setup( - &mut commands, - &mut meshes, - &character_meshes, - &mut materials, - &audio, - &asset_server, - ), - _ => game_over::setup( - &mut commands, - &mut meshes, - &character_meshes, - &mut materials, - &audio, - &asset_server, - ), + stored_level, + ); } } } } + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "1fbba930-644b-0d62-2514-4b302b945327"] +pub struct StoredLevels { + levels: Vec, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "a1464a30-1f57-a654-d56c-ded41032af0b"] +pub struct StoredLevel { + pub comment: String, + pub characters: Vec, + pub platforms: Vec, + pub absorbing_filters: Vec, + pub rotating_filters: Vec, + pub texts: Vec, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "1c798f8c-ef15-c528-693e-76becdef6b10"] +pub struct StoredCharacter { + pub pos: Vec2, + pub color: Vec4, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "31696095-59de-93be-b5e9-333c2afbc900"] +pub struct StoredPlatform { + pub pos: Vec2, + pub size: Vec2, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "bcad7fff-0605-c4e3-3cd4-42d5bbaad926"] +pub struct StoredAbsorbingFilter { + pub pos: Vec2, + pub size: Vec2, + pub color: Vec4, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "fa2843f2-6e34-601b-6c46-4827b0370b3f"] +pub struct StoredRotatingFilter { + pub pos: Vec2, + pub angle: f32, +} + +#[derive(Deserialize, Serialize, TypeUuid)] +#[uuid = "72f6321a-f01f-6eea-9b17-3159837a2fd3"] +pub struct StoredText { + pub pos: Vec2, + pub font_size: f32, + pub text: String, +} + +pub fn spawn_stored_level( + commands: &mut Commands, + character_meshes: &Res, + meshes: &mut ResMut>, + materials: &mut ResMut>, + asset_server: &Res, + audio: &Res>, + + stored_level: &StoredLevel, +) { + let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); + spawn_platforms( + commands, + meshes, + materials, + stored_level.platforms.iter().map(|platform| { + ( + Transform::from_xyz(platform.pos.x, platform.pos.y, 0.), + platform.size, + ) + }), + ); + spawn_characters( + commands, + character_meshes, + materials, + audio, + stored_level.characters.iter().map(|character| { + ( + Transform::from_xyz(character.pos.x, character.pos.y, 0.), + character.color.into(), + ) + }), + ); + for absorbing_filter in stored_level.absorbing_filters.iter() { + spawn_absorbing_filter( + commands, + meshes, + materials, + Transform::from_xyz(absorbing_filter.pos.x, absorbing_filter.pos.y, 2.), + absorbing_filter.size, + absorbing_filter.color.into(), + ); + } + for rotating_filter in stored_level.rotating_filters.iter() { + spawn_rotating_filter( + commands, + asset_server, + Transform::from_xyz(rotating_filter.pos.x, rotating_filter.pos.y, 2.), + rotating_filter.angle, + ); + } + for text in stored_level.texts.iter() { + commands + .spawn_bundle(Text2dBundle { + text: Text::from_section( + &text.text, + TextStyle { + font: font.clone(), + font_size: text.font_size, + color: Color::WHITE, + }, + ) + .with_alignment(TextAlignment::CENTER), + transform: Transform::from_xyz(text.pos.x, text.pos.y, 0.), + ..Default::default() + }) + .insert(Level); + } +} diff --git a/src/levels/game_over.rs b/src/levels/game_over.rs deleted file mode 100644 index d513383..0000000 --- a/src/levels/game_over.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::game::*; - -use bevy::prelude::*; - -pub fn setup( - commands: &mut Commands, - meshes: &mut ResMut>, - character_meshes: &Res, - materials: &mut ResMut>, - audio: &Res>, - asset_server: &Res, -) { - let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); - commands - .spawn_bundle(Text2dBundle { - text: Text::from_section( - "Thank you for playing!", - TextStyle { - font: font.clone(), - font_size: 48.0, - color: Color::WHITE, - }, - ) - .with_alignment(TextAlignment::CENTER), - transform: Transform::from_xyz(0., 128.0, 0.), - ..Default::default() - }) - .insert(Level); - commands - .spawn_bundle(Text2dBundle { - text: Text::from_section( - "There is no more light to combine.", - TextStyle { - font, - font_size: 32.0, - color: Color::WHITE, - }, - ) - .with_alignment(TextAlignment::CENTER), - ..Default::default() - }) - .insert(Level); - - spawn_platform( - commands, - meshes, - materials, - Transform::from_xyz(0.0, -256.0, 0.0), - Vec2 { x: 800.0, y: 16.0 }, - ); - - spawn_character( - commands, - character_meshes, - materials, - audio, - Transform::from_xyz(0., -64., 0.), - Color::RED, - true, - ); -} diff --git a/src/levels/level0.rs b/src/levels/level0.rs deleted file mode 100644 index d6789d8..0000000 --- a/src/levels/level0.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Movement tutorial - -use crate::game::*; - -use bevy::prelude::*; - -pub fn setup( - commands: &mut Commands, - meshes: &mut ResMut>, - character_meshes: &Res, - materials: &mut ResMut>, - audio: &Res>, - asset_server: &Res, -) { - let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); - commands - .spawn_bundle(Text2dBundle { - text: Text::from_section( - "Combine the colors to synthetize a white light.\nUse arrows to move.", - TextStyle { - font, - font_size: 32.0, - color: Color::WHITE, - }, - ) - .with_alignment(TextAlignment::CENTER), - ..Default::default() - }) - .insert(Level); - - spawn_platform( - commands, - meshes, - materials, - Transform::from_xyz(0.0, -256.0, 0.0), - Vec2 { x: 800.0, y: 16.0 }, - ); - - spawn_characters( - commands, - character_meshes, - materials, - audio, - [ - (Transform::from_xyz(0., -192., 0.), Color::RED), - (Transform::from_xyz(-128., -192., 0.), Color::GREEN), - (Transform::from_xyz(128., -192., 0.), Color::BLUE), - ], - ); -} diff --git a/src/levels/level1.rs b/src/levels/level1.rs deleted file mode 100644 index 1d92187..0000000 --- a/src/levels/level1.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Switch tutorial - -use crate::game::*; - -use bevy::prelude::*; - -pub fn setup( - commands: &mut Commands, - meshes: &mut ResMut>, - character_meshes: &Res, - materials: &mut ResMut>, - audio: &Res>, - asset_server: &Res, -) { - let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); - commands - .spawn_bundle(Text2dBundle { - text: Text::from_section( - "Press Tab to switch.", - TextStyle { - font, - font_size: 32.0, - color: Color::WHITE, - }, - ) - .with_alignment(TextAlignment::CENTER), - ..Default::default() - }) - .insert(Level); - - spawn_platforms( - commands, - meshes, - materials, - [ - ( - Transform::from_xyz(0.0, -256.0, 0.0), - Vec2 { x: 800.0, y: 16.0 }, - ), - ( - Transform::from_xyz(128.0, 256.0, 0.0), - Vec2 { x: 96.0, y: 16.0 }, - ), - ], - ); - - spawn_characters( - commands, - character_meshes, - materials, - audio, - [ - (Transform::from_xyz(0., -192., 0.), Color::GREEN), - (Transform::from_xyz(-128., -192., 0.), Color::RED), - (Transform::from_xyz(128., 320., 0.), Color::BLUE), - ], - ); -} diff --git a/src/levels/level2.rs b/src/levels/level2.rs deleted file mode 100644 index 91606d5..0000000 --- a/src/levels/level2.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Absorbing filter tutorial - -use crate::game::*; - -use bevy::prelude::*; - -pub fn setup( - commands: &mut Commands, - meshes: &mut ResMut>, - character_meshes: &Res, - materials: &mut ResMut>, - audio: &Res>, - asset_server: &Res, -) { - let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); - commands - .spawn_bundle(Text2dBundle { - text: Text::from_section( - "Press R to reset.", - TextStyle { - font, - font_size: 32.0, - color: Color::WHITE, - }, - ) - .with_alignment(TextAlignment::CENTER), - ..Default::default() - }) - .insert(Level); - - spawn_platforms( - commands, - meshes, - materials, - [ - ( - Transform::from_xyz(0.0, -256.0, 0.0), - Vec2 { x: 800.0, y: 16.0 }, - ), - ( - Transform::from_xyz(0.0, -128.0, 0.0), - Vec2 { x: 800.0, y: 16.0 }, - ), - ], - ); - - spawn_characters( - commands, - character_meshes, - materials, - audio, - [ - ( - Transform::from_xyz(-128., -192., 0.), - Color::rgba(1., 0.64, 0., 1.), - ), - ( - Transform::from_xyz(128., -192., 0.), - Color::rgba(0., 0.37, 1., 1.), - ), - ], - ); - - spawn_absorbing_filter( - commands, - meshes, - materials, - Transform::from_xyz(0., -192., 2.), - Vec2 { x: 16.0, y: 112.0 }, - Color::RED, - ); -} diff --git a/src/levels/level3.rs b/src/levels/level3.rs deleted file mode 100644 index 5fa2607..0000000 --- a/src/levels/level3.rs +++ /dev/null @@ -1,59 +0,0 @@ -// Rotating filter tutorial - -use crate::game::*; - -use bevy::prelude::*; - -pub fn setup( - commands: &mut Commands, - meshes: &mut ResMut>, - character_meshes: &Res, - materials: &mut ResMut>, - audio: &Res>, - asset_server: &Res, -) { - let font = asset_server.get_handle("UacariLegacy-Thin.ttf"); - commands - .spawn_bundle(Text2dBundle { - text: Text::from_section( - "Let's rotate the hue!", - TextStyle { - font, - font_size: 32.0, - color: Color::WHITE, - }, - ) - .with_alignment(TextAlignment::CENTER), - ..Default::default() - }) - .insert(Level); - - spawn_platforms( - commands, - meshes, - materials, - [( - Transform::from_xyz(0.0, -256.0, 0.0), - Vec2 { x: 800.0, y: 16.0 }, - )], - ); - - spawn_characters( - commands, - character_meshes, - materials, - audio, - [ - (Transform::from_xyz(0., -192., 0.), Color::RED), - (Transform::from_xyz(-128., -192., 0.), Color::RED), - (Transform::from_xyz(128., -192., 0.), Color::RED), - ], - ); - - spawn_rotating_filter( - commands, - asset_server, - Transform::from_xyz(0., -64., 2.), - 45., - ); -} diff --git a/src/main.rs b/src/main.rs index 6cb80d7..410492a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use bevy::{ prelude::*, window::{WindowId, WindowMode}, }; +use bevy_common_assets::json::JsonAssetPlugin; use bevy_rapier2d::prelude::*; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -42,6 +43,9 @@ fn main() { .insert_resource(game::FirstLevel(first_level)) .insert_resource(ClearColor(Color::BLACK)) .add_plugins(DefaultPlugins) + .add_plugin(JsonAssetPlugin::::new(&[ + "levels.json", + ])) .add_plugin(RapierPhysicsPlugin::::pixels_per_meter(64.0)) //.add_plugin(RapierDebugRenderPlugin::default()) .add_plugin(menu::MenuPlugin) @@ -59,11 +63,9 @@ fn setup(mut commands: Commands, mut windows: ResMut, asset_server: Res .unwrap() .set_title(String::from("Bevyjam")); - let font: Handle = asset_server.load("UacariLegacy-Thin.ttf"); - commands.insert_resource(font); - - let bevy_icon: Handle = asset_server.load("bevy.png"); - commands.insert_resource(bevy_icon); + commands.insert_resource(asset_server.load::("game.levels.json")); + commands.insert_resource(asset_server.load::("UacariLegacy-Thin.ttf")); + commands.insert_resource(asset_server.load::("bevy.png")); commands.spawn_bundle(Camera2dBundle::default()); commands.insert_resource(AmbientLight {