Closed idanarye closed 1 year ago
The idea - just like we have edit systems and populate systems, we should also have initialize systems for initializing entities.
Initialize systems are similar to edit systems: they use YoleckEdit
to edit the new entity and potentially YoleckUi
to use egui, and they are stored in a vector that maintains a deterministic order.
Unlike edit systems, only one initialize system is active at any given time. This allows the initialize system to take control over the entire input. The initialize system must return a value - probably an enum, but maybe an Option
will work better because it'd allow easily exit with ?
instead of the usual let
...else
(then again, maybe it's better to force a let
...else
for conformity?). Once the initialize system returns a value that indicates it is done, the next initialize system will be active. Once all the initialize systems finish, the editor/entity goes back to edit mode and once again runs edit systems.
Something like this:
fn vpeol_2d_initialize_position(
mut edit: YoleckEdit<&mut Vpeol2dPosition>,
mut cameras_query: Query<&VpeolCameraState>,
buttons: Res<Input<MouseButton>>,
) -> Option<YoleckInitialize> {
let mut position = edit.get_single_mut().ok()?;
// I think `cursor_ray` is `None` if the cursor is inside the egui window, but if it isn't I
// should probably make it so it does. That would mean clicking inside the egui window should
// not be considered as clicking to set the position.
let cursor_position = camera_state
.iter()
.find_map(|camera_state| camera_state.cursor_ray)?;
position.0 = cursor_position.origin.truncate();
if buttons.just_released(MouseButton::Left) {
Some(YoleckInitialize::Done)
} else {
None
}
}
Note that there are still default values - we just immediately start to edit them.
Not sure if the next initialize system should start in the exact same frame. I worry that buttons.just_released
will also be true in the next initialize system if I do that, but if each initialize system has its own frame it'll cause a delay when some of them are skipped.
Maybe a good heuristic is that if an initialize system returns None
on the first frame it runs, the next one can run in the same frame.
Actually, maybe returning an Option
is not a good idea? In the example I've naturally written I used None
both for "no editable entity with a position" and for "the button was not just released", but one of them would mean "just skip this system" while the other would mean "keep running this system".
I should probably just use an explicit enum
with all three directives (keep running this, continue to the next, abort)
Actually, do I need abort? Maybe abort should be done externally (e.g. - always done when the user hits Escape
) instead of controlled by these systems?
Currently, when adding a new entity in the editor, all the
YoleckComponent
s are initialized to their default value. For the position component, this usually means the origin. This can get a bit cumbersome: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.