Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A way to run the "update" stage potentially many times per render? #3600

Closed
rodya-mirov opened this issue Jan 9, 2022 · 8 comments
Closed
Labels
A-ECS Entities, components, systems, and events C-Examples An addition or correction to our examples C-Usability A simple quality-of-life change that makes Bevy easier to use

Comments

@rodya-mirov
Copy link

What problem does this solve or what need does it fill?

I'm writing a game which is turn-based, with one player and (potentially many) NPC "players." In terms of control flow, think Civilization (but simpler), so a player's turn actions may impact what the next player does. But, in Civ, an NPC civilization will often take a full second to take their turn; while in my game a turn will usually take much less than a millisecond. So I'd like to be able to process as many as possible per tick and give control back to the player as quickly as possible so they experience smooth gameplay in the "normal" case.

What solution would you like?

The most obvious solution is to somehow run a stage (or system set) "as many times as possible" in the tick, then just render whatever's there. There may be better solutions; I'm open to ideas.

What alternative(s) have you considered?

Nothing great.

Most obviously I tried a proper turn-based system -- the entity whose turn it is can take an action (or not), then a bunch of followup systems run, then it passes control to the next person at the end. I don't see a way to make that not be the entire update stage, so this is the whole stage, and so if you have (e.g.) 1 player and 59 NPCs then the player can take exactly 1 action per second, which doesn't feel great. At 500 NPCs it would be completely unplayable, so it starts to inform game design in a bad way.

I've also tried writing the code in a way that handles everybody's turn in one tick, but when I have NPCs in a loop, the nice separation of concerns ECS provides go out the window -- I really need [NPC 1]'s actions to be fully resolved before NPC 2 even considers their choices. So I can't launch an event "NPC 1 chooses this" and have a bunch of followup systems run afterward, before "NPC 2 chooses this" occurs.

I've also tried just not caring about where (e.g.) NPC 1's actions may invalidate NPC 2's actions, but this is starting to drive my game design ("oh, this is going to make bugs, let's do something else") in a way that I don't like.

Additional context

Nothing obvious comes to mind

@rodya-mirov rodya-mirov added C-Enhancement A new feature S-Needs-Triage This issue needs to be labelled labels Jan 9, 2022
@alice-i-cecile alice-i-cecile added S-Needs-Design-Doc This issue or PR is particularly complex, and needs an approved design doc before it can be merged A-ECS Entities, components, systems, and events C-Usability A simple quality-of-life change that makes Bevy easier to use and removed S-Needs-Triage This issue needs to be labelled S-Needs-Design-Doc This issue or PR is particularly complex, and needs an approved design doc before it can be merged labels Jan 9, 2022
@alice-i-cecile
Copy link
Member

So, the best way to do this right now is to make an exclusive system that runs a schedule in a tight loop. Add your game logic systems to this schedule, rather than the schedule owned by the App. After each pass of the loop, check if the elapsed time has exceeded your time budget, and break back into the App's schedule if it has.

This will do exactly what you need, and is actually quite ergonomic and powerful!

The fact that you can do this is not at all obvious however, nor is it properly documented in an example. IMO we should have a game example that does this, but I'm struggling to think of a simple game where this pattern would fit well.

@alice-i-cecile alice-i-cecile added C-Examples An addition or correction to our examples and removed C-Enhancement A new feature labels Jan 9, 2022
@rodya-mirov
Copy link
Author

@alice-i-cecile Thanks! If I can get it working I can try and contribute a small example back to the repo. I think this is useful even without a "real, well-motivated" example, because for people like me, the examples are the only useful documentation of most of bevy's actual API.

@alice-i-cecile
Copy link
Member

That would be very much appreciated! I was thinking about this last night, and realized that this pattern may be useful for predictive AI. Perhaps a tic-tac-toe game example?

@mockersf
Copy link
Member

mockersf commented Jan 9, 2022

if you don't want to go all the way to having your own schedule, you could also use run criteria, as they allow you to rerun systems inside the same frame. This is used for example in fixed time step to rerun systems in the same frame if the time step is smaller than the frame duration.

You can see it in action in the fixed_timestep.rs example by setting it to a small time step (less than 0.016 on 60 fps)

@alice-i-cecile
Copy link
Member

Yep, looping run criteria will also do the trick. They won't play nice with other run criteria (like states) though, and are likely to get cut as part of #2801 due to their sharp corners and excessive complexity :)

@rodya-mirov
Copy link
Author

I think an exclusive system is probably what I want. I've already had to hack bevy more than I'd like to force all the systems to run in a consistent sequence (single threaded, apparently, is not enough) and manually clear events at the end of the tick so they're not processed twice. Clearly what I want is not what bevy is designed for but I think I've got the tools I need to make it work (still love the engine).

Which is to say, at this point I'd rather just assume direct control than try to solve my problems with configuration.

@rodya-mirov
Copy link
Author

I'm going to close this issue out since the question had a solid answer. I'm not sure I feel qualified to contribute a good example but I'll think about it.

Thanks for all your help, and your work on this engine!

@alice-i-cecile
Copy link
Member

Sounds good :) We should be getting a solid example in for this as part of the bevyengine/rfcs#45 work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Examples An addition or correction to our examples C-Usability A simple quality-of-life change that makes Bevy easier to use
Projects
None yet
Development

No branches or pull requests

3 participants