ECS idiomatic way of compontents interaction #8141
-
Hi, I'm programmer with OOP background and I try to understand ECS better and as I understood it is functional paradigm. I wanted to create tanks game to learn bevy and now I struggle with one issue - reusability.
and system for handling player input
But something is telling me this is not correct way for ECS as I need to keep copy of transform in Tank component while in order to affect player/enemy entity I need to copy it back to entity transform. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 5 replies
-
Well, it's difficult to judge of the quality of code when there is no line returns 🙂 . here is how to format code on Github I'll update this answer after I've copy/pasted your code in my text editor and inspected it myself |
Beta Was this translation helpful? Give feedback.
-
A few things. I think you are overthinking this, I think you wrote pretty fluent bevy ECS-style code! There is a few recommendations:
fn update_player_intent(
mut player_query: Query<&mut MoveIntent, With<Player>>,
keyboard: Res<Input<KeyCode>>
) {
for mut intent in &mut player_query {
if keyboard.just_pressed() {
*intent = ;// ...
}
}
}
enum Direction { Up, Down, Left, Right }
// For a crate that does it for you, use
// https://crates.io/crates/leafwing-input-manager
#[derive(Component)]
struct MoveIntent {
direction: Direction
}
fn handle_tank_intent(
mut tank_query: Query<(&mut Transform, &mut Tank, &MoveIntent)>,
mut commands: Commands,
time: Res<Time>,
) {
for (mut transform, mut tank, intent) in &mut tank_query {
// move_to_new_position(&mut self, Transform, &MoveIntent, &Time, &mut Commands)
let new_position = tank.move_to_new_position(*transform, intent, &time, &mut commands);
transform.translation = new_position;
}
} Now the AI can have its own system (say Also note that people would prefer implementing the logic in the |
Beta Was this translation helpful? Give feedback.
-
Something I always keep in mind is: Don't put logic onto components! Create a system for it. Systems can be very generic and adapted for a variety of uses. You don't fall into an inheritance trap with them as well, since systems are composited (Composition over Inheritance!) Also, only put the most specific information into component fields, so that you can reuse the other parts (like Transform) in the ECS context. That becomes useful when you want the transform, but not the rest of the tank. You'd always need to work with the specific Tank object instead of the generic Transform. What if you want to add other objects, like trees, houses, bikes, humans and dragons and want to calculate collision? What if you want the bikes and humans to reuse the movement logic? If you don't separate common stuff out, you'd need to write logic for every specific object :) |
Beta Was this translation helpful? Give feedback.
A few things. I think you are overthinking this, I think you wrote pretty fluent bevy ECS-style code!
There is a few recommendations:
Transform
in theTank
component? The single responsibility principle would require to read & write from theTransform
component rather than copy it inTank
. In any case, whenever you need theTransform
of a tank in a system, you can always query it. And you can always pass it as argument to a method ofTank
if needed.handle_player_input
can only handle... player input! Maybe abstract the "intent" into its own component and work on that when moving the tank. For example: