Browse Source

bug fix: multiple requestAnimationFrame calls

Inderjit Gill 6 months ago
parent
commit
48b7286259
5 changed files with 229 additions and 137 deletions
  1. BIN
      research/tileset.pdn
  2. 65
    113
      src/controller.rs
  3. 153
    21
      src/game.rs
  4. 11
    3
      src/lib.rs
  5. BIN
      web/img/tileset.png

BIN
research/tileset.pdn View File


+ 65
- 113
src/controller.rs View File

@@ -23,10 +23,8 @@ pub struct Controller {
23 23
     pub down: bool,
24 24
     pub left: bool,
25 25
     pub right: bool,
26
-
27 26
     pub a: bool,
28 27
     pub b: bool,
29
-
30 28
     pub start: bool,
31 29
     pub select: bool,
32 30
 
@@ -38,28 +36,6 @@ pub struct Controller {
38 36
     b_previous: bool,
39 37
     start_previous: bool,
40 38
     select_previous: bool,
41
-
42
-    pub up_just_released: bool,
43
-    pub down_just_released: bool,
44
-    pub left_just_released: bool,
45
-    pub right_just_released: bool,
46
-
47
-    pub a_just_released: bool,
48
-    pub b_just_released: bool,
49
-
50
-    pub start_just_released: bool,
51
-    pub select_just_released: bool,
52
-
53
-    pub up_just_pressed: bool,
54
-    pub down_just_pressed: bool,
55
-    pub left_just_pressed: bool,
56
-    pub right_just_pressed: bool,
57
-
58
-    pub a_just_pressed: bool,
59
-    pub b_just_pressed: bool,
60
-
61
-    pub start_just_pressed: bool,
62
-    pub select_just_pressed: bool,
63 39
 }
64 40
 
65 41
 impl Controller {
@@ -82,45 +58,77 @@ impl Controller {
82 58
             b_previous: false,
83 59
             start_previous: false,
84 60
             select_previous: false,
61
+        }
62
+    }
85 63
 
86
-            up_just_released: false,
87
-            down_just_released: false,
88
-            left_just_released: false,
89
-            right_just_released: false,
90
-            a_just_released: false,
91
-            b_just_released: false,
92
-            start_just_released: false,
93
-            select_just_released: false,
64
+    pub fn reset_controller(&mut self) {
65
+        self.up_previous = self.up;
66
+        self.down_previous = self.down;
67
+        self.left_previous = self.left;
68
+        self.right_previous = self.right;
69
+        self.a_previous = self.a;
70
+        self.b_previous = self.b;
71
+        self.start_previous = self.start;
72
+        self.select_previous = self.select;
73
+    }
94 74
 
95
-            up_just_pressed: false,
96
-            down_just_pressed: false,
97
-            left_just_pressed: false,
98
-            right_just_pressed: false,
99
-            a_just_pressed: false,
100
-            b_just_pressed: false,
101
-            start_just_pressed: false,
102
-            select_just_pressed: false,
75
+    pub fn just_released(&self, button: ControllerButton) -> bool {
76
+        match button {
77
+            ControllerButton::Left => {
78
+                !self.left && self.left_previous
79
+            },
80
+            ControllerButton::Right => {
81
+                !self.right && self.right_previous
82
+            },
83
+            ControllerButton::Up => {
84
+                !self.up && self.up_previous
85
+            },
86
+            ControllerButton::Down => {
87
+                !self.down && self.down_previous
88
+            },
89
+            ControllerButton::A => {
90
+                !self.a && self.a_previous
91
+            },
92
+            ControllerButton::B => {
93
+                !self.b && self.b_previous
94
+            },
95
+            ControllerButton::Start => {
96
+                !self.start && self.start_previous
97
+            },
98
+            ControllerButton::Select => {
99
+                !self.select && self.select_previous
100
+            },
103 101
         }
104 102
     }
105 103
 
106
-    pub fn reset_controller(&mut self) {
107
-        self.up_just_released = false;
108
-        self.down_just_released = false;
109
-        self.left_just_released = false;
110
-        self.right_just_released = false;
111
-        self.a_just_released = false;
112
-        self.b_just_released = false;
113
-        self.start_just_released = false;
114
-        self.select_just_released = false;
115 104
 
116
-        self.up_just_pressed = false;
117
-        self.down_just_pressed = false;
118
-        self.left_just_pressed = false;
119
-        self.right_just_pressed = false;
120
-        self.a_just_pressed = false;
121
-        self.b_just_pressed = false;
122
-        self.start_just_pressed = false;
123
-        self.select_just_pressed = false;
105
+    pub fn just_pressed(&self, button: ControllerButton) -> bool {
106
+        match button {
107
+            ControllerButton::Left => {
108
+                self.left && !self.left_previous
109
+            },
110
+            ControllerButton::Right => {
111
+                self.right && !self.right_previous
112
+            },
113
+            ControllerButton::Up => {
114
+                self.up && !self.up_previous
115
+            },
116
+            ControllerButton::Down => {
117
+                self.down && !self.down_previous
118
+            },
119
+            ControllerButton::A => {
120
+                self.a && !self.a_previous
121
+            },
122
+            ControllerButton::B => {
123
+                self.b && !self.b_previous
124
+            },
125
+            ControllerButton::Start => {
126
+                self.start && !self.start_previous
127
+            },
128
+            ControllerButton::Select => {
129
+                self.select && !self.select_previous
130
+            },
131
+        }
124 132
     }
125 133
 
126 134
     pub fn input(&mut self, button: ControllerButton, action: ControllerAction) {
@@ -136,83 +144,27 @@ impl Controller {
136 144
         match button {
137 145
             ControllerButton::Left => {
138 146
                 self.left = self.bool_from_action(action);
139
-
140
-                if self.left == true && self.left_previous == false {
141
-                    self.left_just_pressed = true;
142
-                }
143
-                if self.left == false && self.left_previous == true {
144
-                    self.left_just_released = true;
145
-                }
146 147
             },
147 148
             ControllerButton::Right => {
148 149
                 self.right = self.bool_from_action(action);
149
-
150
-                if self.right == true && self.right_previous == false {
151
-                    self.right_just_pressed = true;
152
-                }
153
-                if self.right == false && self.right_previous == true {
154
-                    self.right_just_released = true;
155
-                }
156 150
             },
157 151
             ControllerButton::Up => {
158 152
                 self.up = self.bool_from_action(action);
159
-
160
-                if self.up == true && self.up_previous == false {
161
-                    self.up_just_pressed = true;
162
-                }
163
-                if self.up == false && self.up_previous == true {
164
-                    self.up_just_released = true;
165
-                }
166 153
             },
167 154
             ControllerButton::Down => {
168 155
                 self.down = self.bool_from_action(action);
169
-
170
-                if self.down == true && self.down_previous == false {
171
-                    self.down_just_pressed = true;
172
-                }
173
-                if self.down == false && self.down_previous == true {
174
-                    self.down_just_released = true;
175
-                }
176 156
             },
177 157
             ControllerButton::A => {
178 158
                 self.a = self.bool_from_action(action);
179
-
180
-                if self.a == true && self.a_previous == false {
181
-                    self.a_just_pressed = true;
182
-                }
183
-                if self.a == false && self.a_previous == true {
184
-                    self.a_just_released = true;
185
-                }
186 159
             },
187 160
             ControllerButton::B => {
188 161
                 self.b = self.bool_from_action(action);
189
-
190
-                if self.b == true && self.b_previous == false {
191
-                    self.b_just_pressed = true;
192
-                }
193
-                if self.b == false && self.b_previous == true {
194
-                    self.b_just_released = true;
195
-                }
196 162
             },
197 163
             ControllerButton::Start => {
198 164
                 self.start = self.bool_from_action(action);
199
-
200
-                if self.start == true && self.start_previous == false {
201
-                    self.start_just_pressed = true;
202
-                }
203
-                if self.start == false && self.start_previous == true {
204
-                    self.start_just_released = true;
205
-                }
206 165
             },
207 166
             ControllerButton::Select => {
208 167
                 self.select = self.bool_from_action(action);
209
-
210
-                if self.select == true && self.select_previous == false {
211
-                    self.select_just_pressed = true;
212
-                }
213
-                if self.select == false && self.select_previous == true {
214
-                    self.select_just_released = true;
215
-                }
216 168
             },
217 169
         };
218 170
     }

+ 153
- 21
src/game.rs View File

@@ -1,4 +1,4 @@
1
-use controller::{Controller, ControllerAction, ControllerButton};
1
+use controller::{Controller, ControllerButton};
2 2
 use error;
3 3
 use geometry::Geometry;
4 4
 use log;
@@ -180,8 +180,14 @@ pub struct Game {
180 180
     colour_saturation: f64,
181 181
     colour_lightness: f64,
182 182
 
183
+    menu_num_items: i32,
183 184
     menu_active_item: i32,
184 185
     menu_volume: i32,
186
+    menu_max_volume: i32,
187
+    menu_crt_update_speed: i32,
188
+    menu_max_crt_update_speed: i32,
189
+    menu_curvature: i32,
190
+    menu_max_curvature: i32,
185 191
 
186 192
     is_game_over: bool,
187 193
 
@@ -209,6 +215,9 @@ pub struct Game {
209 215
     s_count: i32,
210 216
     t_count: i32,
211 217
     z_count: i32,
218
+
219
+    debug_flash: bool,
220
+    debug_delta: f32,
212 221
 }
213 222
 
214 223
 impl Game {
@@ -236,8 +245,17 @@ impl Game {
236 245
             colour_saturation: config.colour_saturation,
237 246
             colour_lightness: config.colour_lightness,
238 247
 
248
+            menu_num_items: 5,
239 249
             menu_active_item: 0,
250
+
240 251
             menu_volume: 4,
252
+            menu_max_volume: 5,
253
+
254
+            menu_crt_update_speed: 4,
255
+            menu_max_crt_update_speed: 5,
256
+
257
+            menu_curvature: 3,
258
+            menu_max_curvature: 5,
241 259
 
242 260
             is_game_over: false,
243 261
 
@@ -266,6 +284,9 @@ impl Game {
266 284
             s_count: 0,
267 285
             t_count: 0,
268 286
             z_count: 0,
287
+
288
+            debug_flash: true,
289
+            debug_delta: 0.0,
269 290
         }
270 291
     }
271 292
 
@@ -337,11 +358,18 @@ impl Game {
337 358
                 }
338 359
             }
339 360
         }
361
+
362
+        if self.debug_flash {
363
+            geometry.push_text("X", Block2D { x: 11, y: 1 }, Col::new(1.0, 1.0, 1.0, 1.0));
364
+        } else {
365
+            geometry.push_text("-", Block2D { x: 11, y: 1 }, Col::new(1.0, 1.0, 1.0, 1.0));
366
+        }
367
+        geometry.push_text(&format!("{}", self.debug_delta), Block2D { x: 12, y: 1 }, Col::new(1.0, 1.0, 1.0, 1.0));
340 368
     }
341 369
 
342 370
     pub fn tick(&mut self, controller: &Controller, delta: f32, random: f32) -> bool {
343 371
 
344
-        if controller.start_just_released {
372
+        if controller.just_released(ControllerButton::Start) {
345 373
             if self.mode == GameMode::Playing {
346 374
                 play_sound(SoundEffect::PauseIn);
347 375
                 self.mode = GameMode::Paused;
@@ -365,6 +393,12 @@ impl Game {
365 393
             corrected_delta = delta;
366 394
         }
367 395
 
396
+        self.debug_flash = !self.debug_flash;
397
+        self.debug_delta = corrected_delta;
398
+        if self.debug_delta > 0.0 && self.debug_delta < 15.0 {
399
+            log(&format!("{}", self.debug_delta));
400
+        }
401
+
368 402
         match self.mode {
369 403
             GameMode::Playing => match self.tick_playing(controller, corrected_delta, random) {
370 404
                 Ok(res) => res,
@@ -620,6 +654,7 @@ fn apply_user_input(game: &mut Game, controller: &Controller, delta: f32) {
620 654
                 y: game.piece.pos.y,
621 655
             };
622 656
             if is_allowed(&game.board, shape, &new_position, &game.piece.angle) {
657
+                // log(&format!("old position: {:?}, new position {:?}", game.piece.pos, new_position));
623 658
                 game.piece.pos = new_position;
624 659
             }
625 660
         }
@@ -639,7 +674,7 @@ fn apply_user_input(game: &mut Game, controller: &Controller, delta: f32) {
639 674
             }
640 675
         }
641 676
 
642
-        if controller.up_just_pressed {
677
+        if controller.just_pressed(ControllerButton::Up) {
643 678
             let new_angle;
644 679
             if shape.fully_rotate {
645 680
                 new_angle = match game.piece.angle {
@@ -661,7 +696,7 @@ fn apply_user_input(game: &mut Game, controller: &Controller, delta: f32) {
661 696
         }
662 697
 
663 698
 
664
-        if controller.down_just_pressed {
699
+        if controller.just_pressed(ControllerButton::Down) {
665 700
             game.piece_is_dropping = true;
666 701
         }
667 702
 
@@ -974,45 +1009,142 @@ fn update_pause_menu(game: &mut Game, controller: &Controller) -> bool {
974 1009
 
975 1010
     let mut update = false;
976 1011
 
977
-    if controller.down_just_pressed {
978
-        log("paused: down pressed");
1012
+    if controller.just_pressed(ControllerButton::Down) {
979 1013
         game.menu_active_item += 1;
1014
+        play_sound(SoundEffect::MenuMove);
980 1015
         update = true;
981 1016
     }
982 1017
 
983
-    if controller.up_just_pressed {
984
-        log("paused: up pressed");
1018
+    if controller.just_pressed(ControllerButton::Up) {
985 1019
         game.menu_active_item -= 1;
1020
+        play_sound(SoundEffect::MenuMove);
986 1021
         update = true;
987 1022
     }
988 1023
 
989
-    if game.menu_active_item < 0 {
990
-        game.menu_active_item = 2;
1024
+    game.menu_active_item = wrap(game.menu_active_item, 0, game.menu_num_items - 1);
1025
+
1026
+    // volume
1027
+    if game.menu_active_item == 1 {
1028
+        if controller.just_pressed(ControllerButton::Left) {
1029
+            game.menu_volume -= 1;
1030
+            play_sound(SoundEffect::MenuMove);
1031
+            update = true;
1032
+        }
1033
+        if controller.just_pressed(ControllerButton::Right) {
1034
+            game.menu_volume += 1;
1035
+            play_sound(SoundEffect::MenuMove);
1036
+            update = true;
1037
+        }
1038
+        game.menu_volume = clamp(game.menu_volume, 0, game.menu_max_volume);
991 1039
     }
992 1040
 
993
-    if game.menu_active_item > 2 {
994
-        game.menu_active_item = 0;
1041
+    // crt update speed
1042
+    if game.menu_active_item == 2 {
1043
+        if controller.just_pressed(ControllerButton::Left) {
1044
+            game.menu_crt_update_speed -= 1;
1045
+            play_sound(SoundEffect::MenuMove);
1046
+            update = true;
1047
+        }
1048
+        if controller.just_pressed(ControllerButton::Right) {
1049
+            game.menu_crt_update_speed += 1;
1050
+            play_sound(SoundEffect::MenuMove);
1051
+            update = true;
1052
+        }
1053
+        game.menu_crt_update_speed = clamp(game.menu_crt_update_speed, 0, game.menu_max_crt_update_speed);
1054
+    }
1055
+
1056
+    // curvature
1057
+    if game.menu_active_item == 3 {
1058
+        if controller.just_pressed(ControllerButton::Left) {
1059
+            game.menu_curvature -= 1;
1060
+            play_sound(SoundEffect::MenuMove);
1061
+            update = true;
1062
+        }
1063
+        if controller.just_pressed(ControllerButton::Right) {
1064
+            game.menu_curvature += 1;
1065
+            play_sound(SoundEffect::MenuMove);
1066
+            update = true;
1067
+        }
1068
+        game.menu_curvature = clamp(game.menu_curvature, 0, game.menu_max_curvature);
995 1069
     }
996 1070
 
997 1071
     update
998 1072
 }
999 1073
 
1074
+fn wrap(val: i32, min: i32, max: i32) -> i32 {
1075
+    if val < min {
1076
+        return max
1077
+    } else if val > max {
1078
+        return min
1079
+    }
1080
+    val
1081
+}
1082
+
1083
+fn clamp(val: i32, min: i32, max: i32) -> i32 {
1084
+    if val < min {
1085
+        return min
1086
+    } else if val > max {
1087
+        return max
1088
+    }
1089
+    val
1090
+}
1091
+
1000 1092
 fn render_pause_menu(game: &Game, geometry: &mut Geometry, centre: Block2D, text_colour: Col, background_colour: Col) {
1001
-    let lines = build_paused_menu(game);
1093
+    let resume = build_menu_item(game, 0, "RESUME");
1094
+    let vol = build_menu_item_slider(game, 1, "Volume      ", game.menu_max_volume, game.menu_volume);
1095
+    let crt_update_speed = build_menu_item_slider(game, 2, "CRT Refresh ", game.menu_max_crt_update_speed, game.menu_crt_update_speed);
1096
+    let curvature = build_menu_item_slider(game, 3, "Curvature   ", game.menu_max_curvature, game.menu_curvature);
1097
+    let restart = build_menu_item(game, 4, "Restart");
1098
+
1099
+    // remember to update Game::menu_num_items when adding another menu option
1100
+
1101
+    let lines: Vec<&str> = vec![&resume[..],
1102
+                                &vol[..],
1103
+                                &crt_update_speed[..],
1104
+                                &curvature[..],
1105
+                                &restart[..]];
1106
+
1002 1107
     geometry.push_centred_boxed_multiline(&lines, centre, text_colour, background_colour);
1003 1108
 }
1004 1109
 
1005
-fn build_paused_menu(game: &Game) -> Vec<&str> {
1006
-    let mut lines: Vec<&str> = vec!["  RESUME", "  Volume: [---*--]", "  Restart"];
1007 1110
 
1008
-    match game.menu_active_item {
1009
-        0 => lines[0] = "> RESUME",
1010
-        1 => lines[1] = "> Volume: [---*--]",
1011
-        2 => lines[2] = "> Restart",
1012
-        _ => (),
1111
+fn build_menu_item(game: &Game, item_order: i32, label: &str) -> String {
1112
+    let mut out = menu_item_base(game, item_order);
1113
+    out.push_str(label);
1114
+    out
1115
+}
1116
+
1117
+fn build_menu_item_slider(game: &Game, item_order: i32, label: &str, max: i32, val: i32) -> String {
1118
+    let mut out = menu_item_base(game, item_order);
1119
+    let slider = build_menu_item_slider_bar(max, val);
1120
+    out.push_str(label);
1121
+    out.push_str(&slider[..]);
1122
+    out
1123
+}
1124
+
1125
+fn menu_item_base(game: &Game, item_order: i32) -> String {
1126
+    let mut out = "".to_owned();
1127
+    if game.menu_active_item == item_order {
1128
+        out.push_str("> ");
1129
+    } else {
1130
+        out.push_str("  ");
1013 1131
     }
1132
+    out
1133
+}
1134
+
1135
+fn build_menu_item_slider_bar(max: i32, value: i32) -> String {
1136
+    let mut out = "".to_owned();
1014 1137
 
1015
-    lines
1138
+    out.push_str("[");
1139
+    for _ in 0..value {
1140
+        out.push_str("-");
1141
+    }
1142
+    out.push_str("*");
1143
+    for _ in value..max {
1144
+        out.push_str("-");
1145
+    }
1146
+    out.push_str("]");
1147
+    out
1016 1148
 }
1017 1149
 
1018 1150
 fn define_shapes() -> HashMap<ShapeKind, Shape> {

+ 11
- 3
src/lib.rs View File

@@ -1,3 +1,4 @@
1
+#![allow(dead_code)]
1 2
 #![feature(use_extern_macros, wasm_custom_section, wasm_import_module)]
2 3
 #![cfg_attr(
3 4
     feature = "cargo-clippy",
@@ -141,6 +142,8 @@ pub struct Bridge {
141 142
     game: Game,
142 143
     controller: Controller,
143 144
     geometry: Geometry,
145
+
146
+    game_is_ticking: bool,
144 147
 }
145 148
 
146 149
 #[wasm_bindgen]
@@ -151,6 +154,7 @@ impl Bridge {
151 154
             game: Game::new(config),
152 155
             controller: Controller::new(),
153 156
             geometry: Geometry::new(config),
157
+            game_is_ticking: false,
154 158
         }
155 159
     }
156 160
 
@@ -180,11 +184,11 @@ impl Bridge {
180 184
     }
181 185
 
182 186
     pub fn tick(&mut self, delta: f32, random: f32) -> bool {
183
-        let res = self.game.tick(&self.controller, delta, random);
187
+        self.game_is_ticking = self.game.tick(&self.controller, delta, random);
184 188
 
185 189
         self.controller.reset_controller();
186 190
 
187
-        res
191
+        self.game_is_ticking
188 192
     }
189 193
 
190 194
     // use the current gamestate to update geometry
@@ -220,12 +224,16 @@ impl Bridge {
220 224
             "a" => call_tick = self.input(ControllerButton::A, action),
221 225
             "z" => call_tick = self.input(ControllerButton::B, action),
222 226
             "Enter" => call_tick = self.input(ControllerButton::Start, action),
227
+            "Escape" => call_tick = self.input(ControllerButton::Start, action),
223 228
             "Shift" => call_tick = self.input(ControllerButton::Select, action),
224 229
             _ => prevent_default = false,
225 230
         }
226 231
 
232
+        // the js side should only call tick if the main game loop isn't already ticking
233
+        // otherwise we'll end up with multiple requestAnimationFrame invocations
234
+
227 235
         KeyEventReturn {
228
-            call_tick,
236
+            call_tick: call_tick && !self.game_is_ticking,
229 237
             prevent_default,
230 238
         }
231 239
     }

BIN
web/img/tileset.png View File