1use mittens_engine::{engine, utils};
2
3#[path = "example_util/mod.rs"]
4mod example_util;
5
6fn main() {
7 mittens_engine::example_support::ensure_model_assets();
8 utils::logger::init();
9
10 let world = engine::ecs::World::default();
11 let mut universe = engine::Universe::new(world);
12
13 let bg_color = universe
14 .world
15 .add_component(engine::ecs::component::BackgroundColorComponent::new());
16 let bg_color_c = universe
17 .world
18 .add_component(engine::ecs::component::ColorComponent::rgba(
19 0.1, 0.02, 0.05, 1.0,
20 ));
21 let _ = universe.world.add_child(bg_color, bg_color_c);
22 universe.add(bg_color);
23
24 let gravity_field = universe
27 .world
28 .add_component(engine::ecs::component::GravityComponent::new().with_coefficient(0.5));
29 universe.add(gravity_field);
30
31 let input = universe
34 .world
35 .add_component(engine::ecs::component::InputComponent::new().with_speed(2.0));
36
37 let rig_transform = universe.world.add_component(
38 engine::ecs::component::TransformComponent::new().with_position(0.0, 0.75, 0.0),
39 );
40 let camera3d = universe
41 .world
42 .add_component(engine::ecs::component::Camera3DComponent::new());
43 let input_mode = universe.world.add_component(
44 engine::ecs::component::InputTransformModeComponent::forward_z()
45 .with_roll_axis_y()
46 .with_fps_rotation(),
47 );
48
49 let rig_collision = universe
50 .world
51 .add_component(engine::ecs::component::CollisionComponent::RIGGED());
52
53 let rig_response = universe
57 .world
58 .add_component(engine::ecs::component::KineticResponseComponent::slide());
59 let rig_shape =
60 universe
61 .world
62 .add_component(engine::ecs::component::CollisionShapeComponent::new(
63 engine::ecs::component::CollisionShape::sphere_radius(0.25),
64 ));
65
66 let _ = universe.attach(input, input_mode);
67 let _ = universe.attach(input, rig_transform);
68 let _ = universe.attach(rig_transform, camera3d);
69
70 let pointer = universe
72 .world
73 .add_component(engine::ecs::component::PointerComponent::new());
74 let _ = universe.attach(camera3d, pointer);
75
76 example_util::spawn_desktop_camera_controls_hint(&mut universe, rig_transform);
78
79 let _ = universe.attach(rig_transform, rig_collision);
80 let _ = universe.attach(rig_collision, rig_response);
81 let _ = universe.attach(rig_collision, rig_shape);
82
83 universe.add(input);
84
85 fn spawn_light(
87 universe: &mut engine::Universe,
88 x: f32,
89 y: f32,
90 z: f32,
91 r: f32,
92 g: f32,
93 b: f32,
94 intensity: f32,
95 distance: f32,
96 ) {
97 let t = universe.world.add_component(
98 engine::ecs::component::TransformComponent::new()
99 .with_position(x, y, z)
100 .with_scale(0.12, 0.12, 0.12),
101 );
102
103 let l = universe.world.add_component(
104 engine::ecs::component::PointLightComponent::new()
105 .with_color(r, g, b)
106 .with_intensity(intensity)
107 .with_distance(distance),
108 );
109 let marker = universe
112 .world
113 .add_component(engine::ecs::component::RenderableComponent::cube());
114 let marker_color =
115 universe
116 .world
117 .add_component(engine::ecs::component::ColorComponent::rgba(
118 1.0, 1.0, 1.0, 1.0,
119 ));
120
121 let _ = universe.attach(t, l);
122 let _ = universe.attach(t, marker);
123 let _ = universe.attach(marker, marker_color);
124 universe.add(t);
125 }
126
127 const N: i32 = 16;
129 let spacing = 1.0;
130 let half = (N as f32 - 1.0) * spacing * 0.5;
131
132 spawn_light(&mut universe, -half, 2.8, -half, 1.0, 0.1, 0.1, 2.5, 14.0); spawn_light(&mut universe, half, 2.8, -half, 0.1, 1.0, 0.1, 2.5, 14.0); spawn_light(&mut universe, half, 2.8, half, 0.1, 0.2, 1.0, 2.5, 14.0); spawn_light(&mut universe, -half, 2.8, half, 1.0, 0.2, 1.0, 2.5, 14.0); spawn_light(&mut universe, 0.0, 5.5, 0.0, 1.0, 1.0, 1.0, 0.7, 40.0); fn spawn_wall_cube(universe: &mut engine::Universe, x: f32, y: f32, z: f32) {
141 let t = universe.world.add_component(
142 engine::ecs::component::TransformComponent::new().with_position(x, y, z),
143 );
144 let r = universe
145 .world
146 .add_component(engine::ecs::component::RenderableComponent::cube());
147 let cn = universe
148 .world
149 .add_component(engine::ecs::component::CollisionComponent::STATIC());
150 let c = universe
151 .world
152 .add_component(engine::ecs::component::ColorComponent::rgba(
153 0.9, 0.2, 0.2, 1.0,
154 ));
155
156 let _ = universe.attach(t, r);
157 let _ = universe.attach(t, cn);
158 let _ = universe.attach(r, c);
159
160 universe.add(t);
161 }
162
163 fn spawn_cube(
164 universe: &mut engine::Universe,
165 x: f32,
166 y: f32,
167 z: f32,
168 sx: f32,
169 sy: f32,
170 sz: f32,
171 r: f32,
172 g: f32,
173 b: f32,
174 ) {
175 let t = universe.world.add_component(
176 engine::ecs::component::TransformComponent::new()
177 .with_position(x, y, z)
178 .with_scale(sx, sy, sz),
179 );
180 let renderable = universe
181 .world
182 .add_component(engine::ecs::component::RenderableComponent::cube());
183 let color = universe
184 .world
185 .add_component(engine::ecs::component::ColorComponent::rgba(r, g, b, 1.0));
186
187 let _ = universe.attach(t, renderable);
188 let _ = universe.attach(renderable, color);
189
190 universe.add(t);
191 }
192
193 fn spawn_pushable_cube(
194 universe: &mut engine::Universe,
195 parent: engine::ecs::ComponentId,
196 x: f32,
197 y: f32,
198 z: f32,
199 s: f32,
200 r: f32,
201 g: f32,
202 b: f32,
203 ) {
204 let t = universe.world.add_component(
205 engine::ecs::component::TransformComponent::new()
206 .with_position(x, y, z)
207 .with_scale(s, s, s),
208 );
209 let renderable = universe
210 .world
211 .add_component(engine::ecs::component::RenderableComponent::cube());
212 let color = universe
213 .world
214 .add_component(engine::ecs::component::ColorComponent::rgba(r, g, b, 1.0));
215
216 let cn = universe
217 .world
218 .add_component(engine::ecs::component::CollisionComponent::KINEMATIC());
219 let response = universe.world.add_component(
220 engine::ecs::component::KineticResponseComponent::push()
221 .with_push_strength(4.0)
222 .with_friction_y(10.0),
223 );
224 let shape =
225 universe
226 .world
227 .add_component(engine::ecs::component::CollisionShapeComponent::new(
228 engine::ecs::component::CollisionShape::cube_half_extents([
229 0.5 * s,
230 0.5 * s,
231 0.5 * s,
232 ]),
233 ));
234
235 let _ = universe.attach(t, renderable);
236 let _ = universe.attach(renderable, color);
237
238 let _ = universe.attach(t, cn);
239 let _ = universe.attach(cn, response);
240 let _ = universe.attach(cn, shape);
241
242 let _ = universe.attach(parent, t);
243 }
244
245 fn spawn_invisible_static_wall(
246 universe: &mut engine::Universe,
247 x: f32,
248 y: f32,
249 z: f32,
250 half_extents: [f32; 3],
251 ) {
252 let t = universe.world.add_component(
253 engine::ecs::component::TransformComponent::new().with_position(x, y, z),
254 );
255
256 let cn = universe
257 .world
258 .add_component(engine::ecs::component::CollisionComponent::STATIC());
259 let shape =
260 universe
261 .world
262 .add_component(engine::ecs::component::CollisionShapeComponent::new(
263 engine::ecs::component::CollisionShape::cube_half_extents(half_extents),
264 ));
265
266 let response = universe
269 .world
270 .add_component(engine::ecs::component::KineticResponseComponent::slide());
271
272 let _ = universe.attach(t, cn);
273 let _ = universe.attach(cn, shape);
274 let _ = universe.attach(cn, response);
275 universe.add(t);
276 }
277
278 let y = 0.5;
279
280 {
282 let ground_half = half + 2.0;
283 let thickness = 0.20;
284
285 let ground_root_t = universe
288 .world
289 .add_component(engine::ecs::component::TransformComponent::new());
290 let ground_geom_t = universe.world.add_component(
291 engine::ecs::component::TransformComponent::new()
292 .with_position(0.0, -thickness, 0.0)
293 .with_scale(ground_half * 2.0, thickness * 2.0, ground_half * 2.0),
294 );
295 let ground_r = universe
296 .world
297 .add_component(engine::ecs::component::RenderableComponent::cube());
298 let ground_c = universe
299 .world
300 .add_component(engine::ecs::component::ColorComponent::rgba(
301 0.08, 0.08, 0.09, 1.0,
302 ));
303 let ground_cn = universe
304 .world
305 .add_component(engine::ecs::component::CollisionComponent::STATIC());
306 let ground_shape =
307 universe
308 .world
309 .add_component(engine::ecs::component::CollisionShapeComponent::new(
310 engine::ecs::component::CollisionShape::cube_half_extents([
311 ground_half,
312 thickness,
313 ground_half,
314 ]),
315 ));
316
317 let _ = universe.attach(ground_root_t, ground_geom_t);
318 let _ = universe.attach(ground_geom_t, ground_r);
319 let _ = universe.attach(ground_r, ground_c);
320 let _ = universe.attach(ground_geom_t, ground_cn);
321 let _ = universe.attach(ground_cn, ground_shape);
322 universe.add(ground_root_t);
323 }
324
325 for i in 0..N {
327 let x = -half + (i as f32) * spacing;
328 let z = -half;
329 spawn_wall_cube(&mut universe, x, y, z);
330 }
331
332 for i in 1..N {
334 let x = half;
335 let z = -half + (i as f32) * spacing;
336 spawn_wall_cube(&mut universe, x, y, z);
337 }
338
339 for i in 1..N {
341 let x = half - (i as f32) * spacing;
342 let z = half;
343 spawn_wall_cube(&mut universe, x, y, z);
344 }
345
346 for i in 1..(N - 1) {
348 let x = -half;
349 let z = half - (i as f32) * spacing;
350 spawn_wall_cube(&mut universe, x, y, z);
351 }
352
353 let outer = half + 3.0;
355 spawn_cube(
356 &mut universe,
357 0.0,
358 0.75,
359 -outer,
360 3.0,
361 1.5,
362 1.0,
363 0.15,
364 0.15,
365 0.18,
366 );
367 spawn_cube(
368 &mut universe,
369 0.0,
370 0.75,
371 outer,
372 3.0,
373 1.5,
374 1.0,
375 0.15,
376 0.15,
377 0.18,
378 );
379 spawn_cube(
380 &mut universe,
381 -outer,
382 0.75,
383 0.0,
384 1.0,
385 1.5,
386 3.0,
387 0.15,
388 0.15,
389 0.18,
390 );
391 spawn_cube(
392 &mut universe,
393 outer,
394 0.75,
395 0.0,
396 1.0,
397 1.5,
398 3.0,
399 0.15,
400 0.15,
401 0.18,
402 );
403
404 {
407 let wall_center_y = 6.0; let wall_half_height = 6.0;
409 let wall_half_thickness = 0.25;
410 let wall_offset = half + 6.0;
411 let wall_half_len = wall_offset + 2.0;
412
413 spawn_invisible_static_wall(
415 &mut universe,
416 0.0,
417 wall_center_y,
418 wall_offset,
419 [wall_half_len, wall_half_height, wall_half_thickness],
420 );
421 spawn_invisible_static_wall(
422 &mut universe,
423 0.0,
424 wall_center_y,
425 -wall_offset,
426 [wall_half_len, wall_half_height, wall_half_thickness],
427 );
428
429 spawn_invisible_static_wall(
431 &mut universe,
432 wall_offset,
433 wall_center_y,
434 0.0,
435 [wall_half_thickness, wall_half_height, wall_half_len],
436 );
437 spawn_invisible_static_wall(
438 &mut universe,
439 -wall_offset,
440 wall_center_y,
441 0.0,
442 [wall_half_thickness, wall_half_height, wall_half_len],
443 );
444
445 spawn_invisible_static_wall(
447 &mut universe,
448 0.0,
449 wall_center_y + wall_half_height + wall_half_thickness,
450 0.0,
451 [wall_half_len, wall_half_thickness, wall_half_len],
452 );
453 }
454
455 let mut seed: u32 = 0xC0111510;
458 let mut rng01 = || {
459 seed ^= seed << 13;
460 seed ^= seed >> 17;
461 seed ^= seed << 5;
462 (seed as f32) / (u32::MAX as f32)
463 };
464
465 for band in 0..3 {
467 for _ in 0..60 {
468 let s = match band {
469 0 => 0.12 + rng01() * 0.20, 1 => 0.35 + rng01() * 0.35, _ => 0.75 + rng01() * 0.55, };
473
474 let bound = (half - (1.0 + s)).max(0.5);
475 let x = (rng01() * 2.0 - 1.0) * bound;
476 let z = (rng01() * 2.0 - 1.0) * bound;
477 let y = 0.5 * s;
478
479 let cr = 0.25 + rng01() * 0.6;
481 let cg = 0.25 + rng01() * 0.6;
482 let cb = 0.25 + rng01() * 0.6;
483
484 spawn_pushable_cube(&mut universe, gravity_field, x, y, z, s, cr, cg, cb);
485 }
486 }
487
488 universe.systems.process_commands(
490 &mut universe.world,
491 &mut universe.visuals,
492 &mut universe.render_assets,
493 &mut universe.command_queue,
494 );
495
496 engine::Windowing::run_app(universe).expect("Windowing failed");
497}