217 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
use bevy::prelude::*;
 | 
						|
use rand::{random, rngs::StdRng, Rng, SeedableRng};
 | 
						|
use std::collections::VecDeque;
 | 
						|
 | 
						|
struct Person;
 | 
						|
 | 
						|
struct Velocity {
 | 
						|
    pub value: math::Vec3,
 | 
						|
}
 | 
						|
 | 
						|
struct NavigationPoint {
 | 
						|
    pub target: math::Vec3,
 | 
						|
}
 | 
						|
 | 
						|
struct Wander {
 | 
						|
    pub duration_bounds: math::Vec2,
 | 
						|
    pub distance_bounds: math::Vec2,
 | 
						|
    pub duration: f32,
 | 
						|
    pub elapsed: f32,
 | 
						|
}
 | 
						|
 | 
						|
fn main() {
 | 
						|
    AppBuilder::new()
 | 
						|
        .add_defaults_legacy()
 | 
						|
        .setup_world(setup)
 | 
						|
        .add_system(build_wander_system())
 | 
						|
        .add_system(build_navigate_system())
 | 
						|
        .add_system(build_move_system())
 | 
						|
        .add_system(build_print_status_system())
 | 
						|
        .run();
 | 
						|
}
 | 
						|
 | 
						|
fn setup(world: &mut World) {
 | 
						|
    let cube = Mesh::load(MeshType::Cube);
 | 
						|
    let cube_handle = {
 | 
						|
        let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
 | 
						|
        mesh_storage.add(cube)
 | 
						|
    };
 | 
						|
 | 
						|
    world.insert(
 | 
						|
        (),
 | 
						|
        vec![
 | 
						|
            // lights
 | 
						|
            (
 | 
						|
                Light {
 | 
						|
                    color: wgpu::Color {
 | 
						|
                        r: 0.8,
 | 
						|
                        g: 0.8,
 | 
						|
                        b: 0.5,
 | 
						|
                        a: 1.0,
 | 
						|
                    },
 | 
						|
                    fov: f32::to_radians(60.0),
 | 
						|
                    depth: 0.1..50.0,
 | 
						|
                    target_view: None,
 | 
						|
                },
 | 
						|
                Material::new(Albedo::Color(math::vec4(0.5, 0.3, 0.3, 1.0))),
 | 
						|
                LocalToWorld::identity(),
 | 
						|
                Translation::new(4.0, -4.0, 5.0),
 | 
						|
                Rotation::from_euler_angles(0.0, 0.0, 0.0),
 | 
						|
            ),
 | 
						|
        ],
 | 
						|
    );
 | 
						|
 | 
						|
    world.insert(
 | 
						|
        (),
 | 
						|
        vec![
 | 
						|
            // camera
 | 
						|
            (
 | 
						|
                Camera::new(CameraType::Projection {
 | 
						|
                    fov: std::f32::consts::PI / 4.0,
 | 
						|
                    near: 1.0,
 | 
						|
                    far: 1000.0,
 | 
						|
                    aspect_ratio: 1.0,
 | 
						|
                }),
 | 
						|
                ActiveCamera,
 | 
						|
                LocalToWorld(Mat4::look_at_rh(
 | 
						|
                    Vec3::new(6.0, -40.0, 20.0),
 | 
						|
                    Vec3::new(0.0, 0.0, 0.0),
 | 
						|
                    Vec3::new(0.0, 0.0, 1.0),
 | 
						|
                )),
 | 
						|
            ),
 | 
						|
        ],
 | 
						|
    );
 | 
						|
 | 
						|
    let mut rng = StdRng::from_entropy();
 | 
						|
    for _ in 0..70000 {
 | 
						|
        create_person(
 | 
						|
            world,
 | 
						|
            cube_handle.clone(),
 | 
						|
            Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)),
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
fn build_wander_system() -> Box<dyn Schedulable> {
 | 
						|
    let mut rng = StdRng::from_entropy();
 | 
						|
 | 
						|
    SystemBuilder::new("Wander")
 | 
						|
        .read_resource::<Time>()
 | 
						|
        .with_query(<(
 | 
						|
            Read<Person>,
 | 
						|
            Read<Translation>,
 | 
						|
            Write<Wander>,
 | 
						|
            Write<NavigationPoint>,
 | 
						|
        )>::query())
 | 
						|
        .build(move |_, world, time, person_query| {
 | 
						|
            for (_, translation, mut wander, mut navigation_point) in person_query.iter_mut(world) {
 | 
						|
                wander.elapsed += time.delta_seconds;
 | 
						|
                if wander.elapsed >= wander.duration {
 | 
						|
                    let direction = math::vec3(
 | 
						|
                        rng.gen_range(-1.0, 1.0),
 | 
						|
                        rng.gen_range(-1.0, 1.0),
 | 
						|
                        rng.gen_range(0.0, 0.001),
 | 
						|
                    )
 | 
						|
                    .normalize();
 | 
						|
                    let distance =
 | 
						|
                        rng.gen_range(wander.distance_bounds.x(), wander.distance_bounds.y());
 | 
						|
                    navigation_point.target = translation.0 + direction * distance;
 | 
						|
                    wander.elapsed = 0.0;
 | 
						|
                    wander.duration =
 | 
						|
                        rng.gen_range(wander.duration_bounds.x(), wander.duration_bounds.y());
 | 
						|
                }
 | 
						|
            }
 | 
						|
        })
 | 
						|
}
 | 
						|
 | 
						|
fn build_navigate_system() -> Box<dyn Schedulable> {
 | 
						|
    SystemBuilder::new("Navigate")
 | 
						|
        .with_query(<(
 | 
						|
            Read<Person>,
 | 
						|
            Write<Translation>,
 | 
						|
            Write<Velocity>,
 | 
						|
            Write<NavigationPoint>,
 | 
						|
        )>::query())
 | 
						|
        .build(move |_, world, _, person_query| {
 | 
						|
            for (_, translation, mut velocity, navigation_point) in person_query.iter_mut(world) {
 | 
						|
                let distance = navigation_point.target - translation.0;
 | 
						|
                if distance.length() > 0.01 {
 | 
						|
                    let direction = distance.normalize();
 | 
						|
                    velocity.value = direction * 2.0;
 | 
						|
                } else {
 | 
						|
                    velocity.value = math::vec3(0.0, 0.0, 0.0);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        })
 | 
						|
}
 | 
						|
 | 
						|
fn build_move_system() -> Box<dyn Schedulable> {
 | 
						|
    SystemBuilder::new("Move")
 | 
						|
        .read_resource::<Time>()
 | 
						|
        .with_query(<(Write<Translation>, Read<Velocity>)>::query())
 | 
						|
        .build(move |_, world, time, person_query| {
 | 
						|
            for (mut translation, velocity) in person_query.iter_mut(world) {
 | 
						|
                translation.0 += velocity.value * time.delta_seconds;
 | 
						|
            }
 | 
						|
        })
 | 
						|
}
 | 
						|
 | 
						|
fn build_print_status_system() -> Box<dyn Schedulable> {
 | 
						|
    let mut elapsed = 0.0;
 | 
						|
    let mut frame_time_total = 0.0;
 | 
						|
    let mut frame_time_count = 0;
 | 
						|
    let frame_time_max = 10;
 | 
						|
    let mut frame_time_values = VecDeque::new();
 | 
						|
    SystemBuilder::new("PrintStatus")
 | 
						|
        .read_resource::<Time>()
 | 
						|
        .with_query(<(Read<Person>,)>::query())
 | 
						|
        .build(move |_, world, time, person_query| {
 | 
						|
            elapsed += time.delta_seconds;
 | 
						|
            frame_time_values.push_front(time.delta_seconds);
 | 
						|
            frame_time_total += time.delta_seconds;
 | 
						|
            frame_time_count += 1;
 | 
						|
            if frame_time_count > frame_time_max {
 | 
						|
                frame_time_count = frame_time_max;
 | 
						|
                frame_time_total -= frame_time_values.pop_back().unwrap();
 | 
						|
            }
 | 
						|
            if elapsed > 1.0 {
 | 
						|
                if frame_time_count > 0 && frame_time_total > 0.0 {
 | 
						|
                    println!(
 | 
						|
                        "fps: {}",
 | 
						|
                        1.0 / (frame_time_total / frame_time_count as f32)
 | 
						|
                    )
 | 
						|
                }
 | 
						|
                println!("peeps: {}", person_query.iter(world).count());
 | 
						|
                elapsed = 0.0;
 | 
						|
            }
 | 
						|
        })
 | 
						|
}
 | 
						|
 | 
						|
fn create_person(world: &mut World, mesh_handle: Handle<Mesh>, translation: Translation) {
 | 
						|
    world.insert(
 | 
						|
        (),
 | 
						|
        vec![(
 | 
						|
            Person {},
 | 
						|
            Wander {
 | 
						|
                duration_bounds: math::vec2(3.0, 10.0),
 | 
						|
                distance_bounds: math::vec2(-50.0, 50.0),
 | 
						|
                elapsed: 0.0,
 | 
						|
                duration: 0.0,
 | 
						|
            },
 | 
						|
            NavigationPoint {
 | 
						|
                target: math::vec3(0.0, 0.0, 0.0),
 | 
						|
            },
 | 
						|
            Velocity {
 | 
						|
                value: math::vec3(0.0, 0.0, 0.0),
 | 
						|
            },
 | 
						|
            Instanced,
 | 
						|
            Material::new(Albedo::Color(
 | 
						|
                math::vec4(0.5, 0.3, 0.3, 1.0) * random::<f32>(),
 | 
						|
            )),
 | 
						|
            mesh_handle,
 | 
						|
            LocalToWorld::identity(),
 | 
						|
            translation,
 | 
						|
        )],
 | 
						|
    );
 | 
						|
}
 |