#Tips for converting non-ecs code to ecs

8 messages · Page 1 of 1 (latest)

tall pewter
#

Hi, I want to make an RTS/top-down style of player controller where the camera is focusing in on the centre of the screen. In other engines like Unity or Godot the way I would do this would be to have an empty object and then make the camera a child object/node of that empty that looks at the empty with a offset relative to the parent node. That way I can have the player input move the empty and the camera automatically follows the empty and will look at it no matter where the empty moves or what rotation the empty is currently facing.
I've had a look through the bevy cheatbook and I have seen the parenting section, but I won't lie it went a bit over my head how that works and I don't really know what to start with. Would appreciate any tips on this kind of behaviour

lusty crescent
#

If you're manipulating the camera transform independently and just need somewhere in space to point your camera at you could try spawning an entity with either the SpatialBundle or TransformBundle or you could just update the Transform component on your camera itself since the Camera3dBundle comes with a Transform component.

#

You might not need an entity hierarchy (for example if you're manipulating the camera entity's transform directly) but you if want to add other siblings then yea you can just create an entity with a SpatialBundle (or TransformBundle if you only need transforms and not visibility options) and then use .with_children() to add whatever else you need under it: https://bevy-cheatbook.github.io/fundamentals/hierarchy.html?highlight=with_children#hierarchical-parentchild-entities

tall pewter
#

So the problem I have is that I don't want to manipulate the camera's transform direction because rotating it would rotate the camera (obvious I know). I want it rotate around a central object. So if it's 10 units away from the central object and I rotate the central object 180 degrees then the camera hasn't just rotated with it, but it's now also 20 units away from it's starting position. Rotation the camera manually would rotate it on the spot

lusty crescent
#

I don't know if there's an easy way to essentially "opt-out" of transform propagation for child entities, especially to opt-out of only rotation propagation while keeping translation. It might be better to keep the camera independent and provide it a "look_at" target and do offsets manually, but that would also require writing manual functions to rotate around target (like with https://docs.rs/bevy/latest/bevy/prelude/struct.Transform.html#method.rotate_around).

tall pewter
#
#[derive(Component, Default)]
pub struct PlayerControllerTag;


#[derive(Bundle, Default)]
pub struct PlayerController {
    pub player_controller_tag: PlayerControllerTag,
    pub transform: TransformBundle,
}

pub fn player_input(
    keys: Res<Input<KeyCode>>,
    time: Res<Time>,
    mut player: Query<(&PlayerControllerTag, &mut Transform)>,
) {
    for (_, mut transform) in player.iter_mut() {
        if keys.pressed(KeyCode::Q) {
            transform.rotate_y(-f32::to_radians(50.0 * time.delta_seconds()))
        }
        if keys.pressed(KeyCode::E) {
            transform.rotate_y(f32::to_radians(50.0 * time.delta_seconds()))
        }
        if keys.pressed(KeyCode::W) {
            let dir = transform.local_z();
            transform.translation -= dir * 10.0 * time.delta_seconds();
        }
        if keys.pressed(KeyCode::S) {
            let dir = transform.local_z();
            transform.translation += dir * 10.0 * time.delta_seconds();
        }
        if keys.pressed(KeyCode::A) {
            let dir = transform.local_x();
            transform.translation -= dir * 10.0 * time.delta_seconds();
        }
        if keys.pressed(KeyCode::D) {
            let dir = transform.local_x();
            transform.translation += dir * 10.0 * time.delta_seconds();
        }
    }
}

pub fn setup_camera(
    mut commands: Commands,
) {
    commands.spawn(PlayerController::default()).with_children(
        | player_controller | {
            player_controller.spawn(Camera3dBundle {
                transform: Transform::from_xyz(0.0, 12.0, 16.0).looking_at(Vec3::ZERO, Vec3::Y),
                ..default()
            });
        });
}```
#

This is what I ended up with