Skip to main content

gamepad/
gamepad.rs

1use sge::prelude::*;
2use sge_input::gilrs::{Gamepad, GamepadId};
3
4const PRIMARY: Color = Color::WHITE;
5const SECONDARY: Color = Color::WHITE;
6
7#[main("Gamepad")]
8async fn main() -> anyhow::Result<()> {
9    let mut gamepad = None;
10
11    loop {
12        if let Some(pad) = gamepad {
13            visualize_gamepad(pad);
14        } else {
15            gamepad = choose_gamepad();
16        }
17
18        if should_quit() {
19            break;
20        }
21
22        next_frame().await;
23    }
24
25    Ok(())
26}
27
28fn choose_gamepad() -> Option<GamepadId> {
29    let input = gamepad::input();
30    let gamepads: Vec<_> = input.gamepads().collect();
31
32    use ui::prelude::*;
33    let ui = Col::with_gap(
34        10.0,
35        gamepads
36            .iter()
37            .enumerate()
38            .map(|(i, (_, pad))| flat::Button::primary_text(i, pad.name()))
39            .collect::<Vec<_>>(),
40    );
41
42    draw_ui(ui, Vec2::splat(10.0));
43
44    Some(
45        gamepads
46            .get(*all_elements_interacted_this_frame().first()?)?
47            .0,
48    )
49}
50
51fn visualize_gamepad(pad: GamepadId) {
52    let input = gamepad::input();
53    let pad = input.gamepad(pad);
54
55    draw_stick(pad.left_stick(), vec2(150.0, 150.0));
56    draw_stick(pad.right_stick(), vec2(450.0, 450.0));
57
58    draw_dpad(pad, vec2(150.0, 450.0));
59    draw_buttons(pad, vec2(450.0, 150.0));
60}
61
62fn draw_stick(val: Vec2, center: Vec2) {
63    const SIZE: f32 = 100.0;
64    let val = val.invert_y(); // because we draw with positive y-down
65
66    draw_circle_outline(center, SIZE, SECONDARY, 5.0);
67
68    let offset = val * SIZE;
69    draw_circle(center + offset, SIZE / 2.0, PRIMARY);
70
71    draw_text(
72        format!("{}, {}", val.x, val.y),
73        vec2(center.x - SIZE, center.y + SIZE + 20.0),
74    );
75}
76
77// this is extremely ugly im afraid
78fn draw_dpad(pad: Gamepad, center: Vec2) {
79    const SIZE: f32 = 100.0;
80    const THICKNESS: f32 = 65.0;
81    const OUTLINE: f32 = 5.0;
82
83    let half = THICKNESS / 2.0;
84    let half_outline = OUTLINE / 2.0;
85    let arm = SIZE - half;
86
87    let buttons = [
88        (
89            gamepad::Button::DPadUp,
90            vec2(center.x - half, center.y - SIZE),
91            vec2(THICKNESS, arm + half_outline),
92        ),
93        (
94            gamepad::Button::DPadDown,
95            vec2(center.x - half, center.y + half - half_outline),
96            vec2(THICKNESS, arm),
97        ),
98        (
99            gamepad::Button::DPadLeft,
100            vec2(center.x - SIZE, center.y - half),
101            vec2(arm + half_outline, THICKNESS),
102        ),
103        (
104            gamepad::Button::DPadRight,
105            vec2(center.x + half - half_outline, center.y - half),
106            vec2(arm, THICKNESS),
107        ),
108    ];
109
110    let points = [
111        vec2(center.x - half, center.y - SIZE),
112        vec2(center.x + half, center.y - SIZE),
113        vec2(center.x + half, center.y - half),
114        vec2(center.x + SIZE, center.y - half),
115        vec2(center.x + SIZE, center.y + half),
116        vec2(center.x + half, center.y + half),
117        vec2(center.x + half, center.y + SIZE),
118        vec2(center.x - half, center.y + SIZE),
119        vec2(center.x - half, center.y + half),
120        vec2(center.x - SIZE, center.y + half),
121        vec2(center.x - SIZE, center.y - half),
122        vec2(center.x - half, center.y - half),
123        vec2(center.x - half, center.y - SIZE),
124    ];
125
126    draw_connected_path(&points, OUTLINE, SECONDARY);
127
128    for (button, pos, size) in buttons {
129        if pad.is_pressed(button) {
130            draw_rect(pos, size, PRIMARY);
131        }
132    }
133}
134
135fn draw_buttons(pad: Gamepad, center: Vec2) {
136    const RADIUS: f32 = 30.0;
137    const DIST: f32 = 70.0;
138    const OUTLINE: f32 = 5.0;
139
140    let buttons = [
141        (gamepad::Button::North, vec2(center.x, center.y - DIST)),
142        (gamepad::Button::South, vec2(center.x, center.y + DIST)),
143        (gamepad::Button::West, vec2(center.x - DIST, center.y)),
144        (gamepad::Button::East, vec2(center.x + DIST, center.y)),
145    ];
146
147    for (button, pos) in buttons {
148        if pad.is_pressed(button) {
149            draw_circle(pos, RADIUS + OUTLINE, PRIMARY);
150        } else {
151            draw_circle_outline(pos, RADIUS, SECONDARY, OUTLINE);
152        }
153    }
154}