Git Product home page Git Product logo

bevy-yoleck's People

Contributors

idanarye avatar kywinston avatar naomijub avatar striezel avatar timjentzsch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

bevy-yoleck's Issues

Give edit systems access to the level index

Most straightforward way - make it a resource.

The idea is to allow levels to refer other levels. For example - a door entity can have a field with the name of another level that door leads to.

Allow user to click on the level where they want to place a new entity instead of just placing it at the origin

Currently, when adding a new entity in the editor, all the YoleckComponents are initialized to their default value. For the position component, this usually means the origin. This can get a bit cumbersome:

  1. You can't put anything at the level origin, because then when you add new entities they'll appear in the same place.
  2. If you edit the level too far away from the origin, you have to scroll to the origin every time you want to add something.

It could be nice if instead of just spawning the thing at the origin, the user would click in the world space where they want to place the new entity.

Note that because there is no position in Yoleck's core (it's part of Vpeol), this will have to be user-customizable. On the plus size this could mean that the same mechanism can be used for other initializations.

Add a Vpeol mode for editing the level structure

Instead of editing the level order in egui and saving it in a level index, I want to make the level index a regular level file where each entity is another level, and the components define the order. The editing will be done by dragging and dropping.

This will also allow non-linear level structure, where the levels map can be a graph instead of a list.

Entity type definition files

Registering entity types via code can be tedious. Users would prefer to use some UI to define them - something like bevy_editor_pls, or an external editor (like Blender) that can add metadata to the scene which Bevy can translate into components.

Yoleck needs to be able to read such files and convert them to YoleckEntityTypes at runtime. That way the user can create entity types with the UI and then place them in the level with Yoleck. Ideally, without even restarting the editor instance.

Yoleck itself should not add that external UI as a dependency. Instead, it should provide the mechanism for importing files (of unknown type!) and then some eternal crate - let's call it for now "bevy-yoleck-pls" - will add the support for specific file types. bevy-yoleck-pls should also allow switching between Yoleck and bevy_editor_pls while editing.

Note that components will still need to be defined (and registered!) by code. Can't escape that.

Also note that Yoleck will need metadata to determine two things:

  1. Which YoleckComponent should the entity type have? These are treated different from regular components. Luckily, it's easy enough to set a default (usually it'd just be Vpeol2dPosition/Vpeol3dPosition) and Yoleck itself could provide the UI for editing the YoleckComponents.
  2. Should the generated entity be the scene itself or some top level object in the scene? We can use the scene itself as default though (a top level object can't be a default because how do you determine which object?)

Since all that metadata has good defaults, it should not be an issue to have Yoleck list a directory and automatically import all the entity definition files from there, and just have some UI to configure them afterwards.

Entities that refer to other entities

Some entities need to refer to other entities. For example - a key that opens a specific door. We need a way to represent this and to provide UI for editing this.

Entity relations

Allow Yoleck managed entities refer other Yoleck managed entities.

Bevy-egui has been updated

Migration guide states that

YoleckUi is now a non-Send resource, which means it can no longer be accessed as a regular Res/ResMut. It must now be accessed as NonSend/NonSendMut.

Hopefully once emilk/egui#3148 is fixed (and gets in to bevy_egui) this can be changed back.

This has been fixed. I tried to update to bevy_egui 0.22 and move yoleckui to res/resmut. However, I got stuck in the fact that egui::Ui doesn't implement Default or bevy::ecs::FromWorld, can you give me any light to help with this change?

I tried to switch to egui::context, but it did not expose the Ui as a consumable.

Hope you are safe

Exclusive input mode for edit systems

Example usecase - #21. When an entity refers to another entity, we want the first entity to click the second entity, we want to be able to do this by editing the target entity, doing something to indicate that we want to pick an entity to refer to, and then click on the other entity.

For this, we need to be able to send an edit system to an "exclusive input mode". In that mode:

  • Other edit systems don't run.
  • Yoleck ignores directives.
    • Actually, there is one directive it won't ignore - a directive for cancelling the exclusive mode.
    • Vpeol should send that directive when Escape is pressed.
  • The exclusive edit system handles the clicks (how? should it get the directives themselves?)

Saving and loading game state

The common conception about saving and loading game state in Bevy (or ECS in general) is that you just have to do serialize all the components of all the entities into a file, and when loading just rebuild the scene from that component data. That, however, is very similar to the common conception about editors for Bevy - the very conception that Yoleck is trying to be an alternative to. So I figure Yoleck can offer a similar alternative to. Since Yoleck already has a concise representation of the level, one that does not have to store every single component because it can build them from YoleckEntityTypes and YoleckComponents, it shouldn't be that much more work to save just the changed data.

Advantages over entire-scene save:

  1. Smaller files - has less data so save.
  2. Saves have a much better chance to survive changes to the levels and the game code. Of course, this is not something that can be guaranteed, and I'll need to come up with guidelines to which changes break the saves and which doesn't.
  3. During playtests in the editor, we will be able to save the state, modify the level, and then resume it from the same state.

Yoleck itself is not going to handle the storage medium for the saved files. Doing that will lock users to a specific persistence solution. Instead, when initiating a save Yoleck will send an event with a serde_json::Value that represents the state, and when loading the user will have to provide that serde_json::Value. Note that serde_json::Value is not an actual JSON - it's just an in-memory data type with JSON semantics. It can be stored as a more compact and less human-readable format.

Gui not visible unless bevy_egui is explicitly added to Cargo.toml

As the title says. It could be some problem with the way my project is structured (maybe a conflicting crate?) but I just wanted to put it out there in case anyone is having the same issue. For me, explicitly adding 'bevy_egui = "0.26.0"' to the Cargo.toml fixes the issue.

Spawning Yoleck entities during gameplay

In order to save entities (#23) they need to be Yoleck entities, which currently means they have to be created from the .yol file. But what if we want to save entities created at runtime? For example - in a strategy game the player will build structures, and we want to save these structures even though they are not in the .yol file.

To support this, we need to be able to generate Yoleck entities during gameplay.

Create functionality to allow editors to spawn new objects

In my game project, I have fences that can be a custom length, and you often want pairs of them. Therefore, I added an yoleck editor button that spawns a clone of that object. This required me to fork yoleck and make a couple fields public, and they reasonably should not be public, since there seems to be some invariants to uphold. My suggestion then is to add functionality to allow the editor to spawn editor objects with an arbitrary payload, since this can be useful for all kinds of use cases.

I'll show you how I did this in my project, with some extra context code. You're free to integrate any of the code I paste in this issue into yoleck, but ask if there's something from the rest of my repo (https://github.com/ZeeQyu/sylt) you want to use.


This is the only change I had to do in yoleck (and I'm hoping this won't be required if you move the function inside since it'd be bad if a user starts editing this without maintaining the invariants).

diff --git a/src/lib.rs b/src/lib.rs
index ea0a503..92d7d96 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -315,8 +315,8 @@ impl YoleckTypeHandlers {
 /// Fields of the Yoleck editor.
 #[derive(Resource)]
 pub struct YoleckState {
-    entity_being_edited: Option<Entity>,
-    level_needs_saving: bool,
+    pub entity_being_edited: Option<Entity>,
+    pub level_needs_saving: bool,
 }
 
 impl YoleckState {

And in my code:

pub fn create_editor_object(commands: &mut Commands, writer: &mut EventWriter<YoleckEditorEvent>, yoleck: &mut ResMut<YoleckState>, type_name: &str, value: serde_json::Value) {
    let cmd = commands.spawn(YoleckRawEntry {
        header: YoleckEntryHeader {
            type_name: String::from(type_name),
            name: String::from(""),
        },
        data: value,
    });
    writer.send(YoleckEditorEvent::EntitySelected(cmd.id()));
    yoleck.entity_being_edited = Some(cmd.id());
    yoleck.level_needs_saving = true;
}

#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize)]
struct EditorFence {
    #[serde(default)]
    position: Vec2,
    #[serde(default)]
    orientation: FenceOrientation,
    #[serde(default)]
    section_length: f32,
}

#[derive(Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum FenceOrientation {
    #[default]
    Horizontal,
    Vertical,
}
fn edit_fence(
    mut edit: YoleckEdit<EditorFence>,
    configuration: Res<Configuration>,
    mut commands: Commands,
    mut writer: EventWriter<YoleckEditorEvent>,
    mut yoleck: ResMut<YoleckState>,
) {
    edit.edit(|ctx, data, ui| {
        if ui.add(egui::Button::new("Spawn copy")).clicked() {
            let offset_axis = match data.orientation {
                FenceOrientation::Horizontal => -Vec2::Y,
                FenceOrientation::Vertical => Vec2::X,
            };
            let value = serde_json::to_value(EditorFence { position: data.position + offset_axis * 20.0, ..data.clone() }).unwrap();
            create_editor_object(&mut commands, &mut writer, &mut yoleck, FENCE_NAME, value);
        }
// --snip--
    });
}

I have no clue how to solve this elegantly, without requiring users to add EventWriter and ResMut to their systems, so I'm hoping you find a better way!

Workaround the assets race

There is a bug with Bevy's assets loader (bevyengine/bevy#9337) That gets triggered when Yoleck:

  • Changes a level
  • Reloads a level (basically changing a level to itself)
  • Starts a playtest
  • Restarts a playtest
  • Finishes a playtest

In all these cases, Yoleck replaces all the entities under its control and creates new ones, but the new ones will only start loading their assets on the next frame, when the Yoleck components are registered and the populate systems run.

This will probably get fixed in Bevy 0.12 with Bevy Asset V2, but until then I'd like Yoleck to have a workaround.

Comment: This is so unbelievable sick

This is EXACTLY what i have been looking for - for so long! Im so excited to see this. Im interested to see forks and additions that add things like click-and-drag wall creation, ground textures, and more. Very exciting.

Getting index handle seems broken

Currently, if you load the level index like shown in the docs.rs example, it seems as though the level_index_assets.get method breaks.
Loading this plugin panics with "Failed to load level" when in the Loading state

// SYSTEMS
pub fn load_level(
    level_index_assets: Res<Assets<YoleckLevelIndex>>, 
    asset_server: Res<AssetServer>,
    mut yoleck_loading_cmd: ResMut<YoleckLoadingCommand>,
    current_level: Res<CurrentLevel>,
    mut state: ResMut<NextState<GameState>>,
) {
    if let Some(level) = current_level.0 {
        bevy::log::debug!("LOADING LEVEL: {level}");
        let level_index_handle: Handle<YoleckLevelIndex> = asset_server.load("levels/index.yoli");
        let Some(level_index) = level_index_assets.get(&level_index_handle) else { panic!("Failed to load level") };

        let level_handle: Handle<YoleckRawLevel> = asset_server.load(
            format!("levels/{}", level_index[level].filename)
        );
        *yoleck_loading_cmd = YoleckLoadingCommand::FromAsset(level_handle);
        state.set(GameState::InGame);
    }
}

// PLUGIN
pub struct Plugin;

impl bevy::app::Plugin for Plugin {
    fn build(&self, app: &mut App) {
        app
            .insert_resource(CurrentLevel(Some(1)))
            .add_systems(OnEnter(GameState::Loading), load_level);
    }
}

Levels as entities

Currently Yoleck levels are loaded with a resource - YoleckLoadingCommand. It would be better if instead a level would be entities, and we could load/unload the level by placing components on them (or maybe just sending events?). The benefits would be:

  1. Being able to load multiple levels at the same time. This is good for:
    • Level transition.
    • Having long lived entities (like the player?) in their own level.
    • Level layers.
  2. We can place other components on the level entities as a solution for #2.
  3. If we have a meta-level containing the levels as Yoleck entities, we could use that meta-level as a solution for #4.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.