dtcristo / bevy_pixels

Bevy plugin that uses Pixels (a tiny pixel buffer) for rendering
https://docs.rs/bevy_pixels
Apache License 2.0
85 stars 12 forks source link

Bevy 0.10 support #15

Closed beetrootpaul closed 1 year ago

beetrootpaul commented 1 year ago

I was trying to use bevy_pixels in my new Bevy 0.10 project, but it didn't work, which is totally understandable, since Bevy 0.10 was released, like, this week 🙂

I might try to create Pull Request to this repository at some point, but for now I only re-created parts of this crate in my own repo (link).

dtcristo commented 1 year ago

Hello! I'm also excited to get bevy 0.10 support up and running. I've just created a WIP PR where I've got it working. See #16.

However I still want to make some improvements to usages of system sets and schedules before releasing a new version of this crate. I also want to take this opportunity to support multiple windows now that windows are entities in bevy 0.10, this will likely change the public API in a major way.

beetrootpaul commented 1 year ago

However I still want to make some improvements to usages of system sets and schedules before releasing a new version of this crate

I ended up in a state where I wouldn't use bevy_pixels in the end, because of to which schedules do I add my systems. I mean: I want my systems run on a fixed FPS (like old games, with movement based on constant increments of time). Just in case you are planning to go into direction which would allow such solution:

I tried to create my own fixed timestep schedule within module which is my modification of bevy_pixels (to imitate how would it look like as part of a library API), but I failed. Probably it's doable, but I didn't manage to put all puzzle pieces together. So, I ended up reusing built-in Bevy's CoreSchedule::FixedUpdate and, sadly, chaining all systems together in that schedule (I failed to understand how to put any base system set to that schedule so I would be able to create a complex graph of systems there, with parallel systems instead of everything chained).

To be clear: if you do not plan to go such road nor add ability for a fixed timestamp solution in bevy_pixels, then I am totally OK with that. I am just sharing my use case and am OK with having my own implementation of pixels usage 🙂

I've just created a WIP PR where I've got it working.

I took a look and, just in case, want to hint the importance of "system sets" vs "base system sets". I made a mistake of using .in_set and ended up having my systems added to both my desired system set and CoreSet::Update, which made my app panic and run my systems in a wrong place of the whole game loop. Then I learnt about necessity to use "base system sets" (but still don't "feel" the topic). For more info please see this forum thread on Bevy Discord: https://discord.com/channels/691052431525675048/1083571454404214885/1083571454404214885

dtcristo commented 1 year ago

I would like bevy_pixels to support all use cases of pixels within bevy, thus I want to support your usage of fixed update game logic. I imagine bevy_pixels should be constantly rendering the pixel buffer to the window at display frame rate (eg. 60 fps) but maybe only if it detects changes since the previous frame. Game logic would be independent and can run on it's own schedule not necessarily linked to display frame rate where the pixel buffer is being updated from. If this is not possible or desirable, perhaps users of bevy_pixels can be given the ability to tweak the schedule somehow.

I still need to read more on the changes in bevy 0.10 to understand all the possibilities.

Thanks for your advice and tips.

dtcristo commented 1 year ago

Hi @beetrootpaul, I've just released 0.9 with support for Bevy 0.10.

I've taken the opportunity to make big changes to the API. I've replaced PixelsResource with a PixelsWrapper component that lives on the window entity. I've also done some reading around system sets and I think I understand how they work. You're correct about the base sets. I've created PixelsSet with three variants configured like this to map to the following base sets.

configure_sets((
    PixelsSet::Update.in_base_set(CoreSet::Update),
    PixelsSet::Draw.in_base_set(CoreSet::PostUpdate),
    PixelsSet::Render.in_base_set(CoreSet::Last),
))

The idea is simulation logic would occur in PixelsSet::Update while the buffer is written to in PixelsSet::Draw. However if using CoreSchedule::FixedUpdate systems for your logic, I imagine it would still work fine. I've not tried it myself though. Keen to see how you go.

beetrootpaul commented 1 year ago

@dtcristo thx for letting me know! 👍

The idea is simulation logic would occur in PixelsSet::Update while the buffer is written to in PixelsSet::Draw. However if using CoreSchedule::FixedUpdate systems for your logic, I imagine it would still work fine.

I think I would need to add both my drawing (buffer write) and rendering to FixedUpdate as well in order to maintain a fixed FPS look&feel of e.g. 30 FPS 🤔

Or, maybe it won't be visible so much in practice and having draw and render in the regular CoreSet? I don't know.

I wonder if it would be possible to have a bevy_pixels plugin defined in a way, that once can:

Maybe I will try to do such in my own custom implementation, just for exploratory reasons (in my next repo I intentionally split game into "base" and "game" packages, hoping to force on myself kind of engine vs game separation, with a single direction dependency, with pixels support in "base" and systems being added to its sets in "game")

Keen to see how you go.

This is how I did it in my most recent PoC: https://github.com/beetrootpaul/poc--bevy-pixels-web-game/blob/11111f5a4fe99243492838b20f25be9012a0f93a/src/game/mod.rs#L119-L173

My sets are defined as follows:

app.edit_schedule(CoreSchedule::FixedUpdate, |schedule| {
    schedule.configure_sets(
        (FixedFpsSpawning, FixedFpsUpdate, FixedFpsDraw, FixedFpsLast).chain(),
    );
    // …
});

This is one of reasons I probably cannot just plug-in bevy_pixels, since I am using all those fixed timestamp system sets.


BTW I probably have one more reason to rely on my custom implementation for now (but haven't checked how would it be with your version yet: I have some window-resize reacting logic which let's my game react to it by changing where in-game controls are positioned (pixels buffer has to adapt to either landscape or portrait layout). Here I support it in what is customization of your previous bevy_pixels implementation: https://github.com/beetrootpaul/poc--bevy-pixels-web-game/blob/a3b6a698698276ca8b60ee436f4f12b7347bd160/src/pixel_canvas/plugin.rs#L66-L171 (PixelCanvas is kind of your PixelWrapper I think).

Especially, I expose values calculated from:

Then, later on, I use those values in order to calculate touch position in in-game coordinates: https://github.com/beetrootpaul/poc--bevy-pixels-web-game/blob/24b41c887aff70812379aa716e442792f3af9ca8/src/pixel_canvas/mod.rs#L32-L45

(sorry for a lot of type::try_from(value).unwrap() noise in my code. I wrote it before I learnt that value as type would work perfectly fine for me)

beetrootpaul commented 1 year ago

UPDATE: apparently, in terms of canvas portrait/landscape layout change I was able to use your crate 🙂 (here is my commit where I do it: https://github.com/beetrootpaul/hen-rescue-hero/commit/4a4d205efc01fd0e587dd50bd39958fe4e99ee05 )

I was able to do it mostly thanks to your public exposure of PixelsOptions and auto_resize_* flags. I set them to false and re-implemented window resize handling on my own 👍


So, the only last thing that I miss is to be able to put everything into a fixed timestamp systems sets. But maybe I will ditch my intention to do fixed FPS and just do updates on floating point, then drawing based on values rounded to integers 🤔 😄 Will see what I managed to do on my side 🙂