use nightshade_api::prelude::*;
struct Crowd {
agents: Vec<(Entity, usize)>,
waypoints: Vec<Vec3>,
player: Entity,
patrol: usize,
hud: Entity,
}
fn main() {
run(setup, update).unwrap();
}
fn setup(world: &mut World) -> Crowd {
spawn_floor(world, 20.0);
for position in obstacles() {
let block = spawn_cube(world, position);
set_scale(world, block, vec3(2.0, 2.0, 2.0));
set_color(world, block, STEEL);
}
bake_navmesh_with(
world,
&RecastNavMeshConfig {
agent_radius: 0.4,
..Default::default()
},
);
let waypoints = vec![
vec3(-12.0, 0.0, -12.0),
vec3(12.0, 0.0, -12.0),
vec3(12.0, 0.0, 12.0),
vec3(-12.0, 0.0, 12.0),
];
let mut agents = Vec::new();
for index in 0..4 {
let agent = spawn_walker(world, waypoints[index]);
set_walk_speed(world, agent, 3.5);
let target = (index + 1) % waypoints.len();
walk_to(world, agent, waypoints[target]);
agents.push((agent, target));
}
let player = first_person(world, vec3(0.0, 1.2, 16.0));
set_controller_speed(world, player, 7.0);
set_controller_jump(world, player, 6.0);
let hud = spawn_text(world, "agents", ScreenAnchor::TopLeft);
spawn_text(
world,
"WASD walk hold F autopilot patrol",
ScreenAnchor::BottomLeft,
);
Crowd {
agents,
waypoints,
player,
patrol: 0,
hud,
}
}
fn obstacles() -> Vec<Vec3> {
vec![
vec3(-5.0, 1.0, 0.0),
vec3(5.0, 1.0, 4.0),
vec3(0.0, 1.0, -6.0),
]
}
fn update(world: &mut World, state: &mut Crowd) {
for slot in 0..state.agents.len() {
let (agent, target) = state.agents[slot];
let here = position(world, agent);
if (here - state.waypoints[target]).magnitude() < 1.5 {
if slot == 0 {
stop_walking(world, agent);
}
let next = (target + 1) % state.waypoints.len();
walk_to(world, agent, state.waypoints[next]);
state.agents[slot].1 = next;
}
}
if key_down(world, KeyCode::KeyF) {
let goal = state.waypoints[state.patrol];
let here = position(world, state.player);
let to_goal = vec3(goal.x - here.x, 0.0, goal.z - here.z);
if to_goal.magnitude() < 1.5 {
state.patrol = (state.patrol + 1) % state.waypoints.len();
}
let movement = if to_goal.magnitude() > 0.1 {
let direction = nalgebra_glm::normalize(&to_goal);
vec2(direction.x, direction.z)
} else {
vec2(0.0, 0.0)
};
move_character(
world,
state.player,
movement,
key_down(world, KeyCode::Space),
);
}
let grounded = is_grounded(world, state.player);
let speed = controller_velocity(world, state.player).magnitude();
set_text(
world,
state.hud,
&format!(
"grounded {} speed {:.1} patrol {}",
grounded, speed, state.patrol
),
);
}