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