use rusting_engine::prelude::*;
use rusting_engine::runtime::{Collider, DirectionalLight, RigidBodyKind};
const SIDE: usize = 25;
const LAYERS: usize = 80;
const GAP: f32 = 0.02;
const BLAST_AT: f32 = 2.5;
const BLAST_HEIGHT: f32 = 6.0;
const BLAST_SPEED: f32 = 14.0;
const CHARGE: &str = r#"
void condition(inout PhysicsState body) {
vec4 blast = condition_params.values[0]; // x time, y height, z speed
if (pc.elapsed < blast.x || pc.elapsed >= blast.x + pc.dt) return;
vec3 position = body.model[3].xyz;
if (position.y > blast.y) return;
vec2 out_dir = normalize(position.xz + vec2(0.01, 0.013));
float strength = 1.0 - position.y / blast.y;
body.velocity.xyz += vec3(out_dir.x, 0.25, out_dir.y) * blast.z * strength;
}
"#;
fn portrait() -> bool {
std::env::args().any(|arg| arg == "--portrait")
}
fn rough() -> Collider {
Collider {
friction: 1.0,
..Collider::default()
}
}
fn facing(direction: [f32; 3]) -> [f32; 3] {
let length = direction.iter().map(|axis| axis * axis).sum::<f32>().sqrt();
let [x, y, z] = direction.map(|axis| axis / length);
[y.asin(), (-x).atan2(-z), 0.0]
}
fn create(scene: &mut GameScene<'_>) {
scene.set_background_color([0.02, 0.025, 0.035, 1.0]);
scene.world().spawn((
Transform {
rotation: facing([-0.5, -1.0, -0.35]),
..Transform::default()
},
DirectionalLight {
illuminance: 60_000.0,
..DirectionalLight::default()
},
));
let ground_material = scene.create_material(MaterialAsset {
base_color: [0.12, 0.12, 0.13, 1.0],
roughness: 0.9,
..MaterialAsset::default()
});
let mut ground = Transform::new([0.0, -0.5, 0.0]);
ground.scale = [400.0, 1.0, 400.0];
scene.spawn_cube_with_material(
"Ground",
ground,
&CubeSpawn::new().class("tower_ground"),
ground_material,
);
scene.apply_gpu_physics_to_class(
"tower_ground",
&GpuBodySettings {
rigid_body: RigidBody {
kind: RigidBodyKind::Fixed,
..RigidBody::default()
},
collider: rough(),
..GpuBodySettings::default()
},
);
let bands = [
[0.9, 0.25, 0.1],
[0.95, 0.6, 0.12],
[0.85, 0.85, 0.8],
[0.2, 0.6, 0.85],
[0.25, 0.3, 0.8],
]
.map(|color| {
scene.create_material(MaterialAsset {
base_color: [color[0], color[1], color[2], 1.0],
roughness: 0.55,
..MaterialAsset::default()
})
});
let shape = CubeSpawn::new().class("tower_cube");
let pitch = 1.0 + GAP;
let centre = (SIDE - 1) as f32 / 2.0;
for layer in 0..LAYERS {
let material = bands[layer * bands.len() / LAYERS];
for cell in 0..SIDE * SIDE {
let x = ((cell % SIDE) as f32 - centre) * pitch;
let z = ((cell / SIDE) as f32 - centre) * pitch;
scene.spawn_cube_with_material(
format!("Cube {}", layer * SIDE * SIDE + cell),
Transform::new([x, 0.5 + layer as f32, z]),
&shape,
material,
);
}
}
scene.apply_gpu_physics_to_class(
"tower_cube",
&GpuBodySettings {
solver: PhysicsSolver::Full,
collider: rough(),
..GpuBodySettings::default()
},
);
println!("tower of {} cubes", SIDE * SIDE * LAYERS);
}
fn update(scene: &mut GameScene<'_>, time: &FrameTime) {
scene.once("create_tower_collapse", create);
scene.set_gpu_condition_shaders(vec![GpuConditionShader {
events: Vec::new(),
glsl: CHARGE.into(),
params: vec![[BLAST_AT, BLAST_HEIGHT, BLAST_SPEED, 0.0]],
events_per_body: 1,
}]);
let t = time.elapsed_seconds();
let smooth = |from: f32, to: f32| {
let k = ((t - from) / (to - from)).clamp(0.0, 1.0);
k * k * (3.0 - 2.0 * k)
};
let fall = smooth(BLAST_AT, BLAST_AT + 8.0);
let rise = smooth(16.0, 28.0);
let reach = if portrait() { 1.0 } else { 0.8 };
let distance = reach * (170.0 - 40.0 * fall + 60.0 * rise);
let angle = 0.7 + 0.04 * t;
let height = 55.0 - 15.0 * fall + 110.0 * rise;
let aim = 38.0 - 32.0 * fall - 6.0 * rise;
let position = [distance * angle.cos(), height, distance * angle.sin()];
scene
.object("Game Camera")
.set_position(position)
.look_at([0.0, aim, 0.0]);
}
rusting_game!("testGame/build/main.rscene.bin", update);