disable/
disable.rs

1use std::io;
2
3use bevy::app::AppExit;
4use bevy::diagnostic::FrameTimeDiagnosticsPlugin;
5use bevy::input::keyboard::KeyboardInput;
6use bevy::input::ButtonState;
7use bevy::prelude::*;
8use bevy::utils::error;
9use bevy_ratatui::event::KeyEvent;
10use bevy_ratatui::terminal::RatatuiContext;
11use bevy_ratatui::RatatuiPlugins;
12use bevy_ratatui_render::{RatatuiRenderContext, RatatuiRenderPlugin};
13use crossterm::event::{KeyCode, KeyEventKind, KeyEventState, KeyModifiers};
14
15// Uncomment these imports, `ScheduleRunnerPlugin`, and remove `.disable()` from
16// `RatatuiRenderPlugin` in order to return to terminal rendering mode.
17// use bevy::app::ScheduleRunnerPlugin;
18// use std::time::Duration;
19fn main() {
20    App::new()
21        .add_plugins((
22            DefaultPlugins,
23            // ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(1. / 60.)),
24            FrameTimeDiagnosticsPlugin,
25            RatatuiPlugins::default(),
26            RatatuiRenderPlugin::new("main", (256, 256)).disable(),
27        ))
28        .insert_resource(ClearColor(Color::BLACK))
29        .add_systems(Startup, setup_camera_system)
30        .add_systems(Startup, setup_scene_system)
31        .add_systems(Update, draw_scene_system.map(error))
32        .add_systems(
33            Update,
34            passthrough_keyboard_events_system.before(handle_input_system),
35        )
36        .add_systems(Update, handle_input_system)
37        .run();
38}
39
40// Use `unwrap_or_default` so the camera falls back to a normal window target.
41fn setup_camera_system(mut commands: Commands, ratatui_render: Res<RatatuiRenderContext>) {
42    commands.spawn((
43        Camera3d::default(),
44        Camera {
45            target: ratatui_render.target("main").unwrap_or_default(),
46            ..default()
47        },
48        Transform::from_xyz(3., 3., 3.).looking_at(Vec3::ZERO, Vec3::Z),
49    ));
50}
51
52// Wrap `frame.render_widget` in an if-let for when `widget(id)` returns `None`.
53fn draw_scene_system(
54    mut ratatui: ResMut<RatatuiContext>,
55    rat_render: Res<RatatuiRenderContext>,
56) -> io::Result<()> {
57    ratatui.draw(|frame| {
58        if let Some(widget) = rat_render.widget("main") {
59            frame.render_widget(widget, frame.area());
60        }
61    })?;
62
63    Ok(())
64}
65
66// Listen for normal bevy input and send equivalent terminal events to get picked up by your systems.
67fn passthrough_keyboard_events_system(
68    mut read_keyboard: EventReader<KeyboardInput>,
69    mut write_crossterm: EventWriter<KeyEvent>,
70) {
71    for ev in read_keyboard.read() {
72        write_crossterm.send(KeyEvent(crossterm::event::KeyEvent {
73            code: match ev.key_code {
74                bevy::prelude::KeyCode::ArrowLeft => KeyCode::Left,
75                bevy::prelude::KeyCode::ArrowRight => KeyCode::Right,
76                bevy::prelude::KeyCode::KeyQ => KeyCode::Char('q'),
77                _ => KeyCode::Null,
78            },
79            kind: match ev.state {
80                ButtonState::Pressed => KeyEventKind::Press,
81                ButtonState::Released => KeyEventKind::Release,
82            },
83            state: KeyEventState::NONE,
84            modifiers: KeyModifiers::NONE,
85        }));
86    }
87}
88
89#[derive(Component)]
90pub struct Cube;
91
92fn setup_scene_system(
93    mut commands: Commands,
94    mut meshes: ResMut<Assets<Mesh>>,
95    mut materials: ResMut<Assets<StandardMaterial>>,
96) {
97    commands.spawn((
98        Cube,
99        Mesh3d(meshes.add(Cuboid::default())),
100        MeshMaterial3d(materials.add(StandardMaterial {
101            base_color: Color::srgb(0.4, 0.54, 0.7),
102            ..default()
103        })),
104    ));
105    commands.spawn((
106        PointLight {
107            shadows_enabled: true,
108            ..Default::default()
109        },
110        Transform::from_xyz(3., 4., 6.),
111    ));
112}
113
114pub fn handle_input_system(
115    mut rat_events: EventReader<KeyEvent>,
116    mut cube: Query<&mut Transform, With<Cube>>,
117    mut exit: EventWriter<AppExit>,
118    time: Res<Time>,
119) {
120    for key_event in rat_events.read() {
121        match key_event.kind {
122            KeyEventKind::Press | KeyEventKind::Repeat => match key_event.code {
123                KeyCode::Char('q') => {
124                    exit.send_default();
125                }
126                KeyCode::Left => {
127                    cube.single_mut().rotate_z(-10. * time.delta_secs());
128                }
129                KeyCode::Right => {
130                    cube.single_mut().rotate_z(10. * time.delta_secs());
131                }
132                _ => {}
133            },
134            _ => {}
135        }
136    }
137}