1use std::time::Duration;
2
3use bevy::{
4 audio::PlaybackMode,
5 core_pipeline::{bloom::BloomSettings, tonemapping::Tonemapping},
6 input::keyboard,
7 pbr::{NotShadowCaster, NotShadowReceiver},
8 prelude::*,
9 render::render_resource::{Extent3d, TextureDimension, TextureFormat},
10 window::{CursorGrabMode, WindowMode},
11};
12use bevy_third_person_camera::{
13 ThirdPersonCamera, ThirdPersonCameraPlugin, ThirdPersonCameraTarget, Zoom,
14};
15const USER_GROUP: Group = Group::GROUP_4;
16const PLANE_GROUP: Group = Group::GROUP_5;
17const BOX_GROUP: Group = Group::GROUP_2;
18const EXPLODER_GROUP: Group = Group::GROUP_3;
19
20use bevy_rapier3d::prelude::*;
21use rand::Rng;
22#[derive(Component, Reflect)]
23struct Cube {
24 max_speed: f32,
25 max_acceleration: f32,
26}
27
28#[derive(Component, Reflect)]
29struct JumpControl {
30 jump: bool,
31 remaining_jumps: u8,
32 jump_speed: f32,
33}
34
35#[derive(States, Debug, Default, Hash, PartialEq, Eq, Clone, Copy)]
36enum GameState {
37 #[default]
38 Init,
39 Splash,
40}
41
42#[bevy_main]
43pub fn main() {
44 App::new()
45 .add_plugins(
46 DefaultPlugins
47 .set(ImagePlugin::default_nearest())
48 .set(WindowPlugin {
49 primary_window: Some(Window {
50 canvas: Some("#game".to_string()),
51 fit_canvas_to_parent: true,
52 mode: WindowMode::BorderlessFullscreen,
53 ..Default::default()
54 }),
55 ..Default::default()
56 }),
57 )
58 .add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
59 .add_state::<GameState>()
60 .register_type::<Cube>()
65 .register_type::<JumpControl>()
66 .add_plugins(ThirdPersonCameraPlugin)
67 .add_systems(Startup, startup)
68 .add_systems(
69 Update,
70 (
71 cube_move_keyboard,
73 cude_move_gamepad,
74 reset_jump,
76 cube_jump,
77 move_elevator,
78 ),
79 )
80 .add_systems(Update, touch_sensor.run_if(in_state(GameState::Init)))
81 .add_systems(
82 Update,
83 (
84 launch,
85 destroy,
86 explode,
87 assend,
88 launch_superball,
89 add_collider,
90 )
91 .run_if(in_state(GameState::Splash)),
92 )
93 .add_systems(OnEnter(GameState::Splash), splash_init)
94 .run();
95}
96
97#[derive(Component)]
98struct DestroyCountdown(f32);
99
100fn destroy(
101 mut commands: Commands,
102 mut items: Query<(Entity, &mut DestroyCountdown)>,
103 time: Res<Time>,
104) {
105 let delta = time.delta_seconds();
106 for (e, mut d) in items.iter_mut() {
107 d.0 -= delta;
108 if d.0 < 0.0 {
109 commands.entity(e).despawn();
110 }
111 }
112}
113
114#[derive(Component)]
115struct ExplodCountDown(f32);
116
117#[derive(Component)]
118struct AddColliderCountDown(Timer);
119
120#[derive(Resource)]
121struct FireWorkMeshes {
122 splash_meshes: Vec<Handle<Mesh>>,
123 meshes: Vec<Handle<Mesh>>,
124 ball_matierials: Vec<Handle<StandardMaterial>>,
125 splash_mat: Vec<Handle<StandardMaterial>>,
126}
127
128#[derive(Component, Debug, Clone)]
129enum FireWorkType {
130 White,
131 Random,
132}
133
134#[derive(Component, Debug, Clone)]
135struct FireWorkProps {
136 range: f32,
137 num: usize,
138 count_down: f32,
139 scale: f32,
140 add_collider: Option<f32>,
141 remaining_splash: Option<Box<FireWorkProps>>,
142 fire_work_type: FireWorkType,
143}
144
145#[derive(Component)]
146struct Assending {
147 speed: f32,
148}
149
150#[derive(Resource)]
151struct SplashTimer(Timer);
152
153fn add_collider(
154 mut commands: Commands,
155 mut items: Query<(Entity, &mut AddColliderCountDown)>,
156 time: Res<Time>,
157) {
158 let delta = time.delta();
159 for (e, mut d) in items.iter_mut() {
160 d.0.tick(delta);
161 if d.0.just_finished() {
162 commands.entity(e).insert((
163 Collider::cuboid(1., 1., 1.),
164 CollisionGroups::new(EXPLODER_GROUP, PLANE_GROUP),
165 ));
166 }
167 }
168}
169
170fn assend(time: Res<Time>, mut items: Query<(&mut Transform, &Assending)>) {
171 let delta = time.delta_seconds();
172 for (mut t, a) in items.iter_mut() {
173 t.translation.y += a.speed * delta;
174 }
175}
176
177fn explode(
178 mut commands: Commands,
179 time: Res<Time>,
180 mut items: Query<(&mut ExplodCountDown, Entity, &FireWorkProps, &mut Transform)>,
181 fire_work_meshs: Res<FireWorkMeshes>,
182) {
183 let delta = time.delta_seconds();
184 for (mut cd, et, fs, ts) in items.iter_mut() {
185 let FireWorkProps {
186 range,
187 num,
188 count_down,
189 scale,
190 add_collider,
191 remaining_splash,
192 fire_work_type,
193 } = fs;
194 cd.0 -= delta;
195 if cd.0 < 0. {
196 commands.entity(et).despawn();
197 let mut rng = rand::thread_rng();
198 for _i in 0..*num {
200 let init_speed = Vec3::new(
201 rng.gen_range(-1. ..1.),
202 rng.gen_range(-1. ..1.),
203 rng.gen_range(-1. ..1.),
204 );
205 let mut cmd = commands.spawn((
206 {
207 let material = match fire_work_type {
208 FireWorkType::White => fire_work_meshs.splash_mat[0].clone(),
209 FireWorkType::Random => {
210 fire_work_meshs.splash_mat[rng.gen_range(0..100)].clone()
211 }
212 };
213 PbrBundle {
214 mesh: fire_work_meshs.splash_meshes[rng.gen_range(0..100)].clone(),
215 material,
216 transform: Transform::from_translation(ts.translation)
217 .with_scale(Vec3::splat(*scale)),
218 ..Default::default()
219 }
220 },
221 Velocity {
222 linvel: init_speed * *range,
223 ..Default::default()
224 },
225 NotShadowCaster,
226 NotShadowReceiver,
227 RigidBody::Dynamic,
228 ));
229 if let Some(time) = add_collider {
230 cmd.insert(AddColliderCountDown(Timer::new(
231 Duration::from_secs_f32(*time),
232 TimerMode::Once,
233 )));
234 }
235 if let Some(remaining_splash) = remaining_splash {
236 let remaining_splash = (**remaining_splash).clone();
238 cmd.insert((remaining_splash, ExplodCountDown(*count_down)));
239 } else {
240 cmd.insert(DestroyCountdown(*count_down));
242 }
243 }
244 }
246 }
247}
248
249fn launch_superball(
250 mut commands: Commands,
251 time: Res<Time>,
252 mut timer: ResMut<SuperBigBallTimer>,
253 superball: Query<Entity, With<SuperBall>>,
254) {
255 timer.timer.tick(time.delta());
256 if timer.timer.just_finished() {
257 println!("launch super ball");
258 let super_ball = superball.single();
259 let mut super_ball = commands.entity(super_ball);
260 super_ball.insert((
261 ExplodCountDown(25.),
262 FireWorkProps {
263 range: 1500.,
264 num: 500,
265 count_down: 10.,
266 scale: 10.,
267 add_collider: Some(1.),
268 remaining_splash: Some(Box::new(FireWorkProps {
269 range: 500.,
270 num: 10,
271 count_down: 22.,
272 scale: 6.,
273 add_collider: None,
274 remaining_splash: None,
275 fire_work_type: FireWorkType::White,
276 })),
277 fire_work_type: FireWorkType::Random,
278 }, Assending { speed: 150. },
280 ));
281 }
282}
283
284fn launch(
285 mut commands: Commands,
286 time: Res<Time>,
287 mut timer: ResMut<SplashTimer>,
288 fire_work_meshs: Res<FireWorkMeshes>,
289 superball_timer: Res<SuperBigBallTimer>,
290) {
291 timer.0.tick(time.delta());
292 if timer.0.just_finished() && !superball_timer.timer.finished() {
293 let mut gen = rand::thread_rng();
294 let mesh_id: usize = gen.gen_range(0..100);
295 let mat_id: usize = gen.gen_range(0..100);
296 let speed: f32 = gen.gen_range(300. ..1000.);
297 let range: f32 = gen.gen_range(300. ..2000.);
298 let cool_down: f32 = gen.gen_range(2. ..5.);
299 commands.spawn((
300 NotShadowCaster,
301 NotShadowReceiver,
302 PbrBundle {
303 mesh: fire_work_meshs.meshes[mesh_id].clone(),
304 material: fire_work_meshs.ball_matierials[mat_id].clone(),
305 transform: Transform::from_translation(Vec3::new(
306 gen.gen_range(-200. ..200.),
307 0.,
308 gen.gen_range(-3500. ..-1000.),
309 )),
310 ..Default::default()
311 },
312 ExplodCountDown(cool_down),
313 FireWorkProps {
315 range,
316 num: 30,
317 count_down: 2.5,
318 scale: 1.,
319 add_collider: Some(0.3),
320 remaining_splash: Some(Box::new(FireWorkProps {
321 range: 100.,
322 num: 5,
323 count_down: 1.,
324 scale: 1.,
325 add_collider: None,
326 remaining_splash: None,
327 fire_work_type: FireWorkType::White,
328 })),
329 fire_work_type: FireWorkType::Random,
330 },
331 Assending { speed },
332 ));
333 }
334}
335
336#[derive(Resource)]
337struct SuperBigBallTimer {
338 timer: Timer,
339}
340
341fn splash_init(
342 mut commands: Commands,
343 mut meshs: ResMut<Assets<Mesh>>,
344 mut materials: ResMut<Assets<StandardMaterial>>,
345 asset_server: Res<AssetServer>,
346) {
347 commands.insert_resource(SplashTimer(Timer::new(
348 Duration::from_secs(1),
349 TimerMode::Repeating,
350 )));
351 commands.insert_resource(SuperBigBallTimer {
352 timer: Timer::new(Duration::from_secs(60), TimerMode::Once),
353 });
354 commands.spawn(AudioBundle {
355 source: asset_server.load("sounds/back.ogg"),
356 settings: PlaybackSettings {
357 mode: PlaybackMode::Once,
358 ..Default::default()
359 },
360 });
361 let mut mesh_res = FireWorkMeshes {
362 splash_meshes: vec![],
363 meshes: vec![],
364 ball_matierials: vec![],
365 splash_mat: vec![],
366 };
367 mesh_res.splash_meshes.push(
369 meshs.add(
370 shape::UVSphere {
371 radius: rand::thread_rng().gen_range(2.5..5.0),
372 sectors: 16,
373 stacks: 16,
374 }
375 .into(),
376 ),
377 );
378 mesh_res.meshes.push(
379 meshs.add(
380 shape::UVSphere {
381 radius: rand::thread_rng().gen_range(2.5..25.0),
382 sectors: 16,
383 stacks: 16,
384 }
385 .into(),
386 ),
387 );
388 mesh_res
389 .ball_matierials
390 .push(materials.add(StandardMaterial {
391 emissive: Color::rgb_linear(5., 5., 5.),
392 ..Default::default()
393 }));
394 mesh_res.splash_mat.push(materials.add(StandardMaterial {
395 emissive: Color::rgb_linear(10., 10., 10.),
396 ..Default::default()
397 }));
398 let mut rng = rand::thread_rng();
399 for _i in 1..100 {
400 mesh_res.meshes.push(
401 meshs.add(
402 shape::UVSphere {
403 radius: rand::thread_rng().gen_range(2.5..25.0),
404 sectors: 16,
405 stacks: 16,
406 }
407 .into(),
408 ),
409 );
410 mesh_res
411 .ball_matierials
412 .push(materials.add(StandardMaterial {
413 emissive: Color::rgb_linear(
414 rng.gen_range(0.1..5.),
415 rng.gen_range(0.1..5.),
416 rng.gen_range(0.1..5.),
417 ),
418 ..Default::default()
419 }));
420 mesh_res.splash_mat.push(materials.add(StandardMaterial {
421 emissive: Color::rgb_linear(
422 rng.gen_range(0.1..15.),
423 rng.gen_range(0.1..15.),
424 rng.gen_range(0.1..15.),
425 ),
426 ..Default::default()
427 }));
428 let rect: bool = rng.gen();
429 if rect {
430 mesh_res
431 .splash_meshes
432 .push(meshs.add(shape::Cube::new(rng.gen_range(2.5..5.0)).into()));
433 } else {
434 mesh_res.splash_meshes.push(
435 meshs.add(
436 shape::UVSphere {
437 radius: rand::thread_rng().gen_range(2.5..5.0),
438 sectors: 16,
439 stacks: 16,
440 }
441 .into(),
442 ),
443 );
444 }
445 }
446
447 commands.insert_resource(mesh_res);
448}
449fn startup(
450 mut commands: Commands,
451 mut meshs: ResMut<Assets<Mesh>>,
452 mut materials: ResMut<Assets<StandardMaterial>>,
453 mut windows: Query<&mut Window>,
454 mut images: ResMut<Assets<Image>>,
455 assert_server: Res<AssetServer>,
456) {
457 let mut window = windows.single_mut();
458 window.cursor.visible = false;
459 window.cursor.grab_mode = CursorGrabMode::Locked;
460 spawn_world(
461 &mut commands,
462 &mut meshs,
463 &mut materials,
464 &mut images,
465 &assert_server,
466 );
467
468 commands.spawn((
470 PbrBundle {
471 mesh: meshs.add(Mesh::from(shape::Cube { size: 1.0 })),
472 material: materials.add(StandardMaterial {
473 emissive: Color::rgb_linear(13.99, 5.32, 2.),
474 ..Default::default()
475 }),
476 transform: Transform::from_xyz(0.0, 5.0, -2.),
477 ..Default::default()
478 },
479 Collider::cuboid(0.5, 0.5, 0.5),
480 RigidBody::Dynamic,
481 ExternalForce::default(),
482 Velocity::default(),
483 Cube {
484 max_speed: 10.,
485 max_acceleration: 10.,
486 },
487 JumpControl {
488 jump: true,
489 remaining_jumps: 2,
490 jump_speed: 10.,
491 },
492 ThirdPersonCameraTarget,
493 Name::new("Player"),
494 CollisionGroups::new(USER_GROUP, PLANE_GROUP | BOX_GROUP),
495 ));
496}
497#[derive(Resource, Deref, Clone, Copy)]
498struct ElevatorStatus {
499 current_location: f32,
501}
502
503#[derive(Component, Deref, Clone, Copy)]
504struct ElevatorId(u8);
505
506fn get_elevator_location(
507 id: ElevatorId,
508 current_status: ElevatorStatus,
509 total_elevators: u8,
510) -> Vec3 {
511 let ratio = id.0 as f32 / total_elevators as f32;
512 let mut status_id = current_status.current_location + ratio * 100.;
513 if status_id > 100. {
514 status_id -= 100.;
515 }
516 if status_id <= 49. {
517 Vec3::new(0., status_id / 49. * 49. * 5., 0.)
518 } else if status_id <= 50. {
519 Vec3::new((status_id - 49.) * 5., 49. * 5., 0.)
520 } else if status_id <= 99. {
521 Vec3::new(5., 49. * 5. - (status_id - 50.) * 5., 0.)
522 } else {
523 Vec3::new(5. - (status_id - 99.) * 5., 0., 0.)
524 }
525}
526static ELEVATOR_LOCATION: Vec3 = Vec3::new(10., -1., 0.);
527const TOTAL_ELEVATORS: u8 = 20;
528#[derive(Resource)]
529struct ElevatorSpeed(f32);
530fn move_elevator(
531 mut ele: Query<(&mut Transform, &ElevatorId)>,
532 mut current_status: ResMut<ElevatorStatus>,
533 time: Res<Time>,
534 elevator_speed: Res<ElevatorSpeed>,
535) {
536 for (mut trans, e) in ele.iter_mut() {
537 let new_position = get_elevator_location(*e, *current_status, TOTAL_ELEVATORS);
538 let new_position = new_position + ELEVATOR_LOCATION;
539 trans.translation = new_position;
540 }
541 current_status.current_location += time.delta_seconds() * elevator_speed.0;
542 if current_status.current_location > 100. {
543 current_status.current_location -= 100.;
544 }
545}
546
547fn spawn_world(
548 commands: &mut Commands,
549 meshs: &mut ResMut<Assets<Mesh>>,
550 materials: &mut ResMut<Assets<StandardMaterial>>,
551 images: &mut ResMut<Assets<Image>>,
552 asset_server: &Res<AssetServer>,
553) {
554 let debug_material = materials.add(StandardMaterial {
555 base_color_texture: Some(images.add(uv_debug_texture())),
556 ..Default::default()
557 });
558 let pink_emit = materials.add(StandardMaterial {
559 emissive: Color::rgb_linear(10., 0.8, 5.8),
560 ..Default::default()
561 });
562 commands.spawn(PointLightBundle {
563 point_light: PointLight {
564 color: Color::WHITE,
565 intensity: 100000.,
566 range: 200.,
567 shadows_enabled: true,
568 ..Default::default()
569 },
570 transform: Transform::from_translation(Vec3::new(0., 20., -10.)),
571 ..Default::default()
572 });
573 spawn_basic(commands, meshs, debug_material.clone());
574
575 let light_material = materials.add(StandardMaterial {
576 emissive: Color::rgb_linear(2.99, 15.32, 2.),
577 ..Default::default()
578 });
579 let light_cube = meshs.add(Mesh::from(shape::Cube { size: 10.0 }));
580
581 spawn_light(commands, &light_cube, &light_material, meshs, pink_emit);
582
583 spawn_elevator(commands, meshs, materials, asset_server);
584 }
586
587fn spawn_elevator(
588 commands: &mut Commands<'_, '_>,
589 meshs: &mut ResMut<'_, Assets<Mesh>>,
590 materials: &mut ResMut<'_, Assets<StandardMaterial>>,
591 assert_server: &Res<AssetServer>,
592) {
593 let image = assert_server.load("images/bibi.png");
595 let front_big_wall_matierial = materials.add(StandardMaterial {
596 base_color_texture: Some(image.clone()),
597 ..Default::default()
598 });
599 commands.spawn((
601 PbrBundle {
602 material: front_big_wall_matierial.clone(),
603 mesh: meshs.add(shape::Box::new(100., 40. * 5., 1.).into()),
604 transform: Transform::from_translation(
605 Vec3::new(0., 40. * 5. / 2., -100.) + ELEVATOR_LOCATION,
606 )
607 .looking_to(Vec3::Z, Vec3::Y),
608 ..Default::default()
609 },
610 Collider::cuboid(100. / 2.0, 40.0 * 5.0 / 2.0, 0.5),
611 CollisionGroups::new(BOX_GROUP, Group::ALL),
612 ));
613 commands.spawn(PointLightBundle {
614 point_light: PointLight {
615 color: Color::WHITE,
616 intensity: 100000.,
617 range: 200.,
618 ..Default::default()
619 },
620 transform: Transform::from_translation(
621 Vec3::new(0., 40. * 5. / 2., -48.) + ELEVATOR_LOCATION,
622 ),
623 ..Default::default()
624 });
625 commands.insert_resource(ElevatorStatus {
627 current_location: 0.0,
628 });
629 commands.insert_resource(ElevatorSpeed(1.));
630
631 let elevator_mesh = meshs.add(shape::Box::new(3., 1., 20.).into());
632 let elevator_matirerial = materials.add(StandardMaterial {
633 emissive: Color::rgb_linear(0.2, 5., 15.),
634 ..Default::default()
635 });
636 let wall_matireial = materials.add(Color::rgba(0.7, 0.6, 0.1, 0.1).into());
638 let side_wall_mesh = meshs.add(shape::Box::new(1., 49. * 5., 20.).into());
639 let front_wall_mesh = meshs.add(shape::Box::new(3. + 5. + 3., 49. * 5., 1.).into());
640 commands.spawn((
642 PbrBundle {
643 material: wall_matireial.clone(),
644 mesh: side_wall_mesh.clone(),
645 transform: Transform::from_translation(
646 Vec3::new(-1.5 - 0.5, 49. * 5. / 2. + 2., 0.) + ELEVATOR_LOCATION,
647 ),
648 ..Default::default()
649 },
650 Collider::cuboid(0.5, 49.0 * 5.0 / 2.0, 20.0 / 2.0),
651 CollisionGroups::new(BOX_GROUP, Group::ALL),
652 ));
653 commands.spawn((
655 PbrBundle {
656 material: wall_matireial.clone(),
657 mesh: side_wall_mesh.clone(),
658 transform: Transform::from_translation(
659 Vec3::new(5. + 1.5 + 0.5, 49. * 5. / 2. + 2., 0.) + ELEVATOR_LOCATION,
660 ),
661 ..Default::default()
662 },
663 Collider::cuboid(0.5, 49.0 * 5.0 / 2.0, 20.0 / 2.0),
664 CollisionGroups::new(BOX_GROUP, Group::ALL),
665 ));
666 commands.spawn((
668 PbrBundle {
669 material: wall_matireial.clone(),
670 mesh: side_wall_mesh.clone(),
671 transform: Transform::from_translation(
672 Vec3::new(2.5, 49. * 5. / 2., 0.) + ELEVATOR_LOCATION,
673 ),
674 ..Default::default()
675 },
676 Collider::cuboid(0.5, 49.0 * 5.0 / 2.0, 20.0 / 2.0),
677 CollisionGroups::new(BOX_GROUP, Group::ALL),
678 ));
679 commands.spawn((
681 PbrBundle {
682 material: wall_matireial.clone(),
683 mesh: front_wall_mesh.clone(),
684 transform: Transform::from_translation(
685 Vec3::new(2.5, 49. * 5. / 2., 10. + 0.5) + ELEVATOR_LOCATION,
686 ),
687 ..Default::default()
688 },
689 Collider::cuboid((3.0 + 5.0 + 3.0) / 2.0, 49.0 * 5.0 / 2.0, 0.5),
690 CollisionGroups::new(BOX_GROUP, Group::ALL),
691 ));
692 commands.spawn((
694 PbrBundle {
695 material: wall_matireial.clone(),
696 mesh: front_wall_mesh.clone(),
697 transform: Transform::from_translation(
698 Vec3::new(2.5, 49. * 5. / 2., -10. - 0.5) + ELEVATOR_LOCATION,
699 ),
700 ..Default::default()
701 },
702 Collider::cuboid((3.0 + 5.0 + 3.0) / 2.0, 49.0 * 5.0 / 2.0, 0.5),
703 CollisionGroups::new(BOX_GROUP, Group::ALL),
704 ));
705
706 commands.spawn((
708 PbrBundle {
709 material: materials.add(Color::WHITE.with_a(0.3).into()),
710 mesh: meshs.add(shape::Plane::from_size(200.).into()),
711 transform: Transform::from_translation(
712 Vec3::new(0.0, 49.0 * 5.0, 0.) + ELEVATOR_LOCATION,
713 ),
714 ..Default::default()
715 },
716 Collider::cuboid(100., 0.01, 100.),
717 CollisionGroups::new(BOX_GROUP, Group::ALL),
718 ));
719 commands.spawn(PointLightBundle {
720 point_light: PointLight {
721 color: Color::WHITE,
722 intensity: 100000.,
723 range: 200.,
724 shadows_enabled: true,
725 ..Default::default()
726 },
727 transform: Transform::from_translation(
728 Vec3::new(0., 49. * 5. + 10., 0.) + ELEVATOR_LOCATION,
729 ),
730 ..Default::default()
731 });
732 commands.spawn((
734 PbrBundle {
735 material: materials.add(Color::PINK.with_a(0.2).into()),
736 mesh: meshs.add(shape::Box::new(200., 0.5, 1.).into()),
737 transform: Transform::from_translation(
738 Vec3::new(0.0, 49.0 * 5.0 + 0.25, -100.) + ELEVATOR_LOCATION,
739 ),
740 ..Default::default()
741 },
742 Collider::cuboid(100., 0.25, 0.5),
743 CollisionGroups::new(BOX_GROUP, Group::ALL),
744 ));
745
746 for i in 0..TOTAL_ELEVATORS {
747 let location = get_elevator_location(
748 ElevatorId(i),
749 ElevatorStatus {
750 current_location: 0.,
751 },
752 TOTAL_ELEVATORS,
753 );
754 commands.spawn((
755 PbrBundle {
756 mesh: elevator_mesh.clone(),
757 material: elevator_matirerial.clone(),
758 transform: Transform::from_translation(location + ELEVATOR_LOCATION),
759 ..Default::default()
760 },
761 RigidBody::KinematicPositionBased,
762 Collider::cuboid(3. / 2., 1. / 2., 20. / 2.),
763 ElevatorId(i),
764 CollisionGroups::new(BOX_GROUP, Group::ALL),
765 ));
766 }
767
768 commands.spawn((
770 Sensor,
771 Collider::cylinder(0.1, 1.),
772 PbrBundle {
773 mesh: meshs.add(
774 shape::Cylinder {
775 radius: 1.,
776 height: 0.2,
777 ..Default::default()
778 }
779 .into(),
780 ),
781 material: materials.add(Color::RED.into()),
782 transform: Transform::from_translation(
783 Vec3::new(-15., 49. * 5. + 0.05, -15.) + ELEVATOR_LOCATION,
784 ),
785 ..Default::default()
786 },
787 CollisionGroups::new(BOX_GROUP, Group::ALL),
788 ));
789}
790
791fn touch_sensor(
792 mut commands: Commands,
793 sensor: Query<Entity, With<Sensor>>,
794 cube: Query<Entity, With<Cube>>,
795 rapier_context: Res<RapierContext>,
796
797 mut next_state: ResMut<NextState<GameState>>,
798) {
799 let s = sensor.single();
800 let cube = cube.single();
801 if rapier_context.intersection_pair(cube, s) == Some(true) {
802 println!("touch sensor");
803 commands.entity(s).despawn();
804 next_state.set(GameState::Splash);
805 }
806}
807#[derive(Component)]
808struct SuperBall;
809fn spawn_light(
810 commands: &mut Commands<'_, '_>,
811 light_cube: &Handle<Mesh>,
812 light_material: &Handle<StandardMaterial>,
813 meshs: &mut ResMut<'_, Assets<Mesh>>,
814 pink_emit: Handle<StandardMaterial>,
815) {
816 for i in 0..100 {
818 commands.spawn(PbrBundle {
819 mesh: light_cube.clone(),
820 material: light_material.clone(),
821 transform: Transform::from_translation(Vec3::new(i as f32 * 10. - 500., 20., -4490.)),
822 ..Default::default()
823 });
824 }
825 commands.spawn((PbrBundle {
826 mesh: meshs.add(
827 shape::Icosphere {
828 radius: 2.,
829 subdivisions: 4,
830 }
831 .try_into()
832 .unwrap(),
833 ),
834 material: light_material.clone(),
835 transform: Transform::from_translation(Vec3::new(0., 10., -4495.)),
836 ..Default::default()
837 },));
838 commands.spawn(PointLightBundle {
839 point_light: PointLight {
840 color: Color::PINK,
841 intensity: 100000.,
842 range: 200.,
843 ..Default::default()
844 },
845 transform: Transform::from_translation(Vec3::new(0., 10., -4495.)),
846 ..Default::default()
847 });
848
849 commands.spawn((
850 PbrBundle {
851 mesh: meshs.add(
852 shape::Icosphere {
853 radius: 200.,
854 subdivisions: 4,
855 }
856 .try_into()
857 .unwrap(),
858 ),
859 material: pink_emit.clone(),
860 transform: Transform::from_translation(Vec3::new(0., 300., -4295.)),
861 ..Default::default()
862 },
863 SuperBall,
864 ));
865 commands.spawn(PointLightBundle {
866 point_light: PointLight {
867 color: Color::PINK,
868 intensity: 100000.,
869 range: 500.,
870 ..Default::default()
871 },
872 transform: Transform::from_translation(Vec3::new(0., 300., -4295.)),
873 ..Default::default()
874 });
875 }
891
892fn spawn_basic(
893 commands: &mut Commands<'_, '_>,
894 meshs: &mut ResMut<'_, Assets<Mesh>>,
895 debug_material: Handle<StandardMaterial>,
896) {
897 commands.spawn((
899 PbrBundle {
900 mesh: meshs.add(Mesh::from(shape::Plane {
901 size: 10000.0,
902 subdivisions: 0,
903 })),
904 material: debug_material.clone(),
905 ..Default::default()
906 },
907 Collider::halfspace(Vec3::Y).unwrap(),
908 CollisionGroups::new(PLANE_GROUP, Group::ALL),
909 ));
910
911 commands.spawn((
913 Camera3dBundle {
914 transform: Transform::from_xyz(0.0, 5.0, 10.0).looking_to(-Vec3::Z, Vec3::Y),
915 camera: Camera {
916 hdr: true,
917 ..Default::default()
918 },
919 tonemapping: Tonemapping::TonyMcMapface,
920 ..Default::default()
921 },
922 BloomSettings::default(),
923 ThirdPersonCamera {
924 cursor_lock_active: true,
925 cursor_lock_toggle_enabled: true,
926 cursor_lock_key: keyboard::KeyCode::L,
927 zoom_enabled: true,
928 zoom: Zoom::new(8., 10.),
929 ..Default::default()
930 },
931 ));
932
933 commands.insert_resource(AmbientLight {
935 color: Color::WHITE,
936 brightness: 0.4,
937 });
938
939 let positions = [
941 Vec3::new(-10., 2., -30.),
942 Vec3::new(10., 3., -20.),
943 Vec3::new(0., 4., -10.),
944 Vec3::new(0., 4., -5000.),
945 ];
946 let sizes = [1., 2., 3., 1000.];
947 for (mut p, s) in positions.into_iter().zip(sizes) {
948 p.y = s / 2.;
949 commands.spawn((
950 PbrBundle {
951 mesh: meshs.add(Mesh::from(shape::Cube { size: s })),
952 material: debug_material.clone(),
953 transform: Transform::from_translation(p),
954 ..Default::default()
955 },
956 Collider::cuboid(s / 2., s / 2., s / 2.),
957 CollisionGroups::new(BOX_GROUP, Group::ALL),
958 ));
959 }
960}
961
962fn cude_move_gamepad(
963 gamepads: Res<Gamepads>,
964 button_inputs: Res<Input<GamepadButton>>,
965 axes: Res<Axis<GamepadAxis>>,
966 mut cube: Query<
967 (&mut Velocity, &mut Transform, &mut JumpControl, &Cube),
968 Without<ThirdPersonCamera>,
969 >,
970 camera: Query<&Transform, With<ThirdPersonCamera>>,
971) {
972 let (mut velocity, mut transform, mut jump_contorl, cube) = cube.single_mut();
973 let camera = camera.single();
974
975 for game_pad in gamepads.iter() {
976 if button_inputs.just_pressed(GamepadButton::new(game_pad, GamepadButtonType::North)) {
977 transform.translation = Vec3::new(0.0, 5.0, 0.0);
978 }
979 if button_inputs.just_pressed(GamepadButton::new(game_pad, GamepadButtonType::West)) {
980 velocity.linvel.x = 0.;
981 velocity.linvel.z = 0.;
982 }
983 if button_inputs.just_pressed(GamepadButton::new(game_pad, GamepadButtonType::South))
984 && jump_contorl.remaining_jumps > 0
985 {
986 velocity.linvel.y = jump_contorl.jump_speed;
988 jump_contorl.remaining_jumps -= 1;
989 }
990 let left_stick_x = axes.get(GamepadAxis::new(game_pad, GamepadAxisType::LeftStickX));
991 let left_stick_y = axes.get(GamepadAxis::new(game_pad, GamepadAxisType::LeftStickY));
992 match (left_stick_x, left_stick_y) {
993 (Some(x), Some(y)) => {
994 if x.abs() > 0.1 || y.abs() > 0.1 {
995 let max_speed = cube.max_speed;
996 let mut forward_direction = camera.forward();
997 forward_direction.y = 0.;
998 forward_direction = forward_direction.normalize();
999 let mut right_direction = camera.right();
1000 right_direction.y = 0.;
1001 right_direction = right_direction.normalize();
1002
1003 let speed = y * forward_direction + x * right_direction;
1004 let speed = speed * max_speed;
1005 let old_y = velocity.linvel.y;
1006 velocity.linvel = speed;
1007 velocity.linvel.y = old_y;
1008 }
1009 }
1010 _ => {}
1011 };
1012 }
1013}
1014
1015fn cube_move_keyboard(
1016 keyboard_input: Res<Input<keyboard::KeyCode>>,
1017 mut cube: Query<(&mut Transform, &mut Velocity, &Cube), Without<ThirdPersonCamera>>,
1018 camera: Query<&Transform, With<ThirdPersonCamera>>,
1019) {
1020 let (mut transform, mut velocity, cube) = cube.single_mut();
1021 if keyboard_input.just_pressed(keyboard::KeyCode::R) {
1022 transform.translation = Vec3::new(0.0, 5.0 * 50., 0.0);
1023 }
1024 if keyboard_input.just_pressed(KeyCode::ShiftLeft) {
1025 velocity.linvel.x = 0.;
1026 velocity.linvel.z = 0.;
1027 }
1028 let camera = camera.single();
1029 let mut direction = Vec3::ZERO;
1030 let mut forward_direction = camera.forward();
1031 forward_direction.y = 0.;
1032 forward_direction = forward_direction.normalize();
1033 let mut right_direction = camera.right();
1034 right_direction.y = 0.;
1035 right_direction = right_direction.normalize();
1036 let mut moved = false;
1037
1038 if keyboard_input.pressed(keyboard::KeyCode::W) {
1039 direction += forward_direction;
1040 moved = true;
1041 }
1042 if keyboard_input.pressed(keyboard::KeyCode::S) {
1043 direction -= forward_direction;
1044 moved = true;
1045 }
1046 if keyboard_input.pressed(keyboard::KeyCode::A) {
1047 direction -= right_direction;
1048 moved = true;
1049 }
1050 if keyboard_input.pressed(keyboard::KeyCode::D) {
1051 direction += right_direction;
1052 moved = true;
1053 }
1054 if moved {
1055 let old_y = velocity.linvel.y;
1056 velocity.linvel = direction * cube.max_speed;
1057 velocity.linvel.y = old_y;
1058 }
1059}
1060fn cube_jump(
1061 keyboard_input: Res<Input<keyboard::KeyCode>>,
1062 mut cube: Query<(&mut Velocity, &mut JumpControl)>,
1063) {
1064 let (mut v, mut jump) = cube.single_mut();
1065 if keyboard_input.just_pressed(keyboard::KeyCode::Space)
1066 && jump.jump
1067 && jump.remaining_jumps > 0
1068 {
1069 v.linvel.y = jump.jump_speed;
1070 jump.remaining_jumps -= 1;
1071 }
1072}
1073
1074fn reset_jump(
1075 mut cube: Query<(&mut JumpControl, Entity), With<Cube>>,
1076 rapier_context: Res<RapierContext>,
1077) {
1078 let (mut cube, e) = cube.single_mut();
1079
1080 let contacts = rapier_context.contact_pairs_with(e);
1081 for _contact in contacts {
1082 if _contact.has_any_active_contacts() {
1083 cube.remaining_jumps = 2;
1084 return;
1085 }
1086 }
1087}
1088fn uv_debug_texture() -> Image {
1090 const TEXTURE_SIZE: usize = 8;
1091
1092 let mut palette: [u8; 32] = [
1093 255, 102, 159, 255, 255, 159, 102, 255, 236, 255, 102, 255, 121, 255, 102, 255, 102, 255,
1094 198, 255, 102, 198, 255, 255, 121, 102, 255, 255, 236, 102, 255, 255,
1095 ];
1096
1097 let mut texture_data = [0; TEXTURE_SIZE * TEXTURE_SIZE * 4];
1098 for y in 0..TEXTURE_SIZE {
1099 let offset = TEXTURE_SIZE * y * 4;
1100 texture_data[offset..(offset + TEXTURE_SIZE * 4)].copy_from_slice(&palette);
1101 palette.rotate_right(4);
1102 }
1103
1104 Image::new_fill(
1105 Extent3d {
1106 width: TEXTURE_SIZE as u32,
1107 height: TEXTURE_SIZE as u32,
1108 depth_or_array_layers: 1,
1109 },
1110 TextureDimension::D2,
1111 &texture_data,
1112 TextureFormat::Rgba8UnormSrgb,
1113 )
1114}