1use quaso::{
2 GameLauncher,
3 assets::{make_directory_database, shader::ShaderAsset},
4 config::Config,
5 context::GameContext,
6 game::{GameInstance, GameObject, GameState, GameStateChange},
7 gc::Gc,
8 third_party::{
9 spitfire_draw::{
10 sprite::Sprite,
11 utils::{Drawable, ShaderRef},
12 },
13 spitfire_glow::graphics::{CameraScaling, Shader},
14 spitfire_input::{
15 CardinalInputCombinator, InputActionRef, InputConsume, InputMapping, VirtualAction,
16 VirtualKeyCode,
17 },
18 vek::{Rgba, Vec2},
19 },
20};
21use std::error::Error;
22
23fn main() -> Result<(), Box<dyn Error>> {
32 GameLauncher::new(GameInstance::new(Preloader).setup_assets(|assets| {
33 *assets = make_directory_database("./resources/").unwrap();
34 }))
35 .title("GC")
36 .config(Config::load_from_file("./resources/GameConfig.toml")?)
37 .run();
38 Ok(())
39}
40
41#[derive(Default)]
42struct Preloader;
43
44impl GameState for Preloader {
45 fn enter(&mut self, context: GameContext) {
46 context.graphics.state.color = [0.2, 0.2, 0.2, 1.0];
47 context.graphics.state.main_camera.screen_alignment = 0.5.into();
48 context.graphics.state.main_camera.scaling = CameraScaling::FitVertical(500.0);
49
50 context
51 .assets
52 .spawn(
53 "shader://color",
54 (ShaderAsset::new(
55 Shader::COLORED_VERTEX_2D,
56 Shader::PASS_FRAGMENT,
57 ),),
58 )
59 .unwrap();
60 context
61 .assets
62 .spawn(
63 "shader://image",
64 (ShaderAsset::new(
65 Shader::TEXTURED_VERTEX_2D,
66 Shader::TEXTURED_FRAGMENT,
67 ),),
68 )
69 .unwrap();
70 context
71 .assets
72 .spawn(
73 "shader://text",
74 (ShaderAsset::new(Shader::TEXT_VERTEX, Shader::TEXT_FRAGMENT),),
75 )
76 .unwrap();
77 }
78
79 fn update(&mut self, context: GameContext, _: f32) {
80 if !context.assets.is_busy() {
81 *context.state_change = GameStateChange::Swap(Box::new(State::default()));
82 }
83 }
84}
85
86#[derive(Default)]
87struct State {
88 player_controller: Option<Gc<PlayerController>>,
90 actors: Vec<Gc<Actor>>,
92 switch: InputActionRef,
93 exit: InputActionRef,
94 spawn: InputActionRef,
95 destroy: InputActionRef,
96}
97
98impl GameState for State {
99 fn enter(&mut self, context: GameContext) {
100 let move_left = InputActionRef::default();
101 let move_right = InputActionRef::default();
102 let move_up = InputActionRef::default();
103 let move_down = InputActionRef::default();
104
105 context.input.push_mapping(
106 InputMapping::default()
107 .consume(InputConsume::Hit)
108 .action(
109 VirtualAction::KeyButton(VirtualKeyCode::A),
110 move_left.clone(),
111 )
112 .action(
113 VirtualAction::KeyButton(VirtualKeyCode::D),
114 move_right.clone(),
115 )
116 .action(VirtualAction::KeyButton(VirtualKeyCode::W), move_up.clone())
117 .action(
118 VirtualAction::KeyButton(VirtualKeyCode::S),
119 move_down.clone(),
120 )
121 .action(
122 VirtualAction::KeyButton(VirtualKeyCode::Left),
123 move_left.clone(),
124 )
125 .action(
126 VirtualAction::KeyButton(VirtualKeyCode::Right),
127 move_right.clone(),
128 )
129 .action(
130 VirtualAction::KeyButton(VirtualKeyCode::Up),
131 move_up.clone(),
132 )
133 .action(
134 VirtualAction::KeyButton(VirtualKeyCode::Down),
135 move_down.clone(),
136 )
137 .action(
138 VirtualAction::KeyButton(VirtualKeyCode::Space),
139 self.switch.clone(),
140 )
141 .action(
142 VirtualAction::KeyButton(VirtualKeyCode::Insert),
143 self.spawn.clone(),
144 )
145 .action(
146 VirtualAction::KeyButton(VirtualKeyCode::Delete),
147 self.destroy.clone(),
148 )
149 .action(
150 VirtualAction::KeyButton(VirtualKeyCode::Escape),
151 self.exit.clone(),
152 ),
153 );
154
155 self.player_controller = Some(Gc::new(PlayerController {
157 movement_input: CardinalInputCombinator::new(move_left, move_right, move_up, move_down),
158 controls: None,
159 }));
160
161 self.spawn_actor(Vec2::new(-100.0, 0.0), 150.0);
162 self.spawn_actor(Vec2::new(100.0, 0.0), 100.0);
163 }
164
165 fn exit(&mut self, context: GameContext) {
166 context.input.pop_mapping();
167 }
168
169 fn fixed_update(&mut self, mut context: GameContext, delta_time: f32) {
170 if let Some(controller) = &mut self.player_controller {
171 controller.write().process(&mut context, delta_time);
173 }
174
175 for actor in &mut self.actors {
176 actor.write().process(&mut context, delta_time);
177 }
178
179 if self.switch.get().is_pressed() {
180 self.switch_to_next();
181 } else if self.spawn.get().is_pressed() {
182 self.spawn_actor(Default::default(), 100.0);
183 } else if self.destroy.get().is_pressed() {
184 self.destroy_current();
185 }
186
187 if self.exit.get().is_pressed() {
188 *context.state_change = GameStateChange::Pop;
189 }
190 }
191
192 fn draw(&mut self, mut context: GameContext) {
193 for actor in &mut self.actors {
194 actor.write().draw(&mut context);
195 }
196
197 if let Some(controller) = &mut self.player_controller {
198 controller.write().draw(&mut context);
199 }
200 }
201}
202
203impl State {
204 fn switch_to_next(&mut self) {
205 if !self.actors.is_empty()
206 && let Some(controller) = &mut self.player_controller
207 {
208 let controller = &mut *controller.write();
209 if let Some(current) = &controller.controls {
210 if let Some(index) = self.actors.iter().position(|a| Gc::ptr_eq(a, current)) {
212 let next = self.actors[(index + 1) % self.actors.len()].reference();
213 controller.controls = Some(next);
214 } else {
215 controller.controls = Some(self.actors[0].reference());
216 }
217 }
218 }
219 }
220
221 fn spawn_actor(&mut self, position: Vec2<f32>, speed: f32) {
222 let actor = Gc::new(Actor {
223 sprite: Sprite::default()
224 .shader(ShaderRef::name("color"))
225 .position(position)
226 .size(50.0.into())
227 .pivot(0.5.into())
228 .tint(Rgba::red()),
229 speed,
230 });
231 if let Some(controller) = &mut self.player_controller {
232 controller.write().controls = Some(actor.reference());
233 }
234 self.actors.push(actor);
235 }
236
237 fn destroy_current(&mut self) {
238 let switch = if let Some(controller) = &mut self.player_controller {
239 let controller = &mut *controller.write();
240 if let Some(current) = &controller.controls {
241 self.actors.retain(|actor| !Gc::ptr_eq(actor, current));
245 true
246 } else {
247 false
248 }
249 } else {
250 false
251 };
252 if switch {
253 self.switch_to_next();
254 }
255 }
256}
257
258struct Actor {
259 sprite: Sprite,
260 speed: f32,
261}
262
263impl GameObject for Actor {
264 fn draw(&mut self, context: &mut GameContext) {
265 self.sprite.draw(context.draw, context.graphics);
266 }
267}
268
269struct PlayerController {
270 pub movement_input: CardinalInputCombinator,
271 pub controls: Option<Gc<Actor>>,
272}
273
274impl GameObject for PlayerController {
275 fn process(&mut self, _: &mut GameContext, delta_time: f32) {
276 if let Some(actor) = &mut self.controls {
277 let mut actor = actor.write();
278 let movement = Vec2::from(self.movement_input.get()) * actor.speed * delta_time;
279 actor.sprite.transform.position += movement;
280 }
281 }
282
283 fn draw(&mut self, context: &mut GameContext) {
284 if let Some(actor) = &mut self.controls {
285 Sprite::default()
286 .shader(ShaderRef::name("color"))
287 .position(actor.read().sprite.transform.position.into())
288 .size(10.0.into())
289 .pivot(0.5.into())
290 .tint(Rgba::blue())
291 .draw(context.draw, context.graphics);
292 }
293 }
294}