Use GameControllers instead of Joysticks
[kaka/rust-sdl-test.git] / src / core / controller.rs
... / ...
CommitLineData
1use geometry::{Angle, ToAngle, Point};
2use sdl2::GameControllerSubsystem;
3use sdl2::HapticSubsystem;
4use sdl2::controller::{GameController, Axis as SDLAxis, Button as SDLButton};
5use sdl2::event::Event;
6use sdl2::haptic::Haptic;
7use std::cell::RefCell;
8use std::collections::HashMap;
9use std::rc::Rc;
10use time::{Duration, prelude::*};
11use {hashmap, point};
12
13#[derive(Debug)]
14pub struct Button {
15 id: SDLButton,
16 pub time_pressed: Duration,
17 pub time_released: Duration,
18 pub is_pressed: bool,
19 pub was_pressed: bool,
20 pub toggle: bool,
21}
22
23impl Button {
24 pub fn new(id: SDLButton) -> Self {
25 Button {
26 id,
27 time_pressed: Duration::zero(),
28 time_released: Duration::zero(),
29 is_pressed: false,
30 was_pressed: false,
31 toggle: false,
32 }
33 }
34
35 fn update(&mut self, device: &GameController, dt: Duration) {
36 self.was_pressed = self.is_pressed;
37 self.is_pressed = match device.button(self.id) {
38 true => {
39 if !self.was_pressed {
40 self.time_pressed = 0.seconds();
41 self.toggle = !self.toggle;
42 }
43 self.time_pressed += dt;
44 true
45 }
46 false => {
47 if self.was_pressed {
48 self.time_released = 0.seconds();
49 }
50 self.time_released += dt;
51 false
52 }
53 }
54 }
55}
56
57#[derive(Debug)]
58pub struct Axis {
59 id: SDLAxis,
60 pub val: f32,
61}
62
63impl Axis {
64 #[allow(dead_code)]
65 fn update(&mut self, device: &GameController, _dt: Duration) {
66 self.val = device.axis(self.id) as f32 / 32768.0;
67 }
68}
69
70#[derive(Debug)]
71pub struct Stick {
72 id: (SDLAxis, SDLAxis),
73 pub x: f32,
74 pub y: f32,
75 pub a: Angle,
76}
77
78impl Stick {
79 pub fn new(idx: SDLAxis, idy: SDLAxis) -> Self {
80 Stick {
81 id: (idx, idy),
82 x: 0.0,
83 y: 0.0,
84 a: 0.radians(),
85 }
86 }
87
88 fn update(&mut self, device: &GameController, _dt: Duration) {
89 self.x = device.axis(self.id.0) as f32 / 32768.0;
90 self.y = device.axis(self.id.1) as f32 / 32768.0;
91 self.a = point!(self.x as f64, self.y as f64).to_angle();
92 }
93
94 #[inline(always)] #[allow(dead_code)] pub fn up(&self) -> bool { self.y < -0.99 }
95 #[inline(always)] #[allow(dead_code)] pub fn down(&self) -> bool { self.y > 0.99 }
96 #[inline(always)] #[allow(dead_code)] pub fn left(&self) -> bool { self.x < -0.99 }
97 #[inline(always)] #[allow(dead_code)] pub fn right(&self) -> bool { self.x > 0.99 }
98
99 pub fn to_axis_point(&self) -> Point<f64> {
100 point!(self.x as f64, self.y as f64)
101 }
102
103 pub fn to_point(&self) -> Point<f64> {
104 let p = point!(self.x as f64, self.y as f64);
105 if p.length() > 1.0 {
106 p.normalized()
107 } else {
108 p
109 }
110 }
111}
112
113impl From<&Stick> for Point<f64> {
114 fn from(item: &Stick) -> Self {
115 Self {
116 x: item.x as f64,
117 y: item.y as f64,
118 }
119 }
120}
121
122impl From<&Stick> for (f64, f64) {
123 fn from(item: &Stick) -> Self {
124 (item.x as f64, item.y as f64)
125 }
126}
127
128#[derive(Eq, PartialEq, Hash)]
129enum ActionControls {
130 MovementX,
131 MovementY,
132 AimX,
133 AimY,
134 Jump,
135 Shoot,
136 Start,
137}
138use self::ActionControls::*;
139
140//#[derive(Debug)]
141pub struct Controller {
142 pub device: GameController,
143 haptic: Option<Rc<RefCell<Haptic>>>,
144
145 pub mov: Stick,
146 pub aim: Stick,
147 pub jump: Button,
148 pub start: Button,
149 pub shoot: Button,
150}
151
152impl Controller {
153 pub fn new(device: GameController, haptic: Option<Rc<RefCell<Haptic>>>) -> Self {
154 let map = get_action_mapping();
155 let mut ctrl = Controller {
156 device,
157 haptic,
158 mov: Stick::new(*map.axes.get(&MovementX).unwrap(), *map.axes.get(&MovementY).unwrap()),
159 aim: Stick::new(*map.axes.get(&AimX).unwrap(), *map.axes.get(&AimY).unwrap()),
160 jump: Button::new(*map.buttons.get(&Jump).unwrap()),
161 start: Button::new(*map.buttons.get(&Start).unwrap()),
162 shoot: Button::new(*map.buttons.get(&Shoot).unwrap()),
163 };
164 ctrl.set_mapping(&map);
165 ctrl
166 }
167
168 fn set_mapping(&mut self, map: &ActionMapping) {
169 self.mov.id.0 = *map.axes.get(&MovementX).unwrap();
170 self.mov.id.1 = *map.axes.get(&MovementY).unwrap();
171 self.aim.id.0 = *map.axes.get(&AimX).unwrap();
172 self.aim.id.1 = *map.axes.get(&AimY).unwrap();
173 self.jump.id = *map.buttons.get(&Jump).unwrap();
174 self.shoot.id = *map.buttons.get(&Shoot).unwrap();
175 self.start.id = *map.buttons.get(&Start).unwrap();
176 }
177
178 pub fn update(&mut self, dt: Duration) {
179 self.mov.update(&self.device, dt);
180 self.aim.update(&self.device, dt);
181 self.jump.update(&self.device, dt);
182 self.shoot.update(&self.device, dt);
183 self.start.update(&self.device, dt);
184 }
185
186 /// strength [0 - 1]
187 pub fn rumble(&self, strength: f32, duration: Duration) {
188 if let Some(h) = &self.haptic {
189 h.borrow_mut().rumble_play(strength, duration.whole_milliseconds() as u32);
190 }
191 }
192}
193
194struct ActionMapping {
195 axes: HashMap<ActionControls, SDLAxis>,
196 buttons: HashMap<ActionControls, SDLButton>,
197}
198
199fn get_action_mapping() -> ActionMapping {
200 ActionMapping {
201 axes: hashmap!(
202 MovementX => SDLAxis::LeftX,
203 MovementY => SDLAxis::LeftY,
204 AimX => SDLAxis::RightX,
205 AimY => SDLAxis::RightY
206 ),
207 buttons: hashmap!(
208 Jump => SDLButton::A,
209 Shoot => SDLButton::RightShoulder,
210 Start => SDLButton::Start
211 )
212 }
213}
214
215//#[derive(Debug)]
216pub struct ControllerManager {
217 pub subsystem: GameControllerSubsystem,
218 haptic: Rc<HapticSubsystem>,
219 pub controllers: HashMap<u32, Rc<RefCell<Controller>>>,
220}
221
222impl ControllerManager {
223 pub fn new(subsystem: GameControllerSubsystem, haptic: HapticSubsystem) -> Self {
224 subsystem.set_event_state(true);
225 let mut c = ControllerManager {
226 subsystem,
227 haptic: Rc::new(haptic),
228 controllers: HashMap::new(),
229 };
230 c.init();
231 c
232 }
233
234 fn init(&mut self) {
235 for i in 0..self.subsystem.num_joysticks().unwrap() {
236 self.add_device(i);
237 }
238 }
239
240 pub fn update(&mut self, dt: Duration) {
241 self.controllers.iter().for_each(|(_, v)| v.borrow_mut().update(dt));
242 }
243
244 pub fn handle_event(&mut self, event: &Event) {
245 match event {
246 Event::ControllerDeviceAdded { which, .. } => { self.add_device(*which) }
247 Event::ControllerDeviceRemoved { which, .. } => { self.remove_device(*which) }
248 // Event::ControllerButtonDown { which, button_idx, .. } => { println!("device {} button {} down!", which, button_idx) }
249 // Event::ControllerButtonUp { which, button_idx, .. } => { println!("device {} button {} up!", which, button_idx) }
250 // Event::ControllerAxisMotion { which, axis_idx, .. } => { println!("device {} axis motion {}!", which, axis_idx) }
251 _ => {}
252 }
253 }
254
255 fn add_device(&mut self, id: u32) {
256 println!("device added ({})!", id);
257 let mut device = self.subsystem.open(id).unwrap();
258 println!("opened {}", device.name());
259
260 /*
261 note about set_rumble (for dualshock 3 at least):
262 the active range for the low frequency is from 65536/4 to 65536 and escalates in large steps throughout the range
263 the active range for the high frequency is from 256 to 65536 and effect is the same throughout the whole range
264 */
265 let haptic = match device.set_rumble(0, 256, 100) {
266 Ok(_) => self.haptic.open_from_joystick_id(id).ok(),
267 Err(_) => None
268 };
269
270 if self.controllers.contains_key(&id) {
271 return;
272 }
273
274 let detached = self.controllers.values().find(|c| !c.borrow().device.attached());
275 match detached {
276 Some(c) => {
277 let mut c = c.borrow_mut();
278 c.device = device;
279 c.haptic = haptic.map(|h| Rc::new(RefCell::new(h)));
280 }
281 None => {
282 let c = Rc::new(RefCell::new(Controller::new(device, haptic.map(|h| Rc::new(RefCell::new(h))))));
283 self.controllers.insert(id, c);
284 }
285 };
286 }
287
288 fn remove_device(&mut self, id: i32) {
289 println!("device removed ({})!", id);
290 // TODO
291 }
292}