Skip to main content

hello_world/
hello_world.rs

1use quaso::{
2    GameLauncher,
3    animation::frame::SpriteFrameAnimation,
4    assets::{anim_texture::AnimTextureAsset, make_directory_database, shader::ShaderAsset},
5    config::Config,
6    context::GameContext,
7    game::{GameInstance, GameState, GameStateChange},
8    third_party::{
9        raui_core::{
10            layout::CoordsMappingScaling,
11            widget::{
12                component::text_box::TextBoxProps,
13                unit::text::{TextBoxFont, TextBoxHorizontalAlign, TextBoxVerticalAlign},
14                utils::Color,
15            },
16        },
17        raui_immediate_widgets::core::text_box,
18        spitfire_draw::{
19            sprite::{Sprite, SpriteTexture},
20            utils::{Drawable, TextureRef},
21        },
22        spitfire_glow::{
23            graphics::{CameraScaling, Shader},
24            renderer::GlowTextureFiltering,
25        },
26        spitfire_input::{
27            CardinalInputCombinator, InputActionRef, InputConsume, InputMapping, VirtualAction,
28        },
29        vek::Vec2,
30        windowing::event::VirtualKeyCode,
31    },
32};
33use std::error::Error;
34
35const SPEED: f32 = 100.0;
36
37fn main() -> Result<(), Box<dyn Error>> {
38    GameLauncher::new(GameInstance::new(Preloader).setup_assets(|assets| {
39        *assets = make_directory_database("./resources/").unwrap();
40    }))
41    .title("Hello World!")
42    .config(Config::load_from_file("./resources/GameConfig.toml")?)
43    .run();
44    Ok(())
45}
46
47#[derive(Default)]
48struct Preloader;
49
50impl GameState for Preloader {
51    fn enter(&mut self, context: GameContext) {
52        context.graphics.state.color = [0.2, 0.2, 0.2, 1.0];
53        context.graphics.state.main_camera.screen_alignment = 0.5.into();
54        context.graphics.state.main_camera.scaling = CameraScaling::FitVertical(500.0);
55        context.gui.coords_map_scaling = CoordsMappingScaling::FitVertical(500.0);
56
57        context
58            .assets
59            .spawn(
60                "shader://color",
61                (ShaderAsset::new(
62                    Shader::COLORED_VERTEX_2D,
63                    Shader::PASS_FRAGMENT,
64                ),),
65            )
66            .unwrap();
67        context
68            .assets
69            .spawn(
70                "shader://image",
71                (ShaderAsset::new(
72                    Shader::TEXTURED_VERTEX_2D,
73                    Shader::TEXTURED_FRAGMENT,
74                ),),
75            )
76            .unwrap();
77        context
78            .assets
79            .spawn(
80                "shader://text",
81                (ShaderAsset::new(Shader::TEXT_VERTEX, Shader::TEXT_FRAGMENT),),
82            )
83            .unwrap();
84
85        context.assets.ensure("font://roboto.ttf").unwrap();
86
87        context
88            .assets
89            .ensure("animtexture://ferris-bongo.gif")
90            .unwrap();
91    }
92
93    fn update(&mut self, context: GameContext, _: f32) {
94        if !context.assets.is_busy() {
95            *context.state_change = GameStateChange::Swap(Box::new(State::default()));
96        }
97    }
98}
99
100#[derive(Default)]
101struct State {
102    ferris: Sprite,
103    ferris_anim: SpriteFrameAnimation,
104    movement: CardinalInputCombinator,
105    exit: InputActionRef,
106}
107
108impl GameState for State {
109    fn enter(&mut self, context: GameContext) {
110        self.ferris = Sprite::single(SpriteTexture {
111            sampler: "u_image".into(),
112            texture: TextureRef::name(""),
113            filtering: GlowTextureFiltering::Linear,
114        })
115        .pivot(0.5.into());
116
117        self.ferris_anim = context
118            .assets
119            .ensure("animtexture://ferris-bongo.gif")
120            .unwrap()
121            .access::<&AnimTextureAsset>(context.assets)
122            .build_animation(TextureRef::name("ferris-bongo.gif"));
123        self.ferris_anim.animation.speed = 0.5;
124        self.ferris_anim.animation.looping = true;
125        self.ferris_anim.animation.play();
126
127        let move_left = InputActionRef::default();
128        let move_right = InputActionRef::default();
129        let move_up = InputActionRef::default();
130        let move_down = InputActionRef::default();
131        self.movement = CardinalInputCombinator::new(
132            move_left.clone(),
133            move_right.clone(),
134            move_up.clone(),
135            move_down.clone(),
136        );
137        context.input.push_mapping(
138            InputMapping::default()
139                .consume(InputConsume::Hit)
140                .action(
141                    VirtualAction::KeyButton(VirtualKeyCode::A),
142                    move_left.clone(),
143                )
144                .action(
145                    VirtualAction::KeyButton(VirtualKeyCode::D),
146                    move_right.clone(),
147                )
148                .action(VirtualAction::KeyButton(VirtualKeyCode::W), move_up.clone())
149                .action(
150                    VirtualAction::KeyButton(VirtualKeyCode::S),
151                    move_down.clone(),
152                )
153                .action(VirtualAction::KeyButton(VirtualKeyCode::Left), move_left)
154                .action(VirtualAction::KeyButton(VirtualKeyCode::Right), move_right)
155                .action(VirtualAction::KeyButton(VirtualKeyCode::Up), move_up)
156                .action(VirtualAction::KeyButton(VirtualKeyCode::Down), move_down)
157                .action(
158                    VirtualAction::KeyButton(VirtualKeyCode::Escape),
159                    self.exit.clone(),
160                ),
161        );
162    }
163
164    fn exit(&mut self, context: GameContext) {
165        context.input.pop_mapping();
166    }
167
168    fn fixed_update(&mut self, context: GameContext, delta_time: f32) {
169        self.ferris_anim.animation.update(delta_time);
170        self.ferris_anim.apply_to_sprite(&mut self.ferris, 0);
171
172        let movement = Vec2::<f32>::from(self.movement.get());
173        self.ferris.transform.position += movement * SPEED * delta_time;
174
175        if self.exit.get().is_pressed() {
176            *context.state_change = GameStateChange::Pop;
177        }
178    }
179
180    fn draw(&mut self, context: GameContext) {
181        self.ferris.draw(context.draw, context.graphics);
182    }
183
184    fn draw_gui(&mut self, _: GameContext) {
185        text_box(TextBoxProps {
186            text: "Hello, World!".to_owned(),
187            horizontal_align: TextBoxHorizontalAlign::Center,
188            vertical_align: TextBoxVerticalAlign::Bottom,
189            font: TextBoxFont {
190                name: "roboto.ttf".to_owned(),
191                size: 50.0,
192            },
193            color: Color {
194                r: 1.0,
195                g: 1.0,
196                b: 0.0,
197                a: 1.0,
198            },
199            ..Default::default()
200        });
201    }
202}