use crate::track::Track;
use bevy::{
math::{cubic_splines::CubicCurve, vec3},
prelude::*,
render::{
mesh::{Indices, PrimitiveTopology},
render_asset::RenderAssetUsages,
texture::{ImageAddressMode, ImageLoaderSettings, ImageSampler, ImageSamplerDescriptor},
},
};
use std::f32::consts::PI;
use rand::{thread_rng, Rng};
#[derive(Debug, Clone, Copy)]
enum Cube {
Rock,
Ring { position: Vec3, look_at: Vec3 },
Empty,
}
pub fn build_level(
mut commands: Commands,
assets: ResMut<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut images: ResMut<Assets<Image>>,
mut mat: ResMut<Assets<StandardMaterial>>,
) {
let mut model: [[[Cube; 10]; 10]; 10] = [[[Cube::Empty; 10]; 10]; 10];
let mut rocks_ct = 300;
let rock = assets.load("Rock 1.glb#Scene0");
let ring = assets.load("Ring.glb#Scene0");
let mut r = thread_rng();
while rocks_ct > 0 {
let (x, y, z) = (r.gen_range(0..10), r.gen_range(0..10), r.gen_range(0..10));
match model[x][y][z] {
Cube::Empty => {
rocks_ct -= 1;
model[x][y][z] = Cube::Rock;
}
_ => (),
}
}
let mut curve_points = vec![Vec3::new(0.0, 0.0, -10.0), Vec3::new(0.0, 0.0, -20.0)];
for _ in 0..8 {
let point = vec3(
(-0.5 + r.gen::<f32>()) * 200.0,
(-0.5 + r.gen::<f32>()) * 200.0,
(-0.5 + r.gen::<f32>()) * 200.0,
);
curve_points.push(point);
}
for round in 0..10 {
for i in 0..curve_points.len() {
let mut p = curve_points[i].clone();
for j in 0..curve_points.len() {
if i != j {
let other = curve_points[j].clone();
let dist = (p - other).length();
p -= (other - curve_points[i]) * 10.0 / (dist * dist);
}
}
curve_points[i] = p;
}
}
for i in 0..curve_points.len() {
for j in 1..curve_points.len() - 2 {
let v1 = (curve_points[j + 1] - curve_points[j]).normalize();
let v2 = (curve_points[j + 2] - curve_points[j + 1]).normalize();
if v1.dot(v2) < 0.75 {
let temp = curve_points[j + 1];
curve_points[j + 1] = curve_points[j + 2];
curve_points[j + 2] = temp;
}
}
}
let track = Track::new(CubicCardinalSpline::new(0.5, curve_points).to_curve(), 1.0, 16, 200);
for t in 0..10 {
let t = t as f32;
let p2 = track.curve.position(t);
model[((p2.x / 20.0).round() + 4.5) as usize][((p2.y / 20.0).round() + 4.5) as usize]
[((p2.z / 20.0).round() + 4.5) as usize] = Cube::Ring {
position: p2.clone(),
look_at: track.curve.velocity(t).normalize(),
};
}
for i in 0..10 {
for j in 0..10 {
for k in 0..10 {
match model[i][j][k] {
Cube::Rock => {
commands.spawn(SceneBundle {
scene: rock.clone(),
transform: Transform::from_xyz(
(-4.5 + i as f32) * 20.0,
(-4.5 + j as f32) * 20.0,
(-4.5 + k as f32) * 20.0,
), ..default()
});
}
Cube::Ring { position, look_at } => {
commands.spawn(SceneBundle {
scene: ring.clone(),
transform: Transform::from_xyz(position.x, position.y, position.z)
.looking_to(look_at, Vec3::ZERO)
.with_scale(Vec3::splat(3.0)),
..default()
});
}
Cube::Empty => (),
};
}
}
}
let texture_handle = assets.load_with_settings("checkerboard_albedo.png", |s: &mut _| {
*s = ImageLoaderSettings {
sampler: ImageSampler::Descriptor(ImageSamplerDescriptor {
address_mode_u: ImageAddressMode::Repeat,
address_mode_v: ImageAddressMode::Repeat,
..default()
}),
..default()
}
});
let mesh = track.mesh();
let mut texture_mat = StandardMaterial::default();
texture_mat.base_color_texture = Some(texture_handle.clone());
commands.spawn(PbrBundle {
mesh: meshes.add(mesh),
material: mat.add(texture_mat),
..default()
});
}