use nightshade_api::prelude::*;
struct Demo {
cube: Entity,
crate_body: Entity,
button: Entity,
hud: Entity,
}
fn main() {
run(setup, update).unwrap();
}
fn entity_of(reply: &CommandReply) -> Entity {
match reply {
CommandReply::Entity(entity) => *entity,
other => panic!("expected an entity reply, got {other:?}"),
}
}
fn setup(world: &mut World) -> Demo {
submit_commands(
world,
&[
Command::SetTitle {
title: "command tour".to_string(),
},
Command::SetTimeOfDay { hour: 10.0 },
Command::SetBackground {
background: Background::Space,
},
Command::ShowGrid { enabled: false },
Command::SetAmbient {
color: [0.1, 0.1, 0.13, 1.0],
},
Command::SetBloom { enabled: true },
Command::SetBloomIntensity { intensity: 0.1 },
Command::SetSsao { enabled: true },
Command::SetSsr { enabled: false },
Command::SetSsgi { enabled: false },
Command::SetTaa { enabled: true },
Command::SetExposure { exposure: 1.0 },
Command::SetColorGrading {
saturation: 1.05,
contrast: 1.0,
brightness: 0.0,
},
Command::SetSun {
color: [1.0, 0.95, 0.85],
intensity: 3.0,
},
Command::PointLight {
position: [0.0, 5.0, 0.0],
color: [1.0, 0.8, 0.6],
intensity: 4.0,
},
Command::SpotLight {
position: [-6.0, 8.0, 6.0],
target: [0.0, 0.0, 0.0],
color: [0.6, 0.8, 1.0],
intensity: 6.0,
},
],
);
let floor = entity_of(&submit_command(
world,
&Command::SpawnFloor { half_extent: 16.0 },
));
submit_commands(
world,
&[
Command::SetTexture {
entity: Ref::Entity(floor),
texture: "checkerboard".to_string(),
},
Command::SetTextureTiling {
entity: Ref::Entity(floor),
repeats: 3.0,
},
],
);
let cube = entity_of(&submit_command(
world,
&Command::SpawnCube {
position: [-3.0, 0.6, 0.0],
},
));
submit_commands(
world,
&[
Command::SetColor {
entity: Ref::Entity(cube),
color: TEAL,
},
Command::SetMetallicRoughness {
entity: Ref::Entity(cube),
metallic: 0.8,
roughness: 0.3,
},
Command::SetNormalTexture {
entity: Ref::Entity(cube),
texture: "checkerboard".to_string(),
},
Command::SetMetallicRoughnessTexture {
entity: Ref::Entity(cube),
texture: "checkerboard".to_string(),
},
Command::SetEmissiveTexture {
entity: Ref::Entity(cube),
texture: "checkerboard".to_string(),
},
Command::SetOcclusionTexture {
entity: Ref::Entity(cube),
texture: "checkerboard".to_string(),
},
Command::Tag {
entity: Ref::Entity(cube),
label: "demo".to_string(),
},
],
);
let sphere = entity_of(&submit_command(
world,
&Command::SpawnSphere {
position: [0.0, 0.6, 0.0],
},
));
submit_command(
world,
&Command::SetEmissive {
entity: Ref::Entity(sphere),
color: [1.0, 0.5, 0.1],
strength: 2.0,
},
);
let cone = entity_of(&submit_command(
world,
&Command::SpawnCone {
position: [5.0, 0.6, 0.0],
},
));
submit_command(
world,
&Command::SetRotation {
entity: Ref::Entity(cone),
axis: [0.0, 0.0, 1.0],
radians: 0.4,
},
);
submit_command(
world,
&Command::SpawnCylinder {
position: [3.0, 0.8, 0.0],
},
);
submit_command(
world,
&Command::SpawnTorus {
position: [-5.0, 0.8, 0.0],
},
);
submit_command(
world,
&Command::SpawnPlane {
position: [0.0, 0.02, 6.0],
},
);
let built = submit_commands(
world,
&[
Command::SpawnGroup {
position: [0.0, 3.0, 0.0],
},
Command::SpawnCube {
position: [1.2, 0.0, 0.0],
},
Command::SetColor {
entity: Ref::Result(1),
color: GREEN,
},
Command::SetScale {
entity: Ref::Result(1),
scale: [0.4, 0.4, 0.4],
},
Command::SetParent {
child: Ref::Result(1),
parent: Some(Ref::Result(0)),
},
],
);
let group = entity_of(&built[0]);
submit_command(
world,
&Command::SetPosition {
entity: Ref::Entity(group),
position: [0.0, 3.0, 0.0],
},
);
let fox = entity_of(&submit_command(
world,
&Command::SpawnModel {
glb: include_bytes!("../../../assets/gltf/fox.glb").to_vec(),
position: [0.0, 0.0, -6.0],
},
));
submit_commands(
world,
&[
Command::SetScale {
entity: Ref::Entity(fox),
scale: [0.02, 0.02, 0.02],
},
Command::PlayAnimationNamed {
entity: Ref::Entity(fox),
name: "Survey".to_string(),
},
Command::AnimationClips {
entity: Ref::Entity(fox),
},
Command::SetAnimationLooping {
entity: Ref::Entity(fox),
looping: true,
},
Command::SetAnimationSpeed {
entity: Ref::Entity(fox),
speed: 1.0,
},
Command::BlendToAnimation {
entity: Ref::Entity(fox),
clip: 1,
seconds: 0.3,
},
Command::PauseAnimation {
entity: Ref::Entity(fox),
},
Command::ResumeAnimation {
entity: Ref::Entity(fox),
},
Command::StopAnimation {
entity: Ref::Entity(fox),
},
Command::PlayAnimation {
entity: Ref::Entity(fox),
clip: 1,
},
],
);
let crate_body = entity_of(&submit_command(
world,
&Command::SpawnObject {
shape: Shape::Cube,
position: [2.0, 5.0, -3.0],
scale: [1.0, 1.0, 1.0],
color: ORANGE,
body: Body::Dynamic { mass: 1.0 },
},
));
submit_commands(
world,
&[
Command::SetCollisionGroups {
entity: Ref::Entity(crate_body),
membership: 1,
filter: 15,
},
Command::ApplyForce {
entity: Ref::Entity(crate_body),
force: [0.0, 8.0, 0.0],
},
Command::ApplyTorque {
entity: Ref::Entity(crate_body),
torque: [0.0, 4.0, 0.0],
},
Command::Push {
entity: Ref::Entity(crate_body),
impulse: [0.0, 1.0, 0.0],
},
Command::SetVelocity {
entity: Ref::Entity(crate_body),
velocity: [0.5, 2.0, 0.0],
},
Command::SetAngularVelocity {
entity: Ref::Entity(crate_body),
velocity: [0.0, 3.0, 0.0],
},
],
);
let pad = entity_of(&submit_command(
world,
&Command::SpawnObject {
shape: Shape::Cube,
position: [0.0, 0.1, 4.0],
scale: [3.0, 0.2, 3.0],
color: PURPLE,
body: Body::Static,
},
));
submit_commands(
world,
&[
Command::MakeSensor {
entity: Ref::Entity(pad),
},
Command::SetCollisionGroups {
entity: Ref::Entity(pad),
membership: 2,
filter: 1,
},
],
);
let temporary = entity_of(&submit_command(
world,
&Command::SpawnCube {
position: [8.0, 0.6, 8.0],
},
));
submit_commands(
world,
&[
Command::Tag {
entity: Ref::Entity(temporary),
label: "temporary".to_string(),
},
Command::Untag {
entity: Ref::Entity(temporary),
label: "temporary".to_string(),
},
Command::SetVisible {
entity: Ref::Entity(temporary),
visible: false,
},
Command::Despawn {
entity: Ref::Entity(temporary),
},
],
);
submit_commands(
world,
&[
Command::EmitFire {
position: [6.0, 0.0, -6.0],
},
Command::EmitSmoke {
position: [6.0, 0.0, -6.0],
},
Command::EmitBurst {
position: [-6.0, 1.0, -6.0],
color: GOLD,
count: 40,
},
],
);
let label = entity_of(&submit_command(
world,
&Command::SpawnLabel {
text: "command tour".to_string(),
position: [0.0, 2.0, 0.0],
},
));
submit_command(
world,
&Command::SetTextColor {
entity: Ref::Entity(label),
color: GOLD,
},
);
let hud = entity_of(&submit_command(
world,
&Command::SpawnText {
text: "fps".to_string(),
anchor: ScreenAnchor::TopLeft,
},
));
submit_command(
world,
&Command::SetTextSize {
entity: Ref::Entity(hud),
size: 24.0,
},
);
let panel = entity_of(&submit_command(
world,
&Command::SpawnPanel {
anchor: ScreenAnchor::TopRight,
width: 200.0,
height: 96.0,
},
));
let button = entity_of(&submit_command(
world,
&Command::PanelButton {
panel: Ref::Entity(panel),
text: "Reset".to_string(),
},
));
submit_command(
world,
&Command::PanelLabel {
panel: Ref::Entity(panel),
text: "tour".to_string(),
},
);
let temporary_panel = entity_of(&submit_command(
world,
&Command::SpawnPanel {
anchor: ScreenAnchor::BottomRight,
width: 120.0,
height: 60.0,
},
));
submit_command(
world,
&Command::DespawnPanel {
panel: Ref::Entity(temporary_panel),
},
);
let walker = entity_of(&submit_command(
world,
&Command::SpawnWalker {
position: [0.0, 0.0, -8.0],
},
));
submit_commands(
world,
&[
Command::BakeNavmesh {},
Command::SetWalkSpeed {
agent: Ref::Entity(walker),
speed: 3.0,
},
Command::WalkTo {
agent: Ref::Entity(walker),
destination: [8.0, 0.0, 8.0],
},
Command::StopWalking {
agent: Ref::Entity(walker),
},
Command::WalkTo {
agent: Ref::Entity(walker),
destination: [-8.0, 0.0, 8.0],
},
],
);
submit_commands(
world,
&[
Command::FlyCamera {
position: [0.0, 4.0, 14.0],
},
Command::FixedCamera {
eye: [10.0, 6.0, 10.0],
target: [0.0, 0.0, 0.0],
},
Command::FirstPerson {
position: [0.0, 1.2, 12.0],
},
Command::OrbitCamera {
focus: [0.0, 1.0, 0.0],
radius: 16.0,
},
Command::LookAt {
eye: [0.0, 8.0, 16.0],
target: [0.0, 1.0, 0.0],
},
Command::SetOrbitFocus {
focus: [0.0, 1.0, 0.0],
},
Command::SetFieldOfView { degrees: 60.0 },
Command::SetOrthographic { half_height: 10.0 },
Command::SetPerspective { degrees: 60.0 },
],
);
Demo {
cube,
crate_body,
button,
hud,
}
}
fn update(world: &mut World, demo: &mut Demo) {
let step = match submit_command(world, &Command::DeltaTime {}) {
CommandReply::Float(value) => value,
_ => 0.0,
};
let elapsed = match submit_command(world, &Command::ElapsedSeconds {}) {
CommandReply::Float(value) => value,
_ => 0.0,
};
submit_command(
world,
&Command::Rotate {
entity: Ref::Entity(demo.cube),
axis: [0.0, 1.0, 0.0],
radians: step,
},
);
submit_commands(
world,
&[
Command::DrawCube {
position: [0.0, 6.0, 0.0],
scale: [0.4, 0.4, 0.4],
color: PURPLE,
},
Command::DrawSphere {
position: [2.0, 6.0, 0.0],
radius: 0.3,
color: TEAL,
},
Command::DrawLine {
start: [0.0, 6.0, 0.0],
end: [2.0, 6.0, 0.0],
color: GOLD,
},
Command::DrawText3d {
text: format!("{elapsed:.0}s"),
position: [0.0, 7.0, 0.0],
},
],
);
let queries = submit_commands(
world,
&[
Command::Position {
entity: Ref::Entity(demo.cube),
},
Command::HasTag {
entity: Ref::Entity(demo.cube),
label: "demo".to_string(),
},
Command::QueryTagged {
label: "demo".to_string(),
},
Command::Velocity {
entity: Ref::Entity(demo.crate_body),
},
Command::AngularVelocity {
entity: Ref::Entity(demo.crate_body),
},
Command::OverlapSphere {
center: [0.0, 1.0, 0.0],
radius: 5.0,
},
Command::CameraPosition {},
Command::CameraForward {},
Command::ButtonHovered {
button: Ref::Entity(demo.button),
},
Command::ButtonClicked {
button: Ref::Entity(demo.button),
},
Command::ClickedEntity {},
Command::EntityUnderCursor {},
Command::CursorOnGround {},
],
);
let nearby = match &queries[5] {
CommandReply::Entities(entities) => entities.len(),
_ => 0,
};
let frames_per_second = if step > 0.0 { 1.0 / step } else { 0.0 };
submit_command(
world,
&Command::SetText {
entity: Ref::Entity(demo.hud),
text: format!("fps {frames_per_second:.0} nearby {nearby}"),
},
);
}