1use micro_games_kit::{
2 assets::{make_directory_database, ShaderAsset},
3 config::Config,
4 context::GameContext,
5 game::{GameInstance, GameState},
6 third_party::{
7 anim8::{spline::Spline, utils::factor_iter},
8 spitfire_draw::{
9 primitives::PrimitivesEmitter,
10 utils::{Drawable, ShaderRef},
11 },
12 spitfire_glow::graphics::{CameraScaling, Shader},
13 spitfire_input::{
14 ArrayInputCombinator, InputAxisRef, InputConsume, InputMapping, VirtualAxis,
15 },
16 vek::{Rgba, Vec2},
17 },
18 GameLauncher,
19};
20use std::error::Error;
21
22struct State {
23 spline: Spline<[f32; 2]>,
24 mouse_xy: Option<ArrayInputCombinator<2>>,
25}
26
27impl Default for State {
28 fn default() -> Self {
29 Self {
30 spline: Spline::smooth(
31 &[
32 [-100.0, -100.0],
33 [100.0, -100.0],
34 [-100.0, 100.0],
35 [100.0, 100.0],
36 ],
37 1.0,
38 )
39 .unwrap(),
40 mouse_xy: None,
41 }
42 }
43}
44
45impl GameState for State {
46 fn enter(&mut self, context: GameContext) {
47 context.graphics.color = [0.2, 0.2, 0.2, 1.0];
48 context.graphics.main_camera.screen_alignment = 0.5.into();
49 context.graphics.main_camera.scaling = CameraScaling::FitVertical(300.0);
50
51 let pointer_x = InputAxisRef::default();
52 let pointer_y = InputAxisRef::default();
53 self.mouse_xy = Some(ArrayInputCombinator::new([
54 pointer_x.clone(),
55 pointer_y.clone(),
56 ]));
57 context.input.push_mapping(
58 InputMapping::default()
59 .consume(InputConsume::Hit)
60 .axis(VirtualAxis::MousePositionX, pointer_x)
61 .axis(VirtualAxis::MousePositionY, pointer_y),
62 );
63
64 context
65 .assets
66 .spawn(
67 "shader://color",
68 (ShaderAsset::new(
69 Shader::COLORED_VERTEX_2D,
70 Shader::PASS_FRAGMENT,
71 ),),
72 )
73 .unwrap();
74 }
75
76 fn draw(&mut self, context: GameContext) {
77 let emitter = PrimitivesEmitter::default().shader(ShaderRef::name("color"));
78
79 let tint = Rgba::new(0.25, 0.25, 1.0, 1.0);
80 emitter
81 .emit_brush(factor_iter(50).map(|factor| {
82 (
83 self.spline.sample(factor).into(),
84 (1.0 - factor * factor) * 5.0,
85 tint,
86 )
87 }))
88 .draw(context.draw, context.graphics);
89
90 for point in self.spline.points() {
91 emitter
92 .emit_circle(point.point.into(), 2.0, 0.1)
93 .tint(Rgba::new(1.0, 0.25, 0.25, 1.0))
94 .draw(context.draw, context.graphics);
95 }
96
97 if let Some(mouse_xy) = self.mouse_xy.as_ref() {
98 let source = Vec2::from(mouse_xy.get());
99 let source = context
100 .graphics
101 .main_camera
102 .screen_matrix()
103 .mul_point(source);
104 let source = context
105 .graphics
106 .main_camera
107 .world_matrix()
108 .inverted()
109 .mul_point(source);
110 let time = self
111 .spline
112 .find_time_closest_to_point(&source.into_array())
113 .0;
114 let target = Vec2::from(self.spline.sample(time));
115 emitter
116 .emit_circle(target, 3.0, 0.1)
117 .draw(context.draw, context.graphics);
118 emitter
119 .emit_lines([source, target])
120 .draw(context.draw, context.graphics);
121 }
122 }
123}
124
125fn main() -> Result<(), Box<dyn Error>> {
126 GameLauncher::new(GameInstance::new(State::default()).setup_assets(|assets| {
127 *assets = make_directory_database("./resources/").unwrap();
128 }))
129 .title("Path")
130 .config(Config::load_from_file("./resources/GameConfig.toml")?)
131 .run();
132 Ok(())
133}