use bevy::prelude::*;
use bevy_director::prelude::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, DirectorPlugin))
.add_systems(Startup, setup)
.add_systems(Update, (play_on_space, skip_on_esc))
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let ground = materials.add(StandardMaterial {
base_color: Color::srgb(0.22, 0.24, 0.28),
..Default::default()
});
commands.spawn((
Mesh3d(meshes.add(Cuboid::new(60.0, 1.0, 60.0))),
MeshMaterial3d(ground.clone()),
Transform::from_xyz(0.0, -0.5, 0.0),
));
let pillar_mesh = meshes.add(Cuboid::new(1.6, 8.0, 1.6));
for x in -3..=3 {
for z in -3..=3 {
if (x + z) % 2 == 0 {
continue;
}
let height_seed = ((x * 7 + z * 13) % 5) as f32;
commands.spawn((
Mesh3d(pillar_mesh.clone()),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::hsl(210.0 + height_seed * 20.0, 0.3, 0.5),
..Default::default()
})),
Transform::from_xyz(x as f32 * 6.0, 4.0 - height_seed * 0.5, z as f32 * 6.0),
));
}
}
commands.spawn((
Name::new("beacon"),
Mesh3d(meshes.add(Sphere::new(0.6))),
MeshMaterial3d(materials.add(StandardMaterial {
emissive: LinearRgba::rgb(2.0, 5.0, 12.0),
..Default::default()
})),
Transform::from_xyz(0.0, 6.0, 0.0),
));
commands.spawn((
DirectionalLight::default(),
Transform::from_xyz(20.0, 40.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
));
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 5.0, 26.0).looking_at(Vec3::new(0.0, 3.0, 0.0), Vec3::Y),
));
info!("space plays the take, esc skips it");
}
fn play_on_space(
keys: Res<ButtonInput<KeyCode>>,
mut assets: ResMut<Assets<SequenceAsset>>,
mut commands: Commands,
) {
if !keys.just_pressed(KeyCode::Space) {
return;
}
let take = SequenceAsset {
name: "flythrough".into(),
shots: vec![
Shot {
start: 0.0,
duration: 6.0,
blend_in: Some(Blend {
secs: 1.0,
ease: EaseFunction::SmoothStep,
}),
rig: Rig::Orbit {
center: TargetRef::Entity("beacon".into()),
radius: ScalarTrack {
keys: vec![
ScalarKey {
time: 0.0,
value: 22.0,
ease: EaseFunction::SmoothStep,
},
ScalarKey {
time: 6.0,
value: 12.0,
ease: EaseFunction::Linear,
},
],
},
yaw_deg: ScalarTrack {
keys: vec![
ScalarKey {
time: 0.0,
value: 0.0,
ease: EaseFunction::Linear,
},
ScalarKey {
time: 6.0,
value: 160.0,
ease: EaseFunction::Linear,
},
],
},
pitch_deg: ScalarTrack::constant(18.0),
},
look: Look::Free, lens: Lens::default(),
shake: None,
camera: None,
},
Shot {
start: 6.0,
duration: 6.0,
blend_in: Some(Blend {
secs: 1.2,
ease: EaseFunction::SmoothStep,
}),
rig: Rig::Rail {
points: vec![
Vec3::new(-14.0, 2.0, 14.0),
Vec3::new(-4.0, 2.5, 2.0),
Vec3::new(8.0, 3.0, -6.0),
Vec3::new(16.0, 5.0, -16.0),
],
kind: RailKind::CatmullRom,
constant_speed: true,
progress: ScalarTrack::default(),
},
look: Look::At {
target: TargetRef::Entity("beacon".into()),
damping: Some(7.0),
},
lens: Lens {
fov: FovSpec::FocalLengthMm {
track: ScalarTrack::constant(32.0),
filmback: Filmback::Super35,
},
focus: Some(FocusTrack::Target {
target: TargetRef::Entity("beacon".into()),
offset: 0.0,
}),
aperture_f_stops: Some(ScalarTrack::constant(2.0)),
vignette: Some(ScalarTrack {
keys: vec![
ScalarKey {
time: 0.0,
value: 0.15,
ease: EaseFunction::SmoothStep,
},
ScalarKey {
time: 6.0,
value: 0.7,
ease: EaseFunction::Linear,
},
],
}),
aberration: Some(ScalarTrack::constant(0.02)),
grading: Some(GradeTrack {
temperature: Some(ScalarTrack {
keys: vec![
ScalarKey {
time: 0.0,
value: 0.0,
ease: EaseFunction::SmoothStep,
},
ScalarKey {
time: 6.0,
value: 0.25,
ease: EaseFunction::Linear,
},
],
}),
saturation: Some(ScalarTrack::constant(1.15)),
..Default::default()
}),
..Default::default()
},
shake: Some(Shake {
amplitude_deg: 0.8,
frequency_hz: 8.0,
seed: 7,
pos_amplitude: 0.03,
ramp: None,
fov_amplitude_deg: None,
focus_amplitude: None,
}),
camera: None,
},
],
markers: vec![Marker {
time: 6.0,
name: "cut_to_rail".into(),
}],
texts: vec![
TextBlock::at(0.6, 3.4, "THE CANYON")
.anchor(TextAnchor::Center)
.fades(0.6, 0.8),
TextBlock::at(6.4, 4.0, "and out along the rail")
.anchor(TextAnchor::LowerThird)
.fades(0.4, 0.8),
],
actors: vec![
ActorTrack::entity("beacon")
.cue(ActorCue::at(0.0, 6.0, "beacon.pulse").fades(0.5, 0.5)),
],
blend_out: Some(Blend {
secs: 1.5,
ease: EaseFunction::SmoothStep,
}),
};
let handle = assets.add(take);
commands.play_sequence_with(
handle,
PlayOptions {
letterbox: Some(2.39),
..Default::default()
},
);
}
fn skip_on_esc(keys: Res<ButtonInput<KeyCode>>, mut commands: Commands) {
if keys.just_pressed(KeyCode::Escape) {
commands.skip_sequence();
}
}