├── .gitignore
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── build.rs
├── src
├── game
│ ├── background.rs
│ ├── builder.rs
│ ├── button.rs
│ ├── cell.rs
│ ├── effect.rs
│ ├── mod.rs
│ ├── piece_profile.rs
│ ├── platform.rs
│ ├── player.rs
│ ├── player_enum.rs
│ ├── star.rs
│ ├── step_queue.rs
│ ├── util.rs
│ └── warp.rs
├── game_input.rs
├── level_loader.rs
├── levels
│ ├── level0.txt
│ ├── level0_index.txt
│ ├── level1.txt
│ ├── level1_index.txt
│ ├── level2.txt
│ ├── level2_index.txt
│ ├── level3.txt
│ ├── level3_index.txt
│ ├── level4.txt
│ ├── level4_index.txt
│ ├── level5.txt
│ ├── level5_index.txt
│ ├── level6.txt
│ └── level6_index.txt
└── main.rs
└── src_assets
├── LICENSE
├── music
└── BgMusic.ogg
├── sounds
├── Button.ogg
├── Clear.ogg
├── Jump.ogg
├── Lasor.ogg
└── Warp.ogg
└── sprites
├── BgPattern.png
├── BlueFade.png
├── BlueWarp.png
├── GreenFade.png
├── GreenWarp.png
├── Instructions.png
├── Lasor.png
├── PinkFade.png
├── PinkWarp.png
├── Platform.png
├── PlayerChirp.png
├── PlayerRun.png
├── PlayerStill.png
├── Puff.png
├── Star.png
├── Tile_t8.png
└── WhiteSquare.png
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 |
3 | /assets/
4 | /html/
5 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "adler32"
5 | version = "1.0.4"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 |
8 | [[package]]
9 | name = "aho-corasick"
10 | version = "0.7.6"
11 | source = "registry+https://github.com/rust-lang/crates.io-index"
12 | dependencies = [
13 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
14 | ]
15 |
16 | [[package]]
17 | name = "autocfg"
18 | version = "0.1.7"
19 | source = "registry+https://github.com/rust-lang/crates.io-index"
20 |
21 | [[package]]
22 | name = "bitflags"
23 | version = "0.7.0"
24 | source = "registry+https://github.com/rust-lang/crates.io-index"
25 |
26 | [[package]]
27 | name = "bitflags"
28 | version = "0.9.1"
29 | source = "registry+https://github.com/rust-lang/crates.io-index"
30 |
31 | [[package]]
32 | name = "bitflags"
33 | version = "1.2.1"
34 | source = "registry+https://github.com/rust-lang/crates.io-index"
35 |
36 | [[package]]
37 | name = "byteorder"
38 | version = "1.3.2"
39 | source = "registry+https://github.com/rust-lang/crates.io-index"
40 |
41 | [[package]]
42 | name = "cfg-if"
43 | version = "0.1.10"
44 | source = "registry+https://github.com/rust-lang/crates.io-index"
45 |
46 | [[package]]
47 | name = "chirperjax"
48 | version = "0.1.0"
49 | dependencies = [
50 | "collider 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
51 | "gate 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
52 | "gate_build 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
53 | ]
54 |
55 | [[package]]
56 | name = "collider"
57 | version = "0.3.1"
58 | source = "registry+https://github.com/rust-lang/crates.io-index"
59 | dependencies = [
60 | "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
61 | ]
62 |
63 | [[package]]
64 | name = "color_quant"
65 | version = "1.0.1"
66 | source = "registry+https://github.com/rust-lang/crates.io-index"
67 |
68 | [[package]]
69 | name = "crossbeam-deque"
70 | version = "0.7.2"
71 | source = "registry+https://github.com/rust-lang/crates.io-index"
72 | dependencies = [
73 | "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
74 | "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
75 | ]
76 |
77 | [[package]]
78 | name = "crossbeam-epoch"
79 | version = "0.8.0"
80 | source = "registry+https://github.com/rust-lang/crates.io-index"
81 | dependencies = [
82 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
83 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
84 | "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
85 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
86 | "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
87 | "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
88 | ]
89 |
90 | [[package]]
91 | name = "crossbeam-queue"
92 | version = "0.2.0"
93 | source = "registry+https://github.com/rust-lang/crates.io-index"
94 | dependencies = [
95 | "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
96 | ]
97 |
98 | [[package]]
99 | name = "crossbeam-utils"
100 | version = "0.7.0"
101 | source = "registry+https://github.com/rust-lang/crates.io-index"
102 | dependencies = [
103 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
104 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
105 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
106 | ]
107 |
108 | [[package]]
109 | name = "deflate"
110 | version = "0.7.20"
111 | source = "registry+https://github.com/rust-lang/crates.io-index"
112 | dependencies = [
113 | "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
114 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
115 | ]
116 |
117 | [[package]]
118 | name = "either"
119 | version = "1.5.3"
120 | source = "registry+https://github.com/rust-lang/crates.io-index"
121 |
122 | [[package]]
123 | name = "enum_primitive"
124 | version = "0.1.1"
125 | source = "registry+https://github.com/rust-lang/crates.io-index"
126 | dependencies = [
127 | "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
128 | ]
129 |
130 | [[package]]
131 | name = "fnv"
132 | version = "1.0.6"
133 | source = "registry+https://github.com/rust-lang/crates.io-index"
134 |
135 | [[package]]
136 | name = "fuchsia-cprng"
137 | version = "0.1.1"
138 | source = "registry+https://github.com/rust-lang/crates.io-index"
139 |
140 | [[package]]
141 | name = "gate"
142 | version = "0.6.3"
143 | source = "registry+https://github.com/rust-lang/crates.io-index"
144 | dependencies = [
145 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
146 | "gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
147 | "sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
148 | ]
149 |
150 | [[package]]
151 | name = "gate_build"
152 | version = "0.6.3"
153 | source = "registry+https://github.com/rust-lang/crates.io-index"
154 | dependencies = [
155 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
156 | "image 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
157 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
158 | "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
159 | ]
160 |
161 | [[package]]
162 | name = "gif"
163 | version = "0.9.2"
164 | source = "registry+https://github.com/rust-lang/crates.io-index"
165 | dependencies = [
166 | "color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
167 | "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
168 | ]
169 |
170 | [[package]]
171 | name = "gl"
172 | version = "0.6.5"
173 | source = "registry+https://github.com/rust-lang/crates.io-index"
174 | dependencies = [
175 | "gl_generator 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
176 | ]
177 |
178 | [[package]]
179 | name = "gl_generator"
180 | version = "0.6.1"
181 | source = "registry+https://github.com/rust-lang/crates.io-index"
182 | dependencies = [
183 | "khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
184 | "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
185 | "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
186 | ]
187 |
188 | [[package]]
189 | name = "hermit-abi"
190 | version = "0.1.5"
191 | source = "registry+https://github.com/rust-lang/crates.io-index"
192 | dependencies = [
193 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
194 | ]
195 |
196 | [[package]]
197 | name = "image"
198 | version = "0.15.0"
199 | source = "registry+https://github.com/rust-lang/crates.io-index"
200 | dependencies = [
201 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
202 | "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
203 | "gif 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
204 | "jpeg-decoder 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
205 | "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
206 | "num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
207 | "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
208 | "png 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
209 | "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
210 | ]
211 |
212 | [[package]]
213 | name = "inflate"
214 | version = "0.2.0"
215 | source = "registry+https://github.com/rust-lang/crates.io-index"
216 |
217 | [[package]]
218 | name = "jpeg-decoder"
219 | version = "0.1.18"
220 | source = "registry+https://github.com/rust-lang/crates.io-index"
221 | dependencies = [
222 | "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
223 | "rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
224 | ]
225 |
226 | [[package]]
227 | name = "khronos_api"
228 | version = "2.2.0"
229 | source = "registry+https://github.com/rust-lang/crates.io-index"
230 |
231 | [[package]]
232 | name = "lazy_static"
233 | version = "0.2.11"
234 | source = "registry+https://github.com/rust-lang/crates.io-index"
235 |
236 | [[package]]
237 | name = "lazy_static"
238 | version = "1.4.0"
239 | source = "registry+https://github.com/rust-lang/crates.io-index"
240 |
241 | [[package]]
242 | name = "libc"
243 | version = "0.2.66"
244 | source = "registry+https://github.com/rust-lang/crates.io-index"
245 |
246 | [[package]]
247 | name = "log"
248 | version = "0.3.9"
249 | source = "registry+https://github.com/rust-lang/crates.io-index"
250 | dependencies = [
251 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
252 | ]
253 |
254 | [[package]]
255 | name = "log"
256 | version = "0.4.8"
257 | source = "registry+https://github.com/rust-lang/crates.io-index"
258 | dependencies = [
259 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
260 | ]
261 |
262 | [[package]]
263 | name = "lzw"
264 | version = "0.10.0"
265 | source = "registry+https://github.com/rust-lang/crates.io-index"
266 |
267 | [[package]]
268 | name = "memchr"
269 | version = "2.2.1"
270 | source = "registry+https://github.com/rust-lang/crates.io-index"
271 |
272 | [[package]]
273 | name = "memoffset"
274 | version = "0.5.3"
275 | source = "registry+https://github.com/rust-lang/crates.io-index"
276 | dependencies = [
277 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
278 | ]
279 |
280 | [[package]]
281 | name = "num"
282 | version = "0.1.42"
283 | source = "registry+https://github.com/rust-lang/crates.io-index"
284 | dependencies = [
285 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
286 | "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
287 | "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
288 | ]
289 |
290 | [[package]]
291 | name = "num-integer"
292 | version = "0.1.41"
293 | source = "registry+https://github.com/rust-lang/crates.io-index"
294 | dependencies = [
295 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
296 | "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
297 | ]
298 |
299 | [[package]]
300 | name = "num-iter"
301 | version = "0.1.39"
302 | source = "registry+https://github.com/rust-lang/crates.io-index"
303 | dependencies = [
304 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
305 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
306 | "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
307 | ]
308 |
309 | [[package]]
310 | name = "num-rational"
311 | version = "0.1.42"
312 | source = "registry+https://github.com/rust-lang/crates.io-index"
313 | dependencies = [
314 | "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
315 | "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
316 | ]
317 |
318 | [[package]]
319 | name = "num-traits"
320 | version = "0.1.43"
321 | source = "registry+https://github.com/rust-lang/crates.io-index"
322 | dependencies = [
323 | "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
324 | ]
325 |
326 | [[package]]
327 | name = "num-traits"
328 | version = "0.2.10"
329 | source = "registry+https://github.com/rust-lang/crates.io-index"
330 | dependencies = [
331 | "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
332 | ]
333 |
334 | [[package]]
335 | name = "num_cpus"
336 | version = "1.11.1"
337 | source = "registry+https://github.com/rust-lang/crates.io-index"
338 | dependencies = [
339 | "hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
340 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
341 | ]
342 |
343 | [[package]]
344 | name = "png"
345 | version = "0.9.0"
346 | source = "registry+https://github.com/rust-lang/crates.io-index"
347 | dependencies = [
348 | "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
349 | "deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
350 | "inflate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
351 | "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
352 | ]
353 |
354 | [[package]]
355 | name = "rand"
356 | version = "0.3.23"
357 | source = "registry+https://github.com/rust-lang/crates.io-index"
358 | dependencies = [
359 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
360 | "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
361 | ]
362 |
363 | [[package]]
364 | name = "rand"
365 | version = "0.4.6"
366 | source = "registry+https://github.com/rust-lang/crates.io-index"
367 | dependencies = [
368 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
369 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
370 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
371 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
372 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
373 | ]
374 |
375 | [[package]]
376 | name = "rand_core"
377 | version = "0.3.1"
378 | source = "registry+https://github.com/rust-lang/crates.io-index"
379 | dependencies = [
380 | "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
381 | ]
382 |
383 | [[package]]
384 | name = "rand_core"
385 | version = "0.4.2"
386 | source = "registry+https://github.com/rust-lang/crates.io-index"
387 |
388 | [[package]]
389 | name = "rayon"
390 | version = "1.2.1"
391 | source = "registry+https://github.com/rust-lang/crates.io-index"
392 | dependencies = [
393 | "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
394 | "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
395 | "rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
396 | ]
397 |
398 | [[package]]
399 | name = "rayon-core"
400 | version = "1.6.1"
401 | source = "registry+https://github.com/rust-lang/crates.io-index"
402 | dependencies = [
403 | "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
404 | "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
405 | "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
406 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
407 | "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
408 | ]
409 |
410 | [[package]]
411 | name = "rdrand"
412 | version = "0.4.0"
413 | source = "registry+https://github.com/rust-lang/crates.io-index"
414 | dependencies = [
415 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
416 | ]
417 |
418 | [[package]]
419 | name = "regex"
420 | version = "1.3.1"
421 | source = "registry+https://github.com/rust-lang/crates.io-index"
422 | dependencies = [
423 | "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
424 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
425 | "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
426 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
427 | ]
428 |
429 | [[package]]
430 | name = "regex-syntax"
431 | version = "0.6.12"
432 | source = "registry+https://github.com/rust-lang/crates.io-index"
433 |
434 | [[package]]
435 | name = "rustc_version"
436 | version = "0.2.3"
437 | source = "registry+https://github.com/rust-lang/crates.io-index"
438 | dependencies = [
439 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
440 | ]
441 |
442 | [[package]]
443 | name = "scoped_threadpool"
444 | version = "0.1.9"
445 | source = "registry+https://github.com/rust-lang/crates.io-index"
446 |
447 | [[package]]
448 | name = "scopeguard"
449 | version = "1.0.0"
450 | source = "registry+https://github.com/rust-lang/crates.io-index"
451 |
452 | [[package]]
453 | name = "sdl2"
454 | version = "0.29.1"
455 | source = "registry+https://github.com/rust-lang/crates.io-index"
456 | dependencies = [
457 | "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
458 | "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
459 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
460 | "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
461 | "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
462 | "sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)",
463 | ]
464 |
465 | [[package]]
466 | name = "sdl2-sys"
467 | version = "0.27.3"
468 | source = "registry+https://github.com/rust-lang/crates.io-index"
469 | dependencies = [
470 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
471 | ]
472 |
473 | [[package]]
474 | name = "semver"
475 | version = "0.9.0"
476 | source = "registry+https://github.com/rust-lang/crates.io-index"
477 | dependencies = [
478 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
479 | ]
480 |
481 | [[package]]
482 | name = "semver-parser"
483 | version = "0.7.0"
484 | source = "registry+https://github.com/rust-lang/crates.io-index"
485 |
486 | [[package]]
487 | name = "thread_local"
488 | version = "0.3.6"
489 | source = "registry+https://github.com/rust-lang/crates.io-index"
490 | dependencies = [
491 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
492 | ]
493 |
494 | [[package]]
495 | name = "winapi"
496 | version = "0.3.8"
497 | source = "registry+https://github.com/rust-lang/crates.io-index"
498 | dependencies = [
499 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
500 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
501 | ]
502 |
503 | [[package]]
504 | name = "winapi-i686-pc-windows-gnu"
505 | version = "0.4.0"
506 | source = "registry+https://github.com/rust-lang/crates.io-index"
507 |
508 | [[package]]
509 | name = "winapi-x86_64-pc-windows-gnu"
510 | version = "0.4.0"
511 | source = "registry+https://github.com/rust-lang/crates.io-index"
512 |
513 | [[package]]
514 | name = "xml-rs"
515 | version = "0.7.0"
516 | source = "registry+https://github.com/rust-lang/crates.io-index"
517 | dependencies = [
518 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
519 | ]
520 |
521 | [metadata]
522 | "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
523 | "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
524 | "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
525 | "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
526 | "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
527 | "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
528 | "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
529 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
530 | "checksum collider 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba1462139efca9ca15e335ae40d43d1fa998d8ff7270d8c12a72decf1d066e1a"
531 | "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
532 | "checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
533 | "checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
534 | "checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700"
535 | "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
536 | "checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4"
537 | "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
538 | "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
539 | "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
540 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
541 | "checksum gate 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b32700c026f790f035cad6e90c030ff09bd7d37e6900d6f2e6fba9fd77479b65"
542 | "checksum gate_build 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e105ab93d4ef2aa834d363bc1ef8855f2c75df7b271e4db2c7c715aef503fa53"
543 | "checksum gif 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e41945ba23db3bf51b24756d73d81acb4f28d85c3dccc32c6fae904438c25f"
544 | "checksum gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1c73b90c285f02059b34a6c66bc645ba5faa18c0e3ab332e0725654fc71db441"
545 | "checksum gl_generator 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "75d69f914b49d9ff32fdf394cbd798f8c716d74fd19f9cc29da3e99797b2a78d"
546 | "checksum hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f629dc602392d3ec14bfc8a09b5e644d7ffd725102b48b81e59f90f2633621d7"
547 | "checksum image 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "634700d4a51fa91ceaa798001d46bf862c7b712bd691085d7ba6afd5521e21f7"
548 | "checksum inflate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d1238524675af3938a7c74980899535854b88ba07907bb1c944abe5b8fc437e5"
549 | "checksum jpeg-decoder 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0256f0aec7352539102a9efbcb75543227b7ab1117e0f95450023af730128451"
550 | "checksum khronos_api 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "037ab472c33f67b5fbd3e9163a2645319e5356fcd355efa6d4eb7fff4bbcb554"
551 | "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
552 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
553 | "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
554 | "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
555 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
556 | "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
557 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
558 | "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
559 | "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
560 | "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
561 | "checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"
562 | "checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
563 | "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
564 | "checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
565 | "checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
566 | "checksum png 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f256476eee4447f55909d52d22a16cfa6e5e55e5cb77fa182c7fcc8c4456ee3c"
567 | "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
568 | "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
569 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
570 | "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
571 | "checksum rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd"
572 | "checksum rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791"
573 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
574 | "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
575 | "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
576 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
577 | "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
578 | "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
579 | "checksum sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c366cfa1f22d001774214ce2fb13f369af760b016bc79cc62d7f5ae15c00fea"
580 | "checksum sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d9f87e3d948f94f2d8688970422f49249c20e97f8f3aad76cb8729901d4eb10"
581 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
582 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
583 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
584 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
585 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
586 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
587 | "checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2"
588 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "chirperjax"
3 | version = "0.1.0"
4 | edition = "2018"
5 |
6 | [dependencies]
7 | gate = "0.6.3"
8 | collider = "0.3.0"
9 |
10 | [build-dependencies]
11 | gate_build = "0.6.3"
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Chirperjax
2 | A simple 2D platformer game that demonstrates the use of two Rust crates:
3 | [Gate](https://crates.io/crates/gate) and [Collider](https://crates.io/crates/collider).
4 |
5 | ### Play Online
6 |
7 | Thanks to WebAssembly and WebGl, you can play this game online at
8 | .
9 |
10 | ### Building
11 |
12 | Instructions are the same as building the Gate example app.
13 | See .
14 |
15 | ### Videos
16 |
17 | Introducing Gate and this game: https://youtu.be/SR-Yx6nTfZY
18 |
19 | ### License
20 |
21 | Chirperjax source code is licensed under the
22 | [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
23 | Chirperjax assets, found in the `src_assets/` directory, are licensed under the
24 | [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 License](https://creativecommons.org/licenses/by-nc-sa/4.0/).
25 |
--------------------------------------------------------------------------------
/build.rs:
--------------------------------------------------------------------------------
1 | // gate_demo, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2018 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | extern crate gate_build;
18 |
19 | use std::path::Path;
20 | use std::env;
21 |
22 | use gate_build::AssetPacker;
23 |
24 | // build script packs image assets into atlases and generates enums to reference assets
25 |
26 | fn main() {
27 | let is_wasm = env::var("TARGET").map(|t| t.starts_with("wasm32")).unwrap_or(false);
28 | let out_dir = env::var("OUT_DIR").unwrap();
29 | let gen_code_path = Path::new(&out_dir).join("asset_id.rs");
30 |
31 | let assets_dir = if is_wasm { "html" } else { "assets" };
32 | let mut packer = AssetPacker::new(Path::new(assets_dir));
33 | packer.cargo_rerun_if_changed();
34 | packer.sprites(Path::new("src_assets/sprites"));
35 | packer.music(Path::new("src_assets/music"));
36 | packer.sounds(Path::new("src_assets/sounds"));
37 | if is_wasm { packer.gen_javascript_and_html(); }
38 | packer.gen_asset_id_code(&gen_code_path);
39 | }
40 |
--------------------------------------------------------------------------------
/src/game/background.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use gate::renderer::{Renderer, SpriteRenderer, Affine};
18 |
19 | use collider::geom::{v2, Vec2};
20 |
21 | use crate::asset_id::{AssetId, SpriteId};
22 | use super::SCREEN_PIXELS_HEIGHT;
23 |
24 | const COLOR: (u8, u8, u8) = (203, 219, 255);
25 | const PERIOD: f64 = 10.;
26 | const SEPARATION: f64 = 60.;
27 |
28 | pub fn draw(renderer: &mut Renderer, camera: Vec2, room_pixels: Vec2, time: f64, screen_pixels_width: f64) {
29 | renderer.clear(COLOR);
30 |
31 | let mut renderer = renderer.sprite_mode();
32 | let time = time + 0.125 * PERIOD;
33 | let offset = (room_pixels * 0.5 - (camera + 0.5 * v2(screen_pixels_width, SCREEN_PIXELS_HEIGHT))) * 0.5;
34 |
35 | draw_bg_piece_grid(&mut renderer, offset, time, screen_pixels_width);
36 | draw_bg_piece_grid(&mut renderer, offset + v2(SEPARATION, SEPARATION), time + 0.25 * PERIOD, screen_pixels_width);
37 | draw_bg_piece_grid(&mut renderer, offset + v2(2. * SEPARATION, 0.), time + 0.5 * PERIOD, screen_pixels_width);
38 | draw_bg_piece_grid(&mut renderer, offset + v2(SEPARATION, -SEPARATION), time + 0.75 * PERIOD, screen_pixels_width);
39 | }
40 |
41 | fn draw_bg_piece_grid(renderer: &mut SpriteRenderer, center: Vec2, time: f64, screen_pixels_width: f64) {
42 | let time = time % PERIOD;
43 | let angle = 0.25 * (time * 15.).sin() * (-3. * time).exp();
44 | let pre_affine = Affine::scale(1.25).pre_rotate(angle);
45 | let separation = SEPARATION * 2.;
46 |
47 | let max_x = (screen_pixels_width + SEPARATION) * 0.5 + 3.;
48 | let max_y = (SCREEN_PIXELS_HEIGHT + SEPARATION) * 0.5 + 3.;
49 |
50 | let start_x_idx = ((-max_x - center.x) / separation).ceil() as i32;
51 | let end_x_idx = ((max_x - center.x) / separation).ceil() as i32;
52 | let start_y_idx = ((-max_y - center.y) / separation).ceil() as i32;
53 | let end_y_idx = ((max_y - center.y) / separation).ceil() as i32;
54 |
55 | let x_off = 0.5 * screen_pixels_width;
56 | let y_off = 0.5 * SCREEN_PIXELS_HEIGHT;
57 |
58 | for x_idx in start_x_idx..end_x_idx {
59 | for y_idx in start_y_idx..end_y_idx {
60 | if (x_idx + y_idx) % 2 == 0 {
61 | let pos = center + v2(separation * x_idx as f64, separation * y_idx as f64);
62 | renderer.draw(&pre_affine.post_translate(pos.x + x_off, pos.y + y_off), SpriteId::BgPattern);
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/game/builder.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use std::collections::HashMap;
18 | use std::mem;
19 |
20 | use collider::{Collider, HbId};
21 | use collider::geom::{Shape, v2, Vec2, Card};
22 |
23 | use super::{GameBoard, Idx2, PlatformKind, CELL_LEN};
24 | use super::player_enum::PlayerEnum;
25 | use super::star::Star;
26 | use super::piece_profile::{PieceProfile, PieceKind};
27 | use super::step_queue::StepQueue;
28 | use super::cell::Cell;
29 | use super::button::{self, ButtonAction};
30 | use super::warp::{WarpColor, LasorKind, Lasor};
31 | use super::util::{IdGen, idx_to_vec, card_offset};
32 |
33 | #[derive(Copy, Clone, PartialEq, Eq)]
34 | enum PendingCell { Wall, Floor, Gate, Spawn(WarpColor, bool) }
35 |
36 | pub struct GameBoardBuilder {
37 | id_gen: IdGen,
38 | collider: Collider,
39 | room_dims: Idx2,
40 | player: Option,
41 | star: Option,
42 | platforms: Vec<(Idx2, PlatformKind)>,
43 | grid: HashMap,
44 | buttons: HashMap, ButtonAction)>,
45 | warps: Vec<(Idx2, WarpColor)>,
46 | respawns: HashMap,
47 | lasors: Vec<(Idx2, LasorKind, WarpColor)>,
48 | }
49 |
50 | impl GameBoardBuilder {
51 | pub fn new(room_dims: Idx2) -> GameBoardBuilder {
52 | GameBoardBuilder {
53 | id_gen: IdGen::new(),
54 | collider: Collider::new(),
55 | room_dims,
56 | player: None,
57 | star: None,
58 | grid: HashMap::new(),
59 | platforms: Vec::new(),
60 | buttons: HashMap::new(),
61 | warps: Vec::new(),
62 | respawns: HashMap::new(),
63 | lasors: Vec::new(),
64 | }
65 | }
66 |
67 | fn button_mut(&mut self, index: u32) -> &mut (Option, ButtonAction) {
68 | self.buttons.entry(index).or_insert((None, ButtonAction { unlock_cells: Vec::new(), platforms: Vec::new() }))
69 | }
70 |
71 | pub fn add_player(&mut self, pos: Idx2) { self.player = Some(PlayerEnum::Start(idx_to_vec(pos))); }
72 | pub fn add_star(&mut self, pos: Idx2) {
73 | let (star, hitbox) = Star::new(self.id_gen.next(), pos);
74 | let overlaps = self.collider.add_hitbox(PieceProfile::new(star.id(), PieceKind::Star), hitbox);
75 | assert!(overlaps.is_empty(), "unexpected overlap with star hitbox");
76 | self.star = Some(star);
77 | }
78 |
79 | pub fn add_wall(&mut self, pos: Idx2) { self.grid.insert(pos, PendingCell::Wall); }
80 | pub fn add_floor(&mut self, pos: Idx2) { self.grid.insert(pos, PendingCell::Floor); }
81 |
82 | pub fn add_platform(&mut self, pos: Idx2, kind: PlatformKind, index: Option) {
83 | if let Some(index) = index {
84 | self.button_mut(index).1.platforms.push((pos, kind));
85 | } else {
86 | self.platforms.push((pos, kind));
87 | }
88 | }
89 |
90 | pub fn add_gate(&mut self, pos: Idx2, index: u32) {
91 | self.grid.insert(pos, PendingCell::Gate);
92 | self.button_mut(index).1.unlock_cells.push(pos);
93 | }
94 |
95 | pub fn add_button(&mut self, pos: Idx2, index: u32) { self.button_mut(index).0 = Some(pos) }
96 |
97 | pub fn add_warp(&mut self, pos: Idx2, color: WarpColor) { self.warps.push((pos, color)); }
98 | pub fn add_respawn(&mut self, pos: Idx2, color: WarpColor) {
99 | self.grid.insert(pos, PendingCell::Spawn(color, false));
100 | self.grid.insert((pos.0 + 1, pos.1), PendingCell::Spawn(color, true));
101 | self.respawns.insert(color, idx_to_vec(pos) + v2(0.5 * CELL_LEN as f64, 11.));
102 | }
103 |
104 | pub fn add_lasor(&mut self, pos: Idx2, kind: LasorKind, color: WarpColor) { self.lasors.push((pos, kind, color)); }
105 |
106 | pub fn build(mut self) -> GameBoard {
107 | let mut grid_positions: Vec<_> = self.grid.keys().cloned().collect();
108 | let grid = grid_positions.drain(..).map(|pos| (pos, self.form_grid_cell(pos))).collect();
109 | self.add_border(false);
110 | self.add_border(true);
111 |
112 | let mut builder_buttons = HashMap::new();
113 | mem::swap(&mut self.buttons, &mut builder_buttons);
114 | let buttons = builder_buttons.drain().map(|(_, (pos, action))| {
115 | let id = self.form_button(pos.expect("button position must be set"));
116 | (id, action)
117 | }).collect();
118 |
119 | let mut builder_lasors = Vec::new();
120 | mem::swap(&mut self.lasors, &mut builder_lasors);
121 | let lasors = builder_lasors.drain(..).map(|(pos, kind, color)| self.form_lasor(pos, kind, color)).collect();
122 |
123 | let mut board = GameBoard {
124 | id_gen: self.id_gen,
125 | collider: self.collider,
126 | move_dir: None,
127 | player: self.player.unwrap(),
128 | star: self.star.unwrap(),
129 | grid,
130 | room_dims: self.room_dims,
131 | platforms: HashMap::new(),
132 | step_queue: StepQueue::new(),
133 | buttons,
134 | effects: Vec::new(),
135 | warps: HashMap::new(),
136 | respawns: self.respawns,
137 | lasors,
138 | };
139 | for (pos, kind) in self.platforms.drain(..) { board.add_platform(pos, kind); }
140 | for (pos, color) in self.warps.drain(..) { board.add_warp(idx_to_vec(pos), color, Vec2::zero(), None); }
141 | board
142 | }
143 |
144 | fn form_button(&mut self, pos: Idx2) -> HbId {
145 | let id = self.id_gen.next();
146 | let hitbox = button::shape(pos).still();
147 | let profile = PieceProfile::new(id, PieceKind::Button);
148 | let overlaps = self.collider.add_hitbox(profile, hitbox);
149 | assert!(overlaps.is_empty(), "unexpected overlap with button");
150 | id
151 | }
152 |
153 | fn form_lasor(&mut self, pos: Idx2, kind: LasorKind, color: WarpColor) -> Lasor {
154 | let all_cards = Card::values();
155 | let card = all_cards.iter().cloned().find(|&c| {
156 | self.neighbor(pos, card_offset(c.flip())) == Some(PendingCell::Wall)
157 | }).expect("lasor was not adjacent to a wall");
158 | Lasor::new(pos, kind, color, card)
159 | }
160 |
161 | fn add_border(&mut self, right: bool) {
162 | let (width, height) = (self.room_dims.0 as f64 * 8., self.room_dims.1 as f64 * 8.);
163 | let shape = Shape::rect(v2(8., height));
164 | let x = if right { width } else { 0. };
165 | let shape = shape.place(v2(x, 0.5 * height));
166 | let pr = PieceProfile::new(self.id_gen.next(), PieceKind::Wall);
167 | let overlaps = self.collider.add_hitbox(pr, shape.still());
168 | assert!(overlaps.is_empty(), "unexpected border overlap");
169 | }
170 |
171 | fn form_grid_cell(&mut self, pos: Idx2) -> Cell {
172 | let kind = self.grid[&pos];
173 | let id = self.id_gen.next();
174 | let cell = match kind {
175 | PendingCell::Wall => {
176 | let mut neighbors = [false; 8];
177 | let neighbor_offsets = [(-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0)];
178 | for (idx, &offset) in neighbor_offsets.iter().enumerate() {
179 | neighbors[idx] = match self.neighbor(pos, offset) {
180 | Some(PendingCell::Wall) | Some(PendingCell::Spawn(_, _)) => true,
181 | _ => false,
182 | }
183 | }
184 | Cell::wall(id, neighbors)
185 | },
186 | PendingCell::Floor => {
187 | let neighbors = [self.neighbor(pos, (-1, 0)).is_some(), self.neighbor(pos, (1, 0)).is_some()];
188 | Cell::floor(id, neighbors)
189 | },
190 | PendingCell::Gate => Cell::gate(id),
191 | PendingCell::Spawn(color, mirror) => Cell::spawn(id, color, mirror),
192 | };
193 | let hitbox = Shape::square(CELL_LEN as f64).place(idx_to_vec(pos)).still();
194 | let overlaps = self.collider.add_hitbox(PieceProfile::cell(id, pos, cell.kind()), hitbox);
195 | assert!(overlaps.is_empty(), "unexpected overlap with grid cell");
196 | cell
197 | }
198 |
199 | fn neighbor(&mut self, pos: Idx2, offset: Idx2) -> Option {
200 | let pos = (pos.0 + offset.0, pos.1 + offset.1);
201 | if pos.0 < 0 || pos.1 < 0 || pos.0 >= self.room_dims.0 || pos.1 >= self.room_dims.1 {
202 | Some(PendingCell::Wall)
203 | } else {
204 | self.grid.get(&pos).cloned()
205 | }
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/game/button.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use gate::renderer::{SpriteRenderer, Affine};
18 |
19 | use collider::geom::{Shape, PlacedShape, v2};
20 |
21 | use crate::asset_id::{AssetId, SpriteId};
22 | use super::{CELL_LEN, Idx2};
23 | use super::platform::PlatformKind;
24 | use super::util::idx_to_vec;
25 |
26 | const WIDTH: f64 = CELL_LEN as f64 - 0.1;
27 | const HEIGHT: f64 = 1.;
28 | const Y_OFFSET: f64 = -0.5 * CELL_LEN as f64 + 0.5 * HEIGHT;
29 |
30 | pub struct ButtonAction { pub unlock_cells: Vec, pub platforms: Vec<(Idx2, PlatformKind)> }
31 |
32 | pub fn shape(pos: Idx2) -> PlacedShape {
33 | Shape::rect(v2(WIDTH, HEIGHT)).place(idx_to_vec(pos) + v2(0., Y_OFFSET))
34 | }
35 |
36 | pub fn draw(renderer: &mut SpriteRenderer, affine: Affine) {
37 | renderer.draw(&affine.pre_translate(0., -Y_OFFSET), SpriteId::TileR1C2);
38 | }
39 |
--------------------------------------------------------------------------------
/src/game/cell.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use gate::renderer::{SpriteRenderer, Affine};
18 |
19 | use collider::HbId;
20 | use collider::geom::Vec2;
21 |
22 | use crate::asset_id::{AssetId, SpriteId};
23 | use super::warp::WarpColor;
24 |
25 | #[derive(Copy, Clone)]
26 | enum CellTransform { Id, Turn90, Turn180, Turn270, Mirror }
27 |
28 | #[derive(Copy, Clone, PartialEq, Eq)]
29 | pub enum CellKind { Wall, Floor }
30 |
31 | pub struct Cell { id: HbId, kind: CellKind, tile: SpriteId, transform: CellTransform }
32 |
33 | impl Cell {
34 | // neighbors flags start at the top-left neighbor and circles clockwise
35 | pub fn wall(id: HbId, neighbors: [bool; 8]) -> Cell {
36 | let (tile, transform) = wall_tile_and_transform(neighbors);
37 | Cell { id, kind: CellKind::Wall, tile, transform }
38 | }
39 |
40 | // neighbors flags are for left and right neighbors respectively
41 | pub fn floor(id: HbId, neighbors: [bool; 2]) -> Cell {
42 | let (tile, transform) = match (neighbors[0], neighbors[1]) {
43 | (false, true) => (SpriteId::TileR0C0, CellTransform::Id),
44 | (true, false) => (SpriteId::TileR0C0, CellTransform::Mirror),
45 | (true, true) => (SpriteId::TileR0C1, CellTransform::Id),
46 | _ => panic!("no suitable floor tile to display given surrounding tiles"),
47 | };
48 | Cell { id, kind: CellKind::Floor, tile, transform }
49 | }
50 |
51 | pub fn gate(id: HbId) -> Cell {
52 | Cell { id, kind: CellKind::Wall, tile: SpriteId::TileR1C3, transform: CellTransform::Id }
53 | }
54 |
55 | pub fn spawn(id: HbId, color: WarpColor, mirrored: bool) -> Cell {
56 | let tile = match color {
57 | WarpColor::Green => SpriteId::TileR2C0,
58 | WarpColor::Blue => SpriteId::TileR2C1,
59 | WarpColor::Pink => SpriteId::TileR2C2,
60 | };
61 | let transform = if mirrored { CellTransform::Mirror } else { CellTransform::Id };
62 | Cell { id, kind: CellKind::Wall, tile, transform }
63 | }
64 |
65 | pub fn id(&self) -> HbId { self.id }
66 | pub fn kind(&self) -> CellKind { self.kind }
67 |
68 | pub fn draw(&self, renderer: &mut SpriteRenderer, pos: Vec2) {
69 | let affine = Affine::translate(pos.x, pos.y);
70 | let affine = match self.transform {
71 | CellTransform::Id => affine,
72 | CellTransform::Turn90 => affine.pre_rotate(-90_f64.to_radians()),
73 | CellTransform::Turn180 => affine.pre_rotate(-180_f64.to_radians()),
74 | CellTransform::Turn270 => affine.pre_rotate(-270_f64.to_radians()),
75 | CellTransform::Mirror => affine.pre_scale_axes(-1., 1.),
76 | };
77 | renderer.draw(&affine, self.tile);
78 | }
79 | }
80 |
81 | fn wall_tile_and_transform(neighbors: [bool; 8]) -> (SpriteId, CellTransform) {
82 | let transform_map = [CellTransform::Id, CellTransform::Turn90, CellTransform::Turn180, CellTransform::Turn270];
83 | for turns in 0..4 {
84 | if let Some(tile) = wall_tile(neighbors, turns * 2) {
85 | return (tile, transform_map[turns]);
86 | }
87 | }
88 | panic!("no suitable wall tile to display given surrounding tiles")
89 | }
90 |
91 | fn wall_tile(neighbors: [bool; 8], neighbors_shift: usize) -> Option {
92 | let n = |idx| neighbors[(idx + neighbors_shift) % 8];
93 | match (n(0), n(1), n(2), n(3), n(4), n(5), n(6), n(7)) {
94 | (_, false, _, true, true, true, _, false) => Some(SpriteId::TileR0C2),
95 | (true, true, true, true, false, true, true, true) => Some(SpriteId::TileR0C3),
96 | (_, false, _, true, true, true, true, true) => Some(SpriteId::TileR1C0),
97 | (true, true, true, true, true, true, true, true) => Some(SpriteId::TileR1C1),
98 | _ => None,
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/game/effect.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use gate::renderer::{SpriteRenderer, Affine};
18 |
19 | use collider::geom::Vec2;
20 |
21 | use crate::asset_id::{AssetId, SpriteId};
22 | use super::util::vec_to_affine;
23 | use super::warp::WarpColor;
24 |
25 | pub struct Effect { value: Box, pos: Vec2, start_time: f64 }
26 |
27 | impl Effect {
28 | pub fn draw(&self, renderer: &mut SpriteRenderer, camera: Vec2, time: f64) -> bool {
29 | self.value.draw(renderer, &vec_to_affine(self.pos - camera), time - self.start_time)
30 | }
31 | }
32 |
33 | trait InternalEffect {
34 | fn draw(&self, renderer: &mut SpriteRenderer, affine: &Affine, time: f64) -> bool;
35 | }
36 |
37 | struct SquareFade;
38 |
39 | impl InternalEffect for SquareFade {
40 | fn draw(&self, renderer: &mut SpriteRenderer, affine: &Affine, time: f64) -> bool {
41 | let scale = 1. - time / 0.3;
42 | if scale > 0. {
43 | renderer.draw(&affine.pre_scale(scale), SpriteId::WhiteSquare);
44 | true
45 | } else {
46 | false
47 | }
48 | }
49 | }
50 |
51 | pub fn square_fade(pos: Vec2, start_time: f64) -> Effect {
52 | Effect { pos, start_time, value: Box::new(SquareFade) }
53 | }
54 |
55 | struct ColorFade { color: WarpColor }
56 |
57 | impl InternalEffect for ColorFade {
58 | fn draw(&self, renderer: &mut SpriteRenderer, affine: &Affine, time: f64) -> bool {
59 | let scale = 1.0 - time / 0.3;
60 | if scale > 0.0 {
61 | let tex = match self.color {
62 | WarpColor::Green => SpriteId::GreenFade,
63 | WarpColor::Blue => SpriteId::BlueFade,
64 | WarpColor::Pink => SpriteId::PinkFade,
65 | };
66 | renderer.draw(&affine.pre_scale(scale), tex);
67 | true
68 | } else {
69 | false
70 | }
71 | }
72 | }
73 |
74 | pub fn color_fade(pos: Vec2, start_time: f64, color: WarpColor) -> Effect {
75 | Effect { pos, start_time, value: Box::new(ColorFade { color }) }
76 | }
77 |
78 | struct Puff { angle: f64, }
79 |
80 | impl InternalEffect for Puff {
81 | fn draw(&self, renderer: &mut SpriteRenderer, affine: &Affine, time: f64) -> bool {
82 | let affine = affine.pre_rotate(self.angle).pre_translate(0., 2.);
83 | let ratio = time / 0.15;
84 | if ratio < 1. {
85 | let dist = 1.5 + 3. * ratio;
86 | renderer.draw(&affine.pre_translate(dist, 0.), SpriteId::Puff);
87 | renderer.draw(&affine.pre_translate(-dist, 0.).pre_scale_axes(-1., 1.), SpriteId::Puff);
88 | true
89 | } else {
90 | false
91 | }
92 | }
93 | }
94 |
95 | pub fn puff(pos: Vec2, start_time: f64, angle: f64) -> Effect {
96 | Effect { pos, start_time, value: Box::new(Puff { angle }) }
97 | }
98 |
--------------------------------------------------------------------------------
/src/game/mod.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | mod background;
18 | mod builder;
19 | mod button;
20 | mod cell;
21 | mod effect;
22 | mod step_queue;
23 | mod piece_profile;
24 | mod platform;
25 | mod player_enum;
26 | mod player;
27 | mod star;
28 | mod util;
29 | mod warp;
30 |
31 | use std::collections::HashMap;
32 | use std::f64;
33 |
34 | use gate::{Audio, AppContext};
35 | use gate::renderer::Renderer;
36 |
37 | use collider::{Collider, HbId, HbVel, HbEvent, HbProfile};
38 | use collider::geom::{v2, Vec2, Card, CardMask, Shape};
39 |
40 | use crate::game_input::{InputEvent, HorizDir};
41 | use crate::asset_id::{AssetId, SoundId};
42 | use self::piece_profile::{PieceKind, PieceProfile};
43 | use self::player_enum::{PlayerEnum, PlayerComplete, PlayerWarping};
44 | use self::player::Player;
45 | use self::step_queue::{StepQueue, Step};
46 | use self::cell::{Cell, CellKind};
47 | use self::effect::Effect;
48 | use self::star::Star;
49 | use self::platform::Platform;
50 | use self::button::ButtonAction;
51 | use self::util::{IdGen, idx_to_vec, vec_to_affine, card_offset};
52 | use self::warp::Lasor;
53 |
54 | pub use self::builder::GameBoardBuilder;
55 | pub use self::platform::PlatformKind;
56 | pub use self::warp::{WarpColor, LasorKind};
57 |
58 | pub type Idx2 = (i32, i32);
59 |
60 | const CELL_LEN: i32 = 8;
61 | pub const SCREEN_PIXELS_HEIGHT: f64 = CELL_LEN as f64 * 24.;
62 |
63 | pub struct GameBoard {
64 | id_gen: IdGen,
65 | collider: Collider,
66 | move_dir: Option,
67 | player: PlayerEnum,
68 | star: Star,
69 | grid: HashMap,
70 | room_dims: Idx2,
71 | platforms: HashMap,
72 | step_queue: StepQueue,
73 | buttons: HashMap,
74 | effects: Vec,
75 | warps: HashMap,
76 | respawns: HashMap,
77 | lasors: Vec,
78 | }
79 |
80 | impl GameBoard {
81 | pub fn builder(dims: Idx2) -> GameBoardBuilder { GameBoardBuilder::new(dims) }
82 | pub fn is_done(&self) -> bool { self.time() > self.star.level_end_time() }
83 |
84 | fn room_pixels(&self) -> Vec2 { v2((self.room_dims.0 * CELL_LEN) as f64, (self.room_dims.1 * CELL_LEN) as f64) }
85 | fn player_pos(&self) -> Vec2 { self.player.pos(&self.collider) }
86 | fn time(&self) -> f64 { self.collider.time() }
87 |
88 | pub fn input(&mut self, event: InputEvent) {
89 | match event {
90 | InputEvent::UpdateMovement(dir) => self.move_dir = dir,
91 | _ => {},
92 | }
93 | if let PlayerEnum::Normal(ref mut player) = self.player {
94 | match event {
95 | InputEvent::UpdateMovement(dir) => player.set_movement(dir),
96 | InputEvent::PressJump => player.press_jump(),
97 | InputEvent::ReleaseJump => player.release_jump(),
98 | }
99 | }
100 | }
101 |
102 | pub fn advance(&mut self, elapsed: f64, audio: &mut Audio) {
103 | let end_time = self.time() + elapsed;
104 | if self.time() == 0.0 && end_time > 0.0 { audio.play_sound(SoundId::Clear); }
105 | while self.time() < end_time {
106 | let collider_time = self.collider.next_time();
107 | let event_time = self.step_queue.peek();
108 | let player_transition_time = self.player.transition_time();
109 | let time = collider_time.min(event_time).min(end_time).min(player_transition_time);
110 | self.collider.set_time(time);
111 | if let PlayerEnum::Normal(ref mut player) = self.player { player.set_time(time); }
112 | if time == event_time {
113 | match self.step_queue.pop() {
114 | Step::Player => self.player_step(audio),
115 | Step::Platform => self.platform_step(),
116 | Step::WarpEffectSpawn => self.warp_effect_step(),
117 | Step::LasorFire => self.lasors_step(audio),
118 | }
119 | } else if time == player_transition_time {
120 | self.player_transition(audio);
121 | } else if let Some((hb_event, p_1, p_2)) = self.collider.next() {
122 | self.handle_hb_event_asym(hb_event, p_1, p_2, audio);
123 | self.handle_hb_event_asym(hb_event, p_2, p_1, audio);
124 | }
125 | }
126 | }
127 |
128 | fn player_transition(&mut self, audio: &mut Audio) {
129 | if let PlayerEnum::Warping(_) = self.player { audio.play_sound(SoundId::Warp) }
130 | let pos = self.player_pos();
131 | let (player, shape) = Player::new(self.id_gen.next(), pos, self.collider.time(), self.move_dir);
132 | let hitbox = shape.still_until(self.step_queue.peek_specific(Step::Player));
133 | let overlaps = self.collider.add_hitbox(PieceProfile::new(player.id(), PieceKind::Player), hitbox);
134 | assert!(overlaps.iter().all(|p| p.kind == PieceKind::Platform), "unexpected overlap with new player");
135 | self.player = PlayerEnum::Normal(player);
136 | }
137 |
138 | fn handle_hb_event_asym(&mut self, event: HbEvent, p_1: PieceProfile, p_2: PieceProfile, audio: &mut Audio) {
139 | match p_1.kind {
140 | PieceKind::Player => match p_2.kind {
141 | PieceKind::Wall | PieceKind::Floor | PieceKind::Platform => self.update_player_barriers(),
142 | PieceKind::Button if event == HbEvent::Collide => self.press_button(p_2.id(), audio),
143 | PieceKind::Warp if event == HbEvent::Collide => self.warp(p_2.id(), audio),
144 | PieceKind::Star if event == HbEvent::Collide => self.obtain_star(audio),
145 | _ => {},
146 | },
147 | PieceKind::Warp if event == HbEvent::Collide => match p_2.kind {
148 | PieceKind::Wall => self.warp_hits_wall(p_1.id, p_2.id, CardMask::full()),
149 | PieceKind::Floor | PieceKind::Platform => self.warp_hits_wall(p_1.id, p_2.id, Card::PlusY.into()),
150 | _ => {},
151 | },
152 | _ => {},
153 | }
154 | }
155 |
156 | fn update_player_barriers(&mut self) {
157 | let is_near_ground = self.check_player_near_ground();
158 | if let PlayerEnum::Normal(ref mut player) = self.player {
159 | let player_shape = self.collider.get_hitbox(player.id()).value;
160 | let barrier_prs = self.collider.get_overlaps(player.id());
161 | let (grid, collider) = (&self.grid, &self.collider);
162 | let barriers = barrier_prs.iter().filter_map(|pr| match pr.kind {
163 | PieceKind::Floor | PieceKind::Platform => Some((collider.get_hitbox(pr.id), Card::PlusY.into())),
164 | PieceKind::Wall if pr.index.is_some() => {
165 | let wall_hitbox = collider.get_hitbox(pr.id);
166 | let player_above_wall = player_shape.masked_normal_from(
167 | &wall_hitbox.value, Card::PlusY.into()).len() < PieceProfile::padding();
168 | let mask = wall_card_mask(grid, pr.index.unwrap(), player_above_wall);
169 | if mask == CardMask::empty() { None } else { Some((wall_hitbox, mask)) }
170 | },
171 | PieceKind::Wall => Some((collider.get_hitbox(pr.id), CardMask::full())),
172 | _ => None,
173 | });
174 | player.update_barriers(player_shape, is_near_ground, barriers);
175 | } else {
176 | unreachable!();
177 | }
178 | self.update_player_hitbox_vel();
179 | }
180 |
181 | fn check_player_near_ground(&self) -> bool {
182 | if let PlayerEnum::Normal(ref player) = self.player {
183 | let player_shape = self.collider.get_hitbox(player.id()).value;
184 | let padding = PieceProfile::padding();
185 | let test_shape = Shape::rect(Vec2::zero())
186 | .place(player_shape.pos + v2(0., -0.5 * player_shape.dims().y - padding));
187 | let mut overlaps = self.collider.query_overlaps(&test_shape, &PieceProfile::new(player.id(), PieceKind::Player));
188 | let result = overlaps.drain(..).any(|p| {
189 | p.kind == PieceKind::Wall || p.kind == PieceKind::Floor
190 | });
191 | result
192 | } else {
193 | unreachable!()
194 | }
195 | }
196 |
197 | fn update_player_hitbox_vel(&mut self) {
198 | if let PlayerEnum::Normal(ref player) = self.player {
199 | let next_time = self.step_queue.peek_specific(Step::Player);
200 | self.collider.set_hitbox_vel(player.id(), HbVel::moving_until(player.vel(), next_time));
201 | }
202 | }
203 |
204 | fn obtain_star(&mut self, audio: &mut Audio) {
205 | let time = self.time();
206 | self.star.obtain(time);
207 | let pos = self.player_pos();
208 | let (tex, mirror) = if let PlayerEnum::Normal(ref mut player) = self.player {
209 | self.collider.remove_hitbox(player.id());
210 | player.tex_and_mirror()
211 | } else {
212 | unreachable!()
213 | };
214 |
215 | self.player = PlayerEnum::Complete(PlayerComplete::new(pos, time, tex, mirror));
216 | audio.play_sound(SoundId::Clear);
217 | }
218 |
219 | fn warp(&mut self, warp_id: HbId, audio: &mut Audio) {
220 | audio.play_sound(SoundId::Warp);
221 | let color = *self.warps.get(&warp_id).unwrap();
222 | if self.collider.get_hitbox(warp_id).vel.value != Vec2::zero() {
223 | self.collider.remove_hitbox(warp_id);
224 | self.warps.remove(&warp_id);
225 | }
226 | let start_pos = self.player_pos();
227 | let end_pos = self.respawns[&color];
228 | if let PlayerEnum::Normal(ref player) = self.player { self.collider.remove_hitbox(player.id()); } else { unreachable!() }
229 | self.player = PlayerEnum::Warping(PlayerWarping::new(start_pos, end_pos, color, self.time()));
230 | }
231 |
232 | fn warp_hits_wall(&mut self, warp_id: HbId, wall_id: HbId, card_mask: CardMask) {
233 | let warp_shape = self.collider.get_hitbox(warp_id).value;
234 | let wall_shape = self.collider.get_hitbox(wall_id).value;
235 | let normal = warp_shape.masked_normal_from(&wall_shape, card_mask);
236 | if normal.len() < PieceProfile::padding() {
237 | self.warps.remove(&warp_id);
238 | self.collider.remove_hitbox(warp_id);
239 | let pos = warp_shape.pos - normal.dir() * 0.5 * warp_shape.dims().x;
240 | let angle = normal.dir().y.atan2(normal.dir().x) - 0.5 * f64::consts::PI;
241 | self.effects.push(effect::puff(pos, self.collider.time(), angle));
242 | }
243 | }
244 |
245 | fn press_button(&mut self, button_id: HbId, audio: &mut Audio) {
246 | audio.play_sound(SoundId::Button);
247 | self.collider.remove_hitbox(button_id);
248 | let mut actions = self.buttons.remove(&button_id).unwrap();
249 | for pos in actions.unlock_cells.drain(..) { self.remove_cell(pos); }
250 | for (pos, kind) in actions.platforms.drain(..) { self.add_platform(pos, kind); }
251 | }
252 |
253 | fn remove_cell(&mut self, pos: Idx2) {
254 | let cell = self.grid.remove(&pos).unwrap();
255 | let overlaps = self.collider.remove_hitbox(cell.id());
256 | assert!(overlaps.is_empty(), "unexpected overlap with removed cell");
257 | self.effects.push(effect::square_fade(idx_to_vec(pos), self.collider.time()));
258 | }
259 |
260 | fn add_platform(&mut self, pos: Idx2, kind: PlatformKind) {
261 | let update_time = self.step_queue.peek_specific(Step::Platform);
262 | for (platform, hitbox) in Platform::new(kind, pos, self.time(), update_time) {
263 | let id = self.id_gen.next();
264 | self.platforms.insert(id, platform);
265 | self.collider.add_hitbox(PieceProfile::new(id, PieceKind::Platform), hitbox);
266 | }
267 | }
268 |
269 | fn add_warp(&mut self, pos: Vec2, color: WarpColor, vel: Vec2, audio: Option<&mut Audio>) {
270 | let id = self.id_gen.next();
271 | self.warps.insert(id, color);
272 | let hitbox = warp::shape().place(pos).moving(vel);
273 | let overlaps = self.collider.add_hitbox(PieceProfile::new(id, PieceKind::Warp), hitbox);
274 | let mut warping = false;
275 | for overlap in overlaps {
276 | match overlap.kind {
277 | PieceKind::Platform | PieceKind::Floor => {},
278 | PieceKind::Player => warping = true,
279 | _ => panic!("unexpected overlap with warp"),
280 | }
281 | }
282 | if warping { self.warp(id, audio.expect("unexpected warping with audio unavailable")) };
283 | }
284 |
285 | fn player_step(&mut self, audio: &mut Audio) {
286 | if let PlayerEnum::Normal(ref mut player) = self.player { player.step(audio); }
287 | self.update_player_hitbox_vel();
288 | }
289 |
290 | fn platform_step(&mut self) {
291 | let time = self.time();
292 | let next_time = self.step_queue.peek_specific(Step::Platform);
293 | for (&id, platform) in self.platforms.iter() {
294 | let mut hitbox = self.collider.get_hitbox(id);
295 | hitbox.vel = platform.step(hitbox.value.pos, time, next_time);
296 | self.collider.set_hitbox_vel(id, hitbox.vel.clone());
297 |
298 | if let PlayerEnum::Normal(ref mut player) = self.player {
299 | if self.collider.is_overlapping(id, player.id()) {
300 | let next_player_step_time = self.step_queue.peek_specific(Step::Player);
301 | let player_shape = self.collider.get_hitbox(player.id()).value;
302 | player.update_platform_vel(&player_shape, &hitbox);
303 | self.collider.set_hitbox_vel(player.id(), HbVel::moving_until(player.vel(), next_player_step_time));
304 | }
305 | }
306 | }
307 | }
308 |
309 | fn warp_effect_step(&mut self) {
310 | let color = match self.player {
311 | PlayerEnum::Warping(ref player) => Some(player.color()),
312 | _ => None,
313 | };
314 | if let Some(color) = color {
315 | let pos = self.player_pos();
316 | self.effects.push(effect::color_fade(pos, self.collider.time(), color));
317 | }
318 | }
319 |
320 | fn lasors_step(&mut self, audio: &mut Audio) {
321 | if self.lasors.len() > 0 {
322 | audio.play_sound(SoundId::Lasor);
323 | let player_pos = self.player_pos();
324 | let mut new_warps: Vec<_> = self.lasors.iter().map(|l| l.fire(player_pos)).collect();
325 | for (warp_pos, warp_color, warp_vel) in new_warps.drain(..) {
326 | self.add_warp(warp_pos, warp_color, warp_vel, Some(audio));
327 | }
328 | }
329 | }
330 |
331 | // TODO consider only drawing tiles that are on-screen?
332 | pub fn draw(&mut self, renderer: &mut Renderer, ctx: &AppContext) {
333 | let time = self.time();
334 | let player_pos = self.player_pos();
335 | let camera = self.camera_pos(ctx);
336 | background::draw(renderer, camera, self.room_pixels(), time, ctx.dims().0);
337 | let renderer = &mut renderer.sprite_mode();
338 | for (&pos, cell) in self.grid.iter() { cell.draw(renderer, idx_to_vec(pos) - camera); }
339 | for &button_id in self.buttons.keys() {
340 | button::draw(renderer, vec_to_affine(self.hb_pos(button_id) - camera));
341 | }
342 | for (&platform_id, platform) in self.platforms.iter() {
343 | platform.draw(renderer, vec_to_affine(self.hb_pos(platform_id) - camera), time);
344 | }
345 | let next_lasor_fire_time = self.step_queue.peek_specific(Step::LasorFire);
346 | for lasor in &self.lasors {
347 | lasor.draw(renderer, camera, time, next_lasor_fire_time, player_pos);
348 | }
349 | for (&warp_id, &warp_color) in self.warps.iter() {
350 | warp_color.draw_warp(renderer, vec_to_affine(self.hb_pos(warp_id) - camera), time);
351 | }
352 | self.star.draw(renderer, vec_to_affine(self.hb_pos(self.star.id()) - camera), time);
353 | self.effects.retain(|e| e.draw(renderer, camera, time));
354 | self.player.draw(renderer, vec_to_affine(player_pos - camera), time);
355 | }
356 |
357 | fn camera_pos(&self, ctx: &AppContext) -> Vec2 {
358 | let screen_pixels_width = ctx.dims().0;
359 | fn coord(player: f64, room_pixels: f64, screen_pixels: f64) -> f64 {
360 | (player - 0.5 * screen_pixels).max(0.).min(room_pixels - screen_pixels)
361 | }
362 | let player = self.player_pos();
363 | let room_pixels = self.room_pixels();
364 | let (x, y) = (coord(player.x, room_pixels.x, screen_pixels_width), coord(player.y, room_pixels.y, SCREEN_PIXELS_HEIGHT));
365 | let (x, y) = ctx.native_px_align(x, y);
366 | v2(x, y)
367 | }
368 |
369 | fn hb_pos(&self, id: HbId) -> Vec2 { self.collider.get_hitbox(id).value.pos }
370 | }
371 |
372 | fn wall_card_mask(grid: &HashMap, index: Idx2, player_above_wall: bool) -> CardMask {
373 | let mut card_mask = CardMask::empty();
374 | for &card in Card::values().iter() {
375 | let offset = card_offset(card);
376 | let neighbor_kind = grid.get(&(index.0 + offset.0, index.1 + offset.1)).map(|cell| cell.kind());
377 | card_mask[card] = match neighbor_kind {
378 | Some(CellKind::Wall) => false,
379 | Some(CellKind::Floor) => match card {
380 | Card::PlusY | Card::MinusY => true,
381 | Card::PlusX | Card::MinusX => !player_above_wall,
382 | },
383 | _ => true,
384 | };
385 | }
386 | card_mask
387 | }
388 |
--------------------------------------------------------------------------------
/src/game/piece_profile.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use collider::{HbId, HbProfile};
18 |
19 | use super::{Idx2, CELL_LEN};
20 | use super::cell::CellKind;
21 |
22 | #[derive(Copy, Clone, PartialEq, Eq)]
23 | pub enum PieceKind { Wall, Floor, Player, Platform, Star, Button, Warp }
24 |
25 | impl From for PieceKind {
26 | fn from(kind: CellKind) -> PieceKind {
27 | match kind {
28 | CellKind::Wall => PieceKind::Wall,
29 | CellKind::Floor => PieceKind::Floor,
30 | }
31 | }
32 | }
33 |
34 | #[derive(Copy, Clone)]
35 | pub struct PieceProfile { pub id: HbId, pub index: Option, pub kind: PieceKind }
36 |
37 | impl PieceProfile {
38 | pub fn new(id: HbId, kind: PieceKind) -> PieceProfile {
39 | PieceProfile { id, kind, index: None }
40 | }
41 |
42 | pub fn cell(id: HbId, index: Idx2, kind: CellKind) -> PieceProfile {
43 | PieceProfile { id, index: Some(index), kind: kind.into() }
44 | }
45 |
46 | fn can_interact_asym(&self, other: &PieceProfile) -> bool {
47 | match self.kind {
48 | PieceKind::Player => match other.kind {
49 | PieceKind::Wall | PieceKind::Floor | PieceKind::Platform | PieceKind::Button | PieceKind::Warp | PieceKind::Star => true,
50 | _ => false,
51 | },
52 | PieceKind::Warp => match other.kind {
53 | PieceKind::Floor | PieceKind::Platform => true,
54 | PieceKind::Wall => other.index.is_some(),
55 | _ => false,
56 | },
57 | _ => false,
58 | }
59 | }
60 | }
61 |
62 | impl HbProfile for PieceProfile {
63 | fn id(&self) -> HbId { self.id }
64 | fn can_interact(&self, other: &Self) -> bool {
65 | self.can_interact_asym(other) || other.can_interact_asym(self)
66 | }
67 |
68 | fn cell_width() -> f64 { CELL_LEN as f64 }
69 | fn padding() -> f64 { 0.025 }
70 | }
71 |
--------------------------------------------------------------------------------
/src/game/platform.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use std::f64;
18 |
19 | use gate::renderer::{SpriteRenderer, Affine};
20 |
21 | use collider::{Hitbox, HbVel};
22 | use collider::geom::{Vec2, v2, Shape};
23 |
24 | use crate::asset_id::{AssetId, SpriteId};
25 | use super::util::idx_to_vec;
26 | use super::Idx2;
27 |
28 | #[derive(Copy, Clone)]
29 | pub enum PlatformKind { Circle, ReverseCircle, UpDown, DownUp, RightLeft, LeftRight }
30 |
31 | impl PlatformKind {
32 | fn radii(self) -> Vec2 {
33 | match self {
34 | PlatformKind::Circle => v2(32., 32.),
35 | PlatformKind::ReverseCircle => v2(32., -32.),
36 | PlatformKind::UpDown => v2(0., 40.),
37 | PlatformKind::DownUp => v2(0., -40.),
38 | PlatformKind::RightLeft => v2(40., 0.),
39 | PlatformKind::LeftRight => v2(-40., 0.),
40 | }
41 | }
42 |
43 | fn count(self) -> u32 {
44 | match self {
45 | PlatformKind::Circle | PlatformKind::ReverseCircle => 4,
46 | _ => 1,
47 | }
48 | }
49 |
50 | fn phase(self, index: u32) -> f64 { (index as f64 / self.count() as f64) * (2. * f64::consts::PI) }
51 |
52 | fn offset(self, index: u32, time: f64) -> Vec2 {
53 | let radii = self.radii();
54 | let angle = time * 1.1 + self.phase(index);
55 | v2(radii.x * angle.cos(), radii.y * angle.sin())
56 | }
57 | }
58 |
59 | pub struct Platform { kind: PlatformKind, index: u32, center: Vec2, fade_in_time: f64 }
60 |
61 | impl Platform {
62 | pub fn new(kind: PlatformKind, pos: Idx2, time: f64, end_time: f64) -> Vec<(Platform, Hitbox)> {
63 | let fade_in_time = if time == 0. { f64::NEG_INFINITY } else { time };
64 | let center = idx_to_vec(pos);
65 | (0..kind.count()).map(|index| {
66 | let platform = Platform { kind, index, fade_in_time, center };
67 | let pos = platform.position_at_time(time);
68 | let vel = platform.step(pos, time, end_time);
69 | (platform, Hitbox::new(Shape::rect(v2(24., 8.)).place(pos), vel))
70 | }).collect()
71 | }
72 |
73 | pub fn step(&self, pos: Vec2, time: f64, end_time: f64) -> HbVel {
74 | let delta_time = end_time - time;
75 | let vel = if delta_time > 0.01 {
76 | let target_pos = self.position_at_time(end_time);
77 | (target_pos - pos) * (1. / delta_time)
78 | } else {
79 | v2(0., 0.)
80 | };
81 | HbVel::moving_until(vel, end_time)
82 | }
83 |
84 | fn position_at_time(&self, time: f64) -> Vec2 { self.center + self.kind.offset(self.index, time) }
85 |
86 | pub fn draw(&self, renderer: &mut SpriteRenderer, affine: Affine, time: f64) {
87 | let time = time - self.fade_in_time;
88 | let flash_ratio = 1.0 - time;
89 | renderer.draw_flash(&affine, SpriteId::Platform, flash_ratio);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/game/player.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use collider::geom::{Card, CardMask, Vec2, PlacedShape, Shape, v2};
18 | use collider::{Hitbox, HbProfile, HbId};
19 |
20 | use gate::Audio;
21 | use gate::renderer::{SpriteRenderer, Affine};
22 |
23 | use super::PieceProfile;
24 | use super::util::nearest_card;
25 | use crate::game_input::HorizDir;
26 | use crate::asset_id::{AssetId, SpriteId, SoundId};
27 |
28 | pub const STEP_PERIOD: f64 = 1. / 60.;
29 |
30 | const MOVE_ACCEL: f64 = 150. * STEP_PERIOD;
31 | const STOP_ACCEL: f64 = 350. * STEP_PERIOD;
32 | const FALL_ACCEL: f64 = 360. * STEP_PERIOD;
33 | const JUMP_SPEED: f64 = 80.;
34 | const MAX_FALL_SPEED: f64 = 120.;
35 | const MAX_MOVE_SPEED: f64 = 80.;
36 | fn jump_duration(x_speed: f64) -> f64 { 0.21 + 0.10 * (x_speed / MAX_MOVE_SPEED) }
37 |
38 | const GRAPHIC_STEP_DURATION: f64 = 0.16;
39 | const GRAPHIC_CHIRP_DELAY: f64 = 0.8;
40 | const GRAPHIC_CHIRP_DURATION: f64 = 0.125;
41 |
42 | pub struct Player {
43 | id: HbId,
44 | time: f64,
45 | dir: HorizDir,
46 | moving: bool,
47 | state_start_time: f64,
48 | on_ground: bool,
49 | jump_held: bool,
50 | queued_jump: bool,
51 | jump_transition_time: f64,
52 | blocked_cards: CardMask,
53 | vel: Vec2,
54 | floor_vel: Vec2,
55 | }
56 |
57 | impl Player {
58 | pub fn new(id: HbId, pos: Vec2, time: f64, move_dir: Option) -> (Player, PlacedShape) {
59 | let mut player = Player {
60 | id,
61 | time,
62 | dir: HorizDir::Right,
63 | moving: false,
64 | state_start_time: time,
65 | on_ground: false,
66 | jump_held: false,
67 | queued_jump: false,
68 | jump_transition_time: time,
69 | blocked_cards: CardMask::empty(),
70 | vel: Vec2::zero(),
71 | floor_vel: Vec2::zero(),
72 | };
73 | player.set_movement(move_dir);
74 | (player, Shape::rect(v2(3.5, 11.)).place(pos))
75 | }
76 |
77 | pub fn set_time(&mut self, time: f64) { self.time = time; }
78 | pub fn id(&self) -> HbId { self.id }
79 | pub fn vel(&self) -> Vec2 { self.vel }
80 |
81 | pub fn update_platform_vel(&mut self, player_shape: &PlacedShape, platform_hb: &Hitbox) {
82 | let normal = player_shape.masked_normal_from(&platform_hb.value, Card::PlusY.into());
83 | if normal.len() < PieceProfile::padding() && self.on_ground {
84 | let vel = platform_hb.vel.value;
85 | let rel_vel_x = self.vel.x - self.floor_vel.x;
86 | self.floor_vel = vel;
87 | self.vel.y = vel.y;
88 | self.vel.x = vel.x + rel_vel_x;
89 | }
90 | }
91 |
92 | pub fn set_movement(&mut self, movement: Option) {
93 | let (moving, dir) = if let Some(dir) = movement { (true, dir) } else { (false, self.dir) };
94 | if self.moving != moving || self.dir != dir { self.state_start_time = self.time; }
95 | self.moving = moving;
96 | self.dir = dir;
97 | }
98 |
99 | pub fn press_jump(&mut self) {
100 | if self.on_ground && !self.queued_jump {
101 | self.queued_jump = true;
102 | self.jump_held = true;
103 | }
104 | }
105 |
106 | pub fn release_jump(&mut self) { self.jump_held = false; }
107 |
108 | pub fn step(&mut self, audio: &mut Audio) {
109 | let stop_accel = if self.on_ground { STOP_ACCEL } else { MOVE_ACCEL };
110 | let rel_vel_x = self.vel.x - self.floor_vel.x;
111 | let rel_vel_x = if self.moving {
112 | let accel = if self.dir.signum() == rel_vel_x.signum() { MOVE_ACCEL } else { stop_accel };
113 | rel_vel_x + self.dir.signum() * accel
114 | } else if self.on_ground {
115 | if rel_vel_x.abs() > stop_accel { rel_vel_x - rel_vel_x.signum() * stop_accel } else { 0.0 }
116 | } else {
117 | rel_vel_x
118 | };
119 | self.vel.x = self.floor_vel.x + rel_vel_x;
120 | if self.queued_jump {
121 | self.jump(audio);
122 | } else if self.time > self.jump_transition_time || !self.jump_held {
123 | self.jump_held = false;
124 | self.vel.y -= FALL_ACCEL;
125 | }
126 | self.bound_vel();
127 | self.update_on_ground(false);
128 | }
129 |
130 | fn jump(&mut self, audio: &mut Audio) {
131 | audio.play_sound(SoundId::Jump);
132 | self.on_ground = false;
133 | self.queued_jump = false;
134 | self.state_start_time = self.time;
135 | self.jump_transition_time = self.time + jump_duration((self.vel.x - self.floor_vel.x).abs());
136 | self.vel.y = JUMP_SPEED + self.floor_vel.y.max(0.0);
137 | self.vel.x = self.vel.x - self.floor_vel.x;
138 | self.floor_vel = Vec2::zero();
139 | }
140 |
141 | pub fn update_barriers>(&mut self, shape: PlacedShape, near_ground: bool, barriers: I) {
142 | let mut barrier_count = 0;
143 | self.blocked_cards = CardMask::empty();
144 | let mut floor_vel = None;
145 | for (hitbox, mask) in barriers {
146 | let normal = shape.masked_normal_from(&hitbox.value, mask);
147 | if normal.len() < PieceProfile::padding() {
148 | if floor_vel.is_none() {
149 | floor_vel = Some(Vec2::zero());
150 | }
151 | let dir = nearest_card(normal.dir()).flip();
152 | self.blocked_cards[dir] = true;
153 | if hitbox.vel.value != Vec2::zero() {
154 | assert!(dir == Card::MinusY, "only floors can be moving barriers");
155 | floor_vel = Some(hitbox.vel.value);
156 | }
157 | barrier_count += 1;
158 | }
159 | }
160 | if let Some(floor_vel) = floor_vel {
161 | self.floor_vel = floor_vel;
162 | }
163 | assert!(self.floor_vel == Vec2::zero() || barrier_count <= 1,
164 | "cannot touch multiple barriers with moving floor");
165 | self.bound_vel();
166 | self.update_on_ground(near_ground);
167 | }
168 |
169 | fn bound_vel(&mut self) {
170 | self.vel.x = self.vel.x.max(-MAX_MOVE_SPEED + self.floor_vel.x);
171 | if self.blocked_cards[Card::MinusX] { self.vel.x = self.vel.x.max(0.0); }
172 | self.vel.x = self.vel.x.min(MAX_MOVE_SPEED + self.floor_vel.x);
173 | if self.blocked_cards[Card::PlusX] { self.vel.x = self.vel.x.min(0.0); }
174 | self.vel.y = self.vel.y.max(-MAX_FALL_SPEED);
175 | if self.blocked_cards[Card::PlusY] {
176 | self.vel.y = self.vel.y.min(0.0);
177 | self.jump_held = false;
178 | }
179 | if self.blocked_cards[Card::MinusY] { self.vel.y = self.vel.y.max(self.floor_vel.y); }
180 | }
181 |
182 | fn update_on_ground(&mut self, near_ground: bool) {
183 | let on_ground = self.blocked_cards[Card::MinusY] && self.vel.y == self.floor_vel.y;
184 | match (self.on_ground, on_ground, near_ground) {
185 | (false, true, _) => {
186 | self.state_start_time = self.time - GRAPHIC_STEP_DURATION; // lands with legs together
187 | self.queued_jump = false;
188 | self.jump_held = false;
189 | self.on_ground = true;
190 | self.bound_vel();
191 | },
192 | (true, false, false) => {
193 | self.floor_vel = Vec2::zero();
194 | self.state_start_time = self.time;
195 | self.queued_jump = false;
196 | self.jump_held = false;
197 | self.on_ground = false;
198 | self.bound_vel();
199 | },
200 | (true, false, true) => {
201 | self.vel.y = -MAX_FALL_SPEED;
202 | self.floor_vel.y = -MAX_FALL_SPEED;
203 | },
204 | _ => {},
205 | }
206 | }
207 |
208 | pub fn tex_and_mirror(&self) -> (SpriteId, bool) {
209 | let time = self.time - self.state_start_time;
210 | let tex = if !self.on_ground {
211 | SpriteId::PlayerRun
212 | } else if self.moving {
213 | let time = time % (2. * GRAPHIC_STEP_DURATION);
214 | if time < GRAPHIC_STEP_DURATION { SpriteId::PlayerRun } else { SpriteId::PlayerStill }
215 | } else {
216 | let time = time % (GRAPHIC_CHIRP_DELAY + GRAPHIC_CHIRP_DURATION);
217 | if time < GRAPHIC_CHIRP_DELAY { SpriteId::PlayerStill } else { SpriteId::PlayerChirp }
218 | };
219 | (tex, self.dir == HorizDir::Left)
220 | }
221 |
222 | pub fn draw(&self, renderer: &mut SpriteRenderer, affine: Affine) {
223 | let (tex, mirror) = self.tex_and_mirror();
224 | let affine = if mirror { affine.pre_scale_axes(-1., 1.) } else { affine };
225 | renderer.draw(&affine, tex);
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/src/game/player_enum.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use std::f64;
18 |
19 | use gate::renderer::{SpriteRenderer, Affine};
20 |
21 | use collider::Collider;
22 | use collider::geom::Vec2;
23 |
24 | use crate::asset_id::{AssetId, SpriteId};
25 | use super::player::Player;
26 | use super::star;
27 | use super::piece_profile::PieceProfile;
28 | use super::warp::WarpColor;
29 |
30 | const START_FADE_VEL: f64 = 1. / 0.6;
31 | const START_DELAY: f64 = 0.7;
32 | const WARP_SPEED: f64 = 180.;
33 |
34 | pub enum PlayerEnum {
35 | Start(Vec2), Normal(Player), Warping(PlayerWarping), Complete(PlayerComplete)
36 | }
37 |
38 | impl PlayerEnum {
39 | pub fn transition_time(&self) -> f64 {
40 | match *self {
41 | PlayerEnum::Warping(ref w) => w.end_time,
42 | PlayerEnum::Start(_) => START_DELAY,
43 | _ => f64::INFINITY,
44 | }
45 | }
46 |
47 | pub fn draw(&self, renderer: &mut SpriteRenderer, affine: Affine, time: f64) {
48 | match *self {
49 | PlayerEnum::Normal(ref player) => player.draw(renderer, affine),
50 | PlayerEnum::Complete(ref player) => {
51 | if time < player.complete_time + star::OBTAIN_VANISH_DELAY {
52 | let fade_time = time - player.complete_time;
53 | let fade = if fade_time > 0. { star::OBTAIN_FADE_VEL * fade_time } else { 0. };
54 | let affine = if player.mirror { affine.pre_scale_axes(-1., 1.) } else { affine };
55 | renderer.draw_flash(&affine, player.tex, fade);
56 | }
57 | },
58 | PlayerEnum::Start(_) => {
59 | let fade = (START_DELAY - time) * START_FADE_VEL;
60 | if fade <= 1. { renderer.draw_flash(&affine, SpriteId::PlayerRun, 0.5 + 0.6 * fade) }
61 | },
62 | PlayerEnum::Warping(_) => {},
63 | }
64 | }
65 |
66 | pub fn pos(&self, collider: &Collider) -> Vec2 {
67 | match *self {
68 | PlayerEnum::Normal(ref player) => collider.get_hitbox(player.id()).value.pos,
69 | PlayerEnum::Start(pos) => pos,
70 | PlayerEnum::Complete(ref player) => player.pos,
71 | PlayerEnum::Warping(ref player) => player.end_pos - player.vel * (player.end_time - collider.time()),
72 | }
73 | }
74 | }
75 |
76 | pub struct PlayerComplete { pos: Vec2, complete_time: f64, tex: SpriteId, mirror: bool }
77 |
78 | impl PlayerComplete {
79 | pub fn new(pos: Vec2, complete_time: f64, tex: SpriteId, mirror: bool) -> PlayerComplete {
80 | PlayerComplete { pos, complete_time, tex, mirror }
81 | }
82 | }
83 |
84 | pub struct PlayerWarping { end_time: f64, color: WarpColor, end_pos: Vec2, vel: Vec2 }
85 |
86 | impl PlayerWarping {
87 | pub fn new(start_pos: Vec2, end_pos: Vec2, color: WarpColor, time: f64) -> PlayerWarping {
88 | let delta_pos = end_pos - start_pos;
89 | let dir = delta_pos.normalize().unwrap_or(Vec2::zero());
90 | PlayerWarping { color, end_pos, vel: dir * WARP_SPEED, end_time: time + delta_pos.len() / WARP_SPEED }
91 | }
92 |
93 | pub fn color(&self) -> WarpColor { self.color }
94 | }
95 |
--------------------------------------------------------------------------------
/src/game/star.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use std::f64;
18 |
19 | use gate::renderer::{SpriteRenderer, Affine};
20 |
21 | use collider::{HbId, Hitbox};
22 | use collider::geom::Shape;
23 |
24 | use crate::asset_id::{AssetId, SpriteId};
25 | use super::Idx2;
26 | use super::util::idx_to_vec;
27 |
28 | pub const OBTAIN_FADE_VEL: f64 = 1.8;
29 | pub const OBTAIN_VANISH_DELAY: f64 = 0.85;
30 |
31 | pub struct Star { id: HbId, obtain_time: f64 }
32 |
33 | impl Star {
34 | pub fn new(id: HbId, pos: Idx2) -> (Star, Hitbox) {
35 | (Star { id, obtain_time: f64::INFINITY }, Shape::circle(13.).place(idx_to_vec(pos)).still())
36 | }
37 |
38 | pub fn id(&self) -> HbId { self.id }
39 |
40 | pub fn obtain(&mut self, time: f64) { self.obtain_time = time; }
41 |
42 | pub fn level_end_time(&self) -> f64 { self.obtain_time + 1.85 }
43 |
44 | pub fn draw(&self, renderer: &mut SpriteRenderer, affine: Affine, time: f64) {
45 | if time < self.obtain_time + OBTAIN_VANISH_DELAY {
46 | let fade_time = time - self.obtain_time;
47 | let fade = if fade_time > 0. { OBTAIN_FADE_VEL * fade_time } else { 0. };
48 | let angle = Star::angle(time);
49 | let lag_angle = Star::angle(time - 0.21);
50 | renderer.draw_flash(&affine.pre_rotate(lag_angle), SpriteId::Star, 1.);
51 | renderer.draw_flash(&affine.pre_rotate(angle), SpriteId::Star, fade);
52 | }
53 | }
54 |
55 | fn angle(time: f64) -> f64 { 0.3 * (5. * (time - 0.21)).sin() }
56 | }
57 |
--------------------------------------------------------------------------------
/src/game/step_queue.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use super::player;
18 |
19 | #[derive(Copy, Clone)]
20 | pub enum Step { Player, Platform, WarpEffectSpawn, LasorFire }
21 | const STEP_COUNT: usize = 4;
22 | const STEPS: [Step; STEP_COUNT] = [Step::Player, Step::Platform, Step::WarpEffectSpawn, Step::LasorFire ];
23 |
24 | impl Step {
25 | fn period(self) -> f64 {
26 | match self {
27 | Step::Player => player::STEP_PERIOD,
28 | Step::Platform => 0.18,
29 | Step::WarpEffectSpawn => 1. / 30.,
30 | Step::LasorFire => 1.,
31 | }
32 | }
33 | }
34 |
35 | pub struct StepQueue { times: [f64; STEP_COUNT] }
36 |
37 | // queue of steps that repeat periodically
38 | impl StepQueue {
39 | pub fn new() -> StepQueue {
40 | let mut times = [0.; STEP_COUNT];
41 | for &step in STEPS.iter() { times[step as usize] = step.period(); }
42 | StepQueue { times }
43 | }
44 |
45 | // returns time of next step
46 | pub fn peek(&self) -> f64 {
47 | self.times.iter().cloned().min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap()
48 | }
49 |
50 | // returns time that step of given type will be returned next
51 | pub fn peek_specific(&self, step: Step) -> f64 {
52 | self.times[step as usize]
53 | }
54 |
55 | // pops the step to occur at time `self.peek()`
56 | pub fn pop(&mut self) -> Step {
57 | let step = STEPS.iter().cloned()
58 | .min_by(|&a, &b| self.times[a as usize].partial_cmp(&self.times[b as usize]).unwrap())
59 | .unwrap();
60 | self.times[step as usize] += step.period();
61 | step
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/game/util.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use gate::renderer::Affine;
18 |
19 | use collider::geom::{Vec2, v2, Card};
20 |
21 | use super::Idx2;
22 |
23 | pub struct IdGen { next: u64 }
24 |
25 | impl IdGen {
26 | pub fn new() -> IdGen { IdGen { next: 0 } }
27 | pub fn next(&mut self) -> u64 {
28 | let id = self.next;
29 | self.next += 1;
30 | id
31 | }
32 | }
33 |
34 | pub fn idx_to_vec(idx: Idx2) -> Vec2 {
35 | fn idx_to_f64(idx: i32) -> f64 { (idx * 8 + 4) as f64 }
36 | v2(idx_to_f64(idx.0), idx_to_f64(idx.1))
37 | }
38 |
39 | pub fn vec_to_affine(vec: Vec2) -> Affine { Affine::translate(vec.x, vec.y) }
40 |
41 | pub fn card_offset(card: Card) -> Idx2 {
42 | match card {
43 | Card::PlusX => (1, 0),
44 | Card::PlusY => (0, 1),
45 | Card::MinusX => (-1, 0),
46 | Card::MinusY => (0, -1),
47 | }
48 | }
49 |
50 | pub fn nearest_card(vector: Vec2) -> Card {
51 | if vector.x.abs() > vector.y.abs() {
52 | if vector.x > 0.0 { Card::PlusX } else { Card::MinusX }
53 | } else {
54 | if vector.y > 0.0 { Card::PlusY } else { Card::MinusY }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/game/warp.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use std::f64;
18 |
19 | use gate::renderer::{SpriteRenderer, Affine};
20 |
21 | use collider::geom::{Shape, Vec2, v2, Card};
22 |
23 | use crate::asset_id::{AssetId, SpriteId};
24 | use super::Idx2;
25 | use super::util::{idx_to_vec, vec_to_affine};
26 |
27 | const SPIN_VEL: f64 = -4.;
28 |
29 | #[derive(Copy, Clone, PartialEq, Eq, Hash)]
30 | pub enum WarpColor { Green, Blue, Pink }
31 |
32 | impl WarpColor {
33 | pub fn draw_warp(self, renderer: &mut SpriteRenderer, affine: Affine, time: f64) {
34 | renderer.draw(&affine.pre_rotate(time * SPIN_VEL), self.tex());
35 | }
36 |
37 | fn tex(self) -> SpriteId {
38 | match self {
39 | WarpColor::Green => SpriteId::GreenWarp,
40 | WarpColor::Blue => SpriteId::BlueWarp,
41 | WarpColor::Pink => SpriteId::PinkWarp,
42 | }
43 | }
44 | }
45 |
46 | pub fn shape() -> Shape { Shape::circle(7.) }
47 |
48 | #[derive(Copy, Clone)]
49 | pub enum LasorKind { Still, Aiming }
50 |
51 | impl LasorKind {
52 | fn max_angle(self) -> f64 {
53 | match self {
54 | LasorKind::Still => 0.,
55 | LasorKind::Aiming => 30_f64.to_radians(),
56 | }
57 | }
58 | }
59 |
60 | const LASOR_FIRE_SPEED: f64 = 60.;
61 | const LASOR_FIRE_OFFSET: f64 = 7.;
62 |
63 | fn angle_to_vec(angle: f64) -> Vec2 { v2(angle.cos(), angle.sin()) }
64 |
65 | pub struct Lasor { pos: Vec2, card: Card, max_angle: f64, color: WarpColor }
66 |
67 | impl Lasor {
68 | pub fn new(pos: Idx2, kind: LasorKind, color: WarpColor, card: Card) -> Lasor {
69 | Lasor { card, color, pos: idx_to_vec(pos), max_angle: kind.max_angle() }
70 | }
71 |
72 | pub fn fire(&self, player_pos: Vec2) -> (Vec2, WarpColor, Vec2) {
73 | let angle = self.angle(player_pos);
74 | (self.fire_pos(angle), self.color, angle_to_vec(angle) * LASOR_FIRE_SPEED)
75 | }
76 |
77 | fn fire_pos(&self, angle: f64) -> Vec2 {
78 | self.pos + angle_to_vec(angle) * LASOR_FIRE_OFFSET
79 | }
80 |
81 | fn support_angle(&self) -> f64 {
82 | let card_vec: Vec2 = self.card.into();
83 | card_vec.y.atan2(card_vec.x)
84 | }
85 |
86 | fn angle(&self, player_pos: Vec2) -> f64 {
87 | let rel_player = player_pos - self.pos;
88 | let support_angle = self.support_angle();
89 | let angle_delta = (rel_player.y.atan2(rel_player.x) - support_angle) % (2. * f64::consts::PI);
90 | let angle_delta = if angle_delta > f64::consts::PI {
91 | angle_delta - 2. * f64::consts::PI
92 | } else if angle_delta < -f64::consts::PI {
93 | angle_delta + 2. * f64::consts::PI
94 | } else {
95 | angle_delta
96 | };
97 | let angle_delta = if angle_delta > 0.5 * f64::consts::PI {
98 | f64::consts::PI - angle_delta
99 | } else if angle_delta < -0.5 * f64::consts::PI {
100 | -f64::consts::PI - angle_delta
101 | } else {
102 | angle_delta
103 | };
104 | let angle_delta = angle_delta.max(-self.max_angle).min(self.max_angle);
105 | support_angle + angle_delta
106 | }
107 |
108 | pub fn draw(&self, renderer: &mut SpriteRenderer, camera: Vec2, time: f64, next_fire_time: f64, player_pos: Vec2) {
109 | renderer.draw(&vec_to_affine(self.pos - camera).pre_rotate(self.support_angle() + f64::consts::PI), SpriteId::TileR2C3);
110 | let angle = self.angle(player_pos);
111 | let lasor_affine = vec_to_affine(self.pos - camera).pre_rotate(angle + f64::consts::PI);
112 | renderer.draw(&lasor_affine, SpriteId::Lasor);
113 | let ratio = 1. - (next_fire_time - time) * 2.5;
114 | if ratio > 0. {
115 | let scale = 0.2 + 0.8 * ratio;
116 | let flash = 1.0 - 0.5 * ratio;
117 | let affine = vec_to_affine(self.fire_pos(angle) - camera).pre_scale(scale).pre_rotate(time * SPIN_VEL);
118 | renderer.draw_flash(&affine, self.color.tex(), flash);
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/game_input.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use gate::KeyCode;
18 |
19 | #[derive(PartialEq, Eq, Copy, Clone, Hash)]
20 | pub enum HorizDir { Left, Right }
21 |
22 | impl HorizDir {
23 | pub fn signum(self) -> f64 {
24 | match self {
25 | HorizDir::Left => -1.,
26 | HorizDir::Right => 1.,
27 | }
28 | }
29 |
30 | fn from_key(key: KeyCode) -> Option {
31 | match key {
32 | KeyCode::Left => Some(HorizDir::Left),
33 | KeyCode::Right => Some(HorizDir::Right),
34 | _ => None,
35 | }
36 | }
37 | }
38 |
39 | pub enum InputEvent {
40 | UpdateMovement(Option),
41 | PressJump,
42 | ReleaseJump,
43 | }
44 |
45 | pub struct GameInput { held_dirs: Vec }
46 |
47 | impl GameInput {
48 | pub fn new() -> GameInput { GameInput { held_dirs: Vec::new() } }
49 |
50 | pub fn key_down(&mut self, key: KeyCode) -> Option {
51 | if let Some(dir) = HorizDir::from_key(key) {
52 | self.held_dirs.push(dir);
53 | Some(InputEvent::UpdateMovement(Some(dir)))
54 | } else if key == KeyCode::Up {
55 | Some(InputEvent::PressJump)
56 | } else {
57 | None
58 | }
59 | }
60 |
61 | pub fn key_up(&mut self, key: KeyCode) -> Option {
62 | if let Some(dir) = HorizDir::from_key(key) {
63 | self.held_dirs.retain(|&d| d != dir);
64 | Some(InputEvent::UpdateMovement(self.held_dir()))
65 | } else if key == KeyCode::Up {
66 | Some(InputEvent::ReleaseJump)
67 | } else {
68 | None
69 | }
70 | }
71 |
72 | pub fn held_dir(&self) -> Option { self.held_dirs.last().cloned() }
73 | }
74 |
--------------------------------------------------------------------------------
/src/level_loader.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | use crate::game::{GameBoard, LasorKind, PlatformKind, WarpColor, Idx2};
18 |
19 | pub const LEVEL_COUNT: usize = 7;
20 |
21 | const LEVELS: [&'static str; LEVEL_COUNT] = [
22 | include_str!("levels/level0.txt"),
23 | include_str!("levels/level1.txt"),
24 | include_str!("levels/level2.txt"),
25 | include_str!("levels/level3.txt"),
26 | include_str!("levels/level4.txt"),
27 | include_str!("levels/level5.txt"),
28 | include_str!("levels/level6.txt"),
29 | ];
30 |
31 | const LEVELS_INDEX: [&'static str; LEVEL_COUNT] = [
32 | include_str!("levels/level0_index.txt"),
33 | include_str!("levels/level1_index.txt"),
34 | include_str!("levels/level2_index.txt"),
35 | include_str!("levels/level3_index.txt"),
36 | include_str!("levels/level4_index.txt"),
37 | include_str!("levels/level5_index.txt"),
38 | include_str!("levels/level6_index.txt"),
39 | ];
40 |
41 | pub fn load(level_num: usize) -> GameBoard {
42 | let level = LevelFile::new(LEVELS[level_num]);
43 | let level_index = LevelFile::new(LEVELS_INDEX[level_num]);
44 |
45 | let mut board = GameBoard::builder(level.dims);
46 | for y in 0..level.dims.1 {
47 | for x in 0..level.dims.0 {
48 | let pos = (x, y);
49 | match (level.get(pos), digit(level_index.get(pos))) {
50 | ('P', None) => board.add_player(pos),
51 | ('@', None) => board.add_star(pos),
52 | ('-', None) => board.add_wall(pos),
53 | ('+', None) => board.add_floor(pos),
54 | ('I', Some(idx)) => board.add_gate(pos, idx),
55 | ('C', idx) => board.add_platform(pos, PlatformKind::Circle, idx),
56 | ('c', idx) => board.add_platform(pos, PlatformKind::ReverseCircle, idx),
57 | ('A', idx) => board.add_platform(pos, PlatformKind::UpDown, idx),
58 | ('V', idx) => board.add_platform(pos, PlatformKind::DownUp, idx),
59 | ('>', idx) => board.add_platform(pos, PlatformKind::RightLeft, idx),
60 | ('<', idx) => board.add_platform(pos, PlatformKind::LeftRight, idx),
61 | ('L', Some(idx)) => board.add_lasor(pos, LasorKind::Still, index_to_color(idx)),
62 | ('H', Some(idx)) => board.add_lasor(pos, LasorKind::Aiming, index_to_color(idx)),
63 | ('B', Some(idx)) => board.add_button(pos, idx),
64 | ('w', Some(idx)) => board.add_respawn(pos, index_to_color(idx)),
65 | ('W', Some(idx)) => board.add_warp(pos, index_to_color(idx)),
66 | (' ', None) => {},
67 | _ => panic!("error reading level {}, position {:?}", level_num, pos),
68 | }
69 | }
70 | }
71 |
72 | board.build()
73 | }
74 |
75 | fn digit(c: char) -> Option {
76 | if c >= '0' && c <= '9' { Some(c as u32 - '0' as u32) } else { None }
77 | }
78 |
79 | fn index_to_color(index: u32) -> WarpColor {
80 | match index {
81 | 0 => WarpColor::Green,
82 | 1 => WarpColor::Blue,
83 | 2 => WarpColor::Pink,
84 | _ => panic!("invalid warp index"),
85 | }
86 | }
87 |
88 | struct LevelFile { dims: Idx2, grid: Vec> }
89 |
90 | impl LevelFile {
91 | fn new(file_contents: &str) -> LevelFile {
92 | let grid: Vec> = file_contents.lines().map(|s| s.chars().collect())
93 | .filter(|s: &Vec| !s.is_empty())
94 | .collect();
95 | LevelFile { dims: (grid[0].len() as i32 - 1, grid.len() as i32), grid }
96 | }
97 |
98 | fn get(&self, pos: Idx2) -> char {
99 | self.grid[(self.dims.1 - 1 - pos.1) as usize][pos.0 as usize]
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/levels/level0.txt:
--------------------------------------------------------------------------------
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | @ |
13 | |
14 | +++++++++++ ----++ < -----|
15 | ---- -----|
16 | ----++ -----|
17 | P ------- ---- -----|
18 | ------- ---- -----|
19 | -----------------------------------------------------|
20 | -----------------------------------------------------|
21 | -----------------------------------------------------|
22 | -----------------------------------------------------|
23 | -----------------------------------------------------|
24 | -----------------------------------------------------|
25 |
--------------------------------------------------------------------------------
/src/levels/level0_index.txt:
--------------------------------------------------------------------------------
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | @ |
13 | |
14 | +++++++++++ ----++ < -----|
15 | ---- -----|
16 | ----++ -----|
17 | P ------- ---- -----|
18 | ------- ---- -----|
19 | -----------------------------------------------------|
20 | -----------------------------------------------------|
21 | -----------------------------------------------------|
22 | -----------------------------------------------------|
23 | -----------------------------------------------------|
24 | -----------------------------------------------------|
25 |
--------------------------------------------------------------------------------
/src/levels/level1.txt:
--------------------------------------------------------------------------------
1 | - -- |
2 | - -- |
3 | - I |
4 | - @ I |
5 | - I |
6 | ------------ +++ +++ |
7 | ------------ |
8 | ------------ |
9 | --- +++ |
10 | --- |
11 | --- B |
12 | -------- +++ |
13 | -------- |
14 | ------ |
15 | ------ C |
16 | -- |
17 | -- B |
18 | -- ---++++---++|
19 | -- --- --- |
20 | ---------- --- --- |
21 | ---------- --- --- --- |
22 | - I --- --- --- |
23 | - I --- --- --- |
24 | - B P I ---- --- --- |
25 | - --- I ---- --- --- |
26 | -------------------------------------------|
27 |
--------------------------------------------------------------------------------
/src/levels/level1_index.txt:
--------------------------------------------------------------------------------
1 | - -- |
2 | - -- |
3 | - 2 |
4 | - @ 2 |
5 | - 2 |
6 | ------------ +++ +++ |
7 | ------------ |
8 | ------------ |
9 | --- +++ |
10 | --- |
11 | --- 2 |
12 | -------- +++ |
13 | -------- |
14 | ------ |
15 | ------ 1 |
16 | -- |
17 | -- 1 |
18 | -- ---++++---++|
19 | -- --- --- |
20 | ---------- --- --- |
21 | ---------- --- --- --- |
22 | - 0 --- --- --- |
23 | - 0 --- --- --- |
24 | - 0 P 0 ---- --- --- |
25 | - --- 0 ---- --- --- |
26 | -------------------------------------------|
27 |
--------------------------------------------------------------------------------
/src/levels/level2.txt:
--------------------------------------------------------------------------------
1 | -- -- -- |
2 | -- -- -- |
3 | -- -- -- |
4 | -- -- -- |
5 | -- -- -- |
6 | -- -- B -- |
7 | -- --+++++--++ -- |
8 | -- @ -- -- -- |
9 | -- -- -- -- |
10 | ------- -- -- -- |
11 | ------- -- -- -- |
12 | ---- -- -- V -- |
13 | ---- -- -- -- |
14 | -- I -- -- |
15 | -- A I -- -- |
16 | -- I -- -- |
17 | -- I I -- |
18 | -- I I -- |
19 | -- I I -- |
20 | -- --+++ I A -- |
21 | -- -- I -- |
22 | -- -- I -- |
23 | -- V -- +++-- -- |
24 | -- -- -- -- |
25 | -- --- B --- -- |
26 | -- ---------++++++++++++-- |
27 | -- ------- -- |
28 | -- B I I B -- |
29 | -----+++ I I +++----- |
30 | ----- I B I ----- |
31 | -- +++-----+++ -- |
32 | -- ----- -- |
33 | -- ----- -- |
34 | -- P --------- -- |
35 | -- ---- ---- -- |
36 | -------------------- --------------------|
37 |
--------------------------------------------------------------------------------
/src/levels/level2_index.txt:
--------------------------------------------------------------------------------
1 | -- -- -- |
2 | -- -- -- |
3 | -- -- -- |
4 | -- -- -- |
5 | -- -- -- |
6 | -- -- 4 -- |
7 | -- --+++++--++ -- |
8 | -- @ -- -- -- |
9 | -- -- -- -- |
10 | ------- -- -- -- |
11 | ------- -- -- -- |
12 | ---- -- -- V -- |
13 | ---- -- -- -- |
14 | -- 1 -- -- |
15 | -- 4 1 -- -- |
16 | -- 1 -- -- |
17 | -- 1 2 -- |
18 | -- 1 2 -- |
19 | -- 1 2 -- |
20 | -- --+++ 2 3 -- |
21 | -- -- 2 -- |
22 | -- -- 2 -- |
23 | -- V -- +++-- -- |
24 | -- -- -- -- |
25 | -- --- 2 --- -- |
26 | -- ---------++++++++++++-- |
27 | -- ------- -- |
28 | -- 0 0 2 3 -- |
29 | -----+++ 0 2 +++----- |
30 | ----- 0 1 2 ----- |
31 | -- +++-----+++ -- |
32 | -- ----- -- |
33 | -- ----- -- |
34 | -- P --------- -- |
35 | -- ---- ---- -- |
36 | -------------------- --------------------|
37 |
--------------------------------------------------------------------------------
/src/levels/level3.txt:
--------------------------------------------------------------------------------
1 | |
2 | -------- |
3 | -------- |
4 | -- |
5 | ---------- -- |
6 | ---------- -- |
7 | - -- -- |
8 | - -- W -- --+++-- |
9 | - -- -- -- W -- |
10 | - -- -------- c -- -- |
11 | - @ -- ++ -------- +++++ |
12 | - -- -- |
13 | -----w --- -- |
14 | ---------- +++ -- |
15 | - -- -- |
16 | - -- -- |
17 | - -- +++ -- C C |
18 | - -- ---w - |
19 | - P W -- -- ------ |
20 | - -- -- ------ |
21 | -----------w ---- ------ |
22 | ----------------- ------ |
23 | ----------------- ------ |
24 | -----------------WWWWWWWWWWWWWWW------WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW|
25 |
--------------------------------------------------------------------------------
/src/levels/level3_index.txt:
--------------------------------------------------------------------------------
1 | |
2 | -------- |
3 | -------- |
4 | -- |
5 | ---------- -- |
6 | ---------- -- |
7 | - -- -- |
8 | - -- 1 -- --+++-- |
9 | - -- -- -- 2 -- |
10 | - -- -------- c -- -- |
11 | - @ -- ++ -------- +++++ |
12 | - -- -- |
13 | -----2 --- -- |
14 | ---------- +++ -- |
15 | - -- -- |
16 | - -- -- |
17 | - -- +++ -- C C |
18 | - -- ---1 - |
19 | - P 0 -- -- ------ |
20 | - -- -- ------ |
21 | -----------0 ---- ------ |
22 | ----------------- ------ |
23 | ----------------- ------ |
24 | -----------------000000000000000------1111111111111111111111111111111111111111111|
25 |
--------------------------------------------------------------------------------
/src/levels/level4.txt:
--------------------------------------------------------------------------------
1 | --- |
2 | --------|
3 | --------|
4 | --------|
5 | ---|
6 | W ---|
7 | B ---|
8 | - -------------------|
9 | -L -------------------|
10 | - -------------------|
11 | C LLLLLLLLLLLLL |
12 | |
13 | B |
14 | --- --- --- |
15 | --- --- --- < |
16 | L L L > |
17 | |
18 | |
19 | V V |
20 | |
21 | |
22 | |
23 | P @ |
24 | B |
25 | --------w ------- ----------------- +-w ----------------------|
26 | ----------------- ----------------- -------------------------|
27 | ----------------- I I +-------------------------|
28 | ----------------- I I -------------------------|
29 | ----------------- I B I -------------------------|
30 | ----------------------------------------------------------------|
31 |
--------------------------------------------------------------------------------
/src/levels/level4_index.txt:
--------------------------------------------------------------------------------
1 | --- |
2 | --------|
3 | --------|
4 | --------|
5 | ---|
6 | 1 ---|
7 | 3 ---|
8 | - -------------------|
9 | -0 -------------------|
10 | - -------------------|
11 | 2 1111111111111 |
12 | |
13 | 2 |
14 | --- --- --- |
15 | --- --- --- 3 |
16 | 0 0 0 3 |
17 | |
18 | |
19 | 1 1 |
20 | |
21 | |
22 | |
23 | P @ |
24 | 0 |
25 | --------0 ------- ----------------- +-1 ----------------------|
26 | ----------------- ----------------- -------------------------|
27 | ----------------- 1 0 +-------------------------|
28 | ----------------- 1 0 -------------------------|
29 | ----------------- 1 1 0 -------------------------|
30 | ----------------------------------------------------------------|
31 |
--------------------------------------------------------------------------------
/src/levels/level5.txt:
--------------------------------------------------------------------------------
1 | -----|
2 | |
3 | |
4 | |
5 | |
6 | P ---++++ |
7 | --- |
8 | -w - > < --- ++++|
9 | ---- WWWWWWWWWWW --- |
10 | ---- W ---++++ |
11 | ---- W --- |
12 | ---- W B --- ++++|
13 | ---- WWWWWWWWW ---- |
14 | ---- W ---- |
15 | - L W < --- |
16 | - W --- --+++++|
17 | - W --- -- |
18 | - ++-- WWWWWWWWWWWWWWW--- --- -- L |
19 | - -- --- --- -------|
20 | - -- --- --- -------|
21 | - --++ --- --- -- |
22 | - --- --- -- |
23 | - -- --- --- -- |
24 | C -- --- --- -- |
25 | A -- --- --- -- |
26 | -- --- --- -- |
27 | -- --- --- -- |
28 | -- --- --- -- |
29 | -- --- --- -- |
30 | -- W W -------|
31 | --B B B-------|
32 | ------------- |
33 | ------------- |
34 | I I I |
35 | B I I I @ |
36 | --- --- I I I |
37 | ----WW---WWWW---WW---------w -----------------|
38 |
--------------------------------------------------------------------------------
/src/levels/level5_index.txt:
--------------------------------------------------------------------------------
1 | -----|
2 | |
3 | |
4 | |
5 | |
6 | P ---++++ |
7 | --- |
8 | -1 - > 3 --- ++++|
9 | ---- 00000000000 --- |
10 | ---- 0 ---++++ |
11 | ---- 0 --- |
12 | ---- 0 3 --- ++++|
13 | ---- 000000000 ---- |
14 | ---- 0 ---- |
15 | - 1 0 < --- |
16 | - 0 --- --+++++|
17 | - 0 --- -- |
18 | - ++-- 000000000000000--- --- -- 1 |
19 | - -- --- --- -------|
20 | - -- --- --- -------|
21 | - --++ --- --- -- |
22 | - --- --- -- |
23 | - -- --- --- -- |
24 | C -- --- --- -- |
25 | 4 -- --- --- -- |
26 | -- --- --- -- |
27 | -- --- --- -- |
28 | -- --- --- -- |
29 | -- --- --- -- |
30 | -- 0 0 -------|
31 | --0 1 2-------|
32 | ------------- |
33 | ------------- |
34 | 0 1 2 |
35 | 4 0 1 2 @ |
36 | --- --- 0 1 2 |
37 | ----00---0000---00---------0 -----------------|
38 |
--------------------------------------------------------------------------------
/src/levels/level6.txt:
--------------------------------------------------------------------------------
1 | --- -- |
2 | --- -- |
3 | I -- |
4 | I @ -- |
5 | I -- |
6 | -------------------------------------|
7 | ++-------------------------------------|
8 | H H I |
9 | I B |
10 | +++ I ---|
11 | I ---|
12 | I+++++---|
13 | -w -- I ---|
14 | ----- I ---|
15 | - ----++---|
16 | - ---- |
17 | - ---- |
18 | - < ----+++++|
19 | - |
20 | - |
21 | - > > |
22 | - WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW|
23 | - -----------+++++++++++++++-----------|
24 | - ----------- -----------|
25 | - -- ---- ---|
26 | - -- ----- ---|
27 | - A -- ---- -|
28 | - -- ----- -|
29 | - -- -----|
30 | - L-- W -----|
31 | - -- B ---|
32 | ----------------- ---|
33 | ----------------- -|
34 | -- H -- -- -|
35 | -- -- -- -|
36 | -- ------ -|
37 | -- ------ H-|
38 | -- ------ C -|
39 | V -- -- -- |
40 | -- -- -- |
41 | -- ------ |
42 | -- ------ |
43 | |
44 | P --- |
45 | --- --- B |
46 | ---w ----------------------------------------|
47 |
--------------------------------------------------------------------------------
/src/levels/level6_index.txt:
--------------------------------------------------------------------------------
1 | --- -- |
2 | --- -- |
3 | 2 -- |
4 | 2 @ -- |
5 | 2 -- |
6 | -------------------------------------|
7 | ++-------------------------------------|
8 | 1 1 2 |
9 | 2 2 |
10 | +++ 2 ---|
11 | 2 ---|
12 | 2+++++---|
13 | -1 -- 2 ---|
14 | ----- 2 ---|
15 | - ----++---|
16 | - ---- |
17 | - ---- |
18 | - 1 ----+++++|
19 | - |
20 | - |
21 | - 1 1 |
22 | - 0000000000000000000000000000000000000|
23 | - -----------+++++++++++++++-----------|
24 | - ----------- -----------|
25 | - -- ---- ---|
26 | - -- ----- ---|
27 | - 1 -- ---- -|
28 | - -- ----- -|
29 | - -- -----|
30 | - 0-- 0 -----|
31 | - -- 1 ---|
32 | ----------------- ---|
33 | ----------------- -|
34 | -- 0 -- -- -|
35 | -- -- -- -|
36 | -- ------ -|
37 | -- ------ 0-|
38 | -- ------ 0 -|
39 | 1 -- -- -- |
40 | -- -- -- |
41 | -- ------ |
42 | -- ------ |
43 | |
44 | P --- |
45 | --- --- 0 |
46 | ---0 ----------------------------------------|
47 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | // chirperjax, a demo game built using the "gate" game library.
2 | // Copyright (C) 2017-2019 Matthew D. Michelotti
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This program is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | #[macro_use]
18 | extern crate gate;
19 | extern crate collider;
20 |
21 | gate_header!();
22 |
23 | mod level_loader;
24 | mod game_input;
25 | mod game;
26 | mod asset_id { include!(concat!(env!("OUT_DIR"), "/asset_id.rs")); }
27 |
28 | use gate::{App, AppContext, AppInfo, KeyCode};
29 | use gate::renderer::{Renderer, Affine};
30 |
31 | use crate::game_input::{GameInput, InputEvent};
32 | use crate::game::GameBoard;
33 | use crate::asset_id::{AssetId, MusicId, SpriteId};
34 | use crate::level_loader::LEVEL_COUNT;
35 |
36 | fn main() {
37 | // TODO allow some flexibility in the app height
38 | let info = AppInfo::with_max_dims(game::SCREEN_PIXELS_HEIGHT * 16. / 9., game::SCREEN_PIXELS_HEIGHT)
39 | .min_dims(game::SCREEN_PIXELS_HEIGHT * 4. / 3., game::SCREEN_PIXELS_HEIGHT)
40 | .tile_width(8)
41 | .title("Chirperjax")
42 | .print_workload_info()
43 | .print_gl_info();
44 | gate::run(info, GameApp::new());
45 | }
46 |
47 | struct GameApp { input: GameInput, level: usize, board: GameBoard }
48 |
49 | impl GameApp {
50 | pub fn new() -> GameApp {
51 | GameApp { input: GameInput::new(), level: 0, board: level_loader::load(0) }
52 | }
53 |
54 | fn load_next_level(&mut self) {
55 | self.level = (self.level + 1) % LEVEL_COUNT;
56 | self.board = level_loader::load(self.level);
57 | if let Some(held_dir) = self.input.held_dir() {
58 | self.board.input(InputEvent::UpdateMovement(Some(held_dir)));
59 | }
60 | }
61 | }
62 |
63 | impl App for GameApp {
64 | fn start(&mut self, ctx: &mut AppContext) { ctx.audio.loop_music(MusicId::BgMusic); }
65 |
66 | fn render(&mut self, renderer: &mut Renderer, ctx: &AppContext) {
67 | self.board.draw(renderer, ctx);
68 | if self.level == 0 {
69 | let affine = &Affine::translate(0.5 * ctx.dims().0, 0.5 * ctx.dims().1).pre_scale(2.);
70 | renderer.sprite_mode().draw(affine, SpriteId::Instructions);
71 | }
72 | }
73 |
74 | fn advance(&mut self, seconds: f64, ctx: &mut AppContext) {
75 | self.board.advance(seconds, &mut ctx.audio);
76 | if self.board.is_done() {
77 | self.load_next_level();
78 | }
79 | }
80 |
81 | fn key_down(&mut self, key: KeyCode, _: &mut AppContext) {
82 | if let Some(event) = self.input.key_down(key) {
83 | self.board.input(event);
84 | }
85 | }
86 |
87 | fn key_up(&mut self, key: KeyCode, _: &mut AppContext) {
88 | if let Some(event) = self.input.key_up(key) {
89 | self.board.input(event);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src_assets/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
2 | Public License
3 |
4 | By exercising the Licensed Rights (defined below), You accept and agree
5 | to be bound by the terms and conditions of this Creative Commons
6 | Attribution-NonCommercial-ShareAlike 4.0 International Public License
7 | ("Public License"). To the extent this Public License may be
8 | interpreted as a contract, You are granted the Licensed Rights in
9 | consideration of Your acceptance of these terms and conditions, and the
10 | Licensor grants You such rights in consideration of benefits the
11 | Licensor receives from making the Licensed Material available under
12 | these terms and conditions.
13 |
14 |
15 | Section 1 -- Definitions.
16 |
17 | a. Adapted Material means material subject to Copyright and Similar
18 | Rights that is derived from or based upon the Licensed Material
19 | and in which the Licensed Material is translated, altered,
20 | arranged, transformed, or otherwise modified in a manner requiring
21 | permission under the Copyright and Similar Rights held by the
22 | Licensor. For purposes of this Public License, where the Licensed
23 | Material is a musical work, performance, or sound recording,
24 | Adapted Material is always produced where the Licensed Material is
25 | synched in timed relation with a moving image.
26 |
27 | b. Adapter's License means the license You apply to Your Copyright
28 | and Similar Rights in Your contributions to Adapted Material in
29 | accordance with the terms and conditions of this Public License.
30 |
31 | c. BY-NC-SA Compatible License means a license listed at
32 | creativecommons.org/compatiblelicenses, approved by Creative
33 | Commons as essentially the equivalent of this Public License.
34 |
35 | d. Copyright and Similar Rights means copyright and/or similar rights
36 | closely related to copyright including, without limitation,
37 | performance, broadcast, sound recording, and Sui Generis Database
38 | Rights, without regard to how the rights are labeled or
39 | categorized. For purposes of this Public License, the rights
40 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
41 | Rights.
42 |
43 | e. Effective Technological Measures means those measures that, in the
44 | absence of proper authority, may not be circumvented under laws
45 | fulfilling obligations under Article 11 of the WIPO Copyright
46 | Treaty adopted on December 20, 1996, and/or similar international
47 | agreements.
48 |
49 | f. Exceptions and Limitations means fair use, fair dealing, and/or
50 | any other exception or limitation to Copyright and Similar Rights
51 | that applies to Your use of the Licensed Material.
52 |
53 | g. License Elements means the license attributes listed in the name
54 | of a Creative Commons Public License. The License Elements of this
55 | Public License are Attribution, NonCommercial, and ShareAlike.
56 |
57 | h. Licensed Material means the artistic or literary work, database,
58 | or other material to which the Licensor applied this Public
59 | License.
60 |
61 | i. Licensed Rights means the rights granted to You subject to the
62 | terms and conditions of this Public License, which are limited to
63 | all Copyright and Similar Rights that apply to Your use of the
64 | Licensed Material and that the Licensor has authority to license.
65 |
66 | j. Licensor means the individual(s) or entity(ies) granting rights
67 | under this Public License.
68 |
69 | k. NonCommercial means not primarily intended for or directed towards
70 | commercial advantage or monetary compensation. For purposes of
71 | this Public License, the exchange of the Licensed Material for
72 | other material subject to Copyright and Similar Rights by digital
73 | file-sharing or similar means is NonCommercial provided there is
74 | no payment of monetary compensation in connection with the
75 | exchange.
76 |
77 | l. Share means to provide material to the public by any means or
78 | process that requires permission under the Licensed Rights, such
79 | as reproduction, public display, public performance, distribution,
80 | dissemination, communication, or importation, and to make material
81 | available to the public including in ways that members of the
82 | public may access the material from a place and at a time
83 | individually chosen by them.
84 |
85 | m. Sui Generis Database Rights means rights other than copyright
86 | resulting from Directive 96/9/EC of the European Parliament and of
87 | the Council of 11 March 1996 on the legal protection of databases,
88 | as amended and/or succeeded, as well as other essentially
89 | equivalent rights anywhere in the world.
90 |
91 | n. You means the individual or entity exercising the Licensed Rights
92 | under this Public License. Your has a corresponding meaning.
93 |
94 |
95 | Section 2 -- Scope.
96 |
97 | a. License grant.
98 |
99 | 1. Subject to the terms and conditions of this Public License,
100 | the Licensor hereby grants You a worldwide, royalty-free,
101 | non-sublicensable, non-exclusive, irrevocable license to
102 | exercise the Licensed Rights in the Licensed Material to:
103 |
104 | a. reproduce and Share the Licensed Material, in whole or
105 | in part, for NonCommercial purposes only; and
106 |
107 | b. produce, reproduce, and Share Adapted Material for
108 | NonCommercial purposes only.
109 |
110 | 2. Exceptions and Limitations. For the avoidance of doubt, where
111 | Exceptions and Limitations apply to Your use, this Public
112 | License does not apply, and You do not need to comply with
113 | its terms and conditions.
114 |
115 | 3. Term. The term of this Public License is specified in Section
116 | 6(a).
117 |
118 | 4. Media and formats; technical modifications allowed. The
119 | Licensor authorizes You to exercise the Licensed Rights in
120 | all media and formats whether now known or hereafter created,
121 | and to make technical modifications necessary to do so. The
122 | Licensor waives and/or agrees not to assert any right or
123 | authority to forbid You from making technical modifications
124 | necessary to exercise the Licensed Rights, including
125 | technical modifications necessary to circumvent Effective
126 | Technological Measures. For purposes of this Public License,
127 | simply making modifications authorized by this Section 2(a)
128 | (4) never produces Adapted Material.
129 |
130 | 5. Downstream recipients.
131 |
132 | a. Offer from the Licensor -- Licensed Material. Every
133 | recipient of the Licensed Material automatically
134 | receives an offer from the Licensor to exercise the
135 | Licensed Rights under the terms and conditions of this
136 | Public License.
137 |
138 | b. Additional offer from the Licensor -- Adapted Material.
139 | Every recipient of Adapted Material from You
140 | automatically receives an offer from the Licensor to
141 | exercise the Licensed Rights in the Adapted Material
142 | under the conditions of the Adapter's License You apply.
143 |
144 | c. No downstream restrictions. You may not offer or impose
145 | any additional or different terms or conditions on, or
146 | apply any Effective Technological Measures to, the
147 | Licensed Material if doing so restricts exercise of the
148 | Licensed Rights by any recipient of the Licensed
149 | Material.
150 |
151 | 6. No endorsement. Nothing in this Public License constitutes or
152 | may be construed as permission to assert or imply that You
153 | are, or that Your use of the Licensed Material is, connected
154 | with, or sponsored, endorsed, or granted official status by,
155 | the Licensor or others designated to receive attribution as
156 | provided in Section 3(a)(1)(A)(i).
157 |
158 | b. Other rights.
159 |
160 | 1. Moral rights, such as the right of integrity, are not
161 | licensed under this Public License, nor are publicity,
162 | privacy, and/or other similar personality rights; however, to
163 | the extent possible, the Licensor waives and/or agrees not to
164 | assert any such rights held by the Licensor to the limited
165 | extent necessary to allow You to exercise the Licensed
166 | Rights, but not otherwise.
167 |
168 | 2. Patent and trademark rights are not licensed under this
169 | Public License.
170 |
171 | 3. To the extent possible, the Licensor waives any right to
172 | collect royalties from You for the exercise of the Licensed
173 | Rights, whether directly or through a collecting society
174 | under any voluntary or waivable statutory or compulsory
175 | licensing scheme. In all other cases the Licensor expressly
176 | reserves any right to collect such royalties, including when
177 | the Licensed Material is used other than for NonCommercial
178 | purposes.
179 |
180 |
181 | Section 3 -- License Conditions.
182 |
183 | Your exercise of the Licensed Rights is expressly made subject to the
184 | following conditions.
185 |
186 | a. Attribution.
187 |
188 | 1. If You Share the Licensed Material (including in modified
189 | form), You must:
190 |
191 | a. retain the following if it is supplied by the Licensor
192 | with the Licensed Material:
193 |
194 | i. identification of the creator(s) of the Licensed
195 | Material and any others designated to receive
196 | attribution, in any reasonable manner requested by
197 | the Licensor (including by pseudonym if
198 | designated);
199 |
200 | ii. a copyright notice;
201 |
202 | iii. a notice that refers to this Public License;
203 |
204 | iv. a notice that refers to the disclaimer of
205 | warranties;
206 |
207 | v. a URI or hyperlink to the Licensed Material to the
208 | extent reasonably practicable;
209 |
210 | b. indicate if You modified the Licensed Material and
211 | retain an indication of any previous modifications; and
212 |
213 | c. indicate the Licensed Material is licensed under this
214 | Public License, and include the text of, or the URI or
215 | hyperlink to, this Public License.
216 |
217 | 2. You may satisfy the conditions in Section 3(a)(1) in any
218 | reasonable manner based on the medium, means, and context in
219 | which You Share the Licensed Material. For example, it may be
220 | reasonable to satisfy the conditions by providing a URI or
221 | hyperlink to a resource that includes the required
222 | information.
223 | 3. If requested by the Licensor, You must remove any of the
224 | information required by Section 3(a)(1)(A) to the extent
225 | reasonably practicable.
226 |
227 | b. ShareAlike.
228 |
229 | In addition to the conditions in Section 3(a), if You Share
230 | Adapted Material You produce, the following conditions also apply.
231 |
232 | 1. The Adapter's License You apply must be a Creative Commons
233 | license with the same License Elements, this version or
234 | later, or a BY-NC-SA Compatible License.
235 |
236 | 2. You must include the text of, or the URI or hyperlink to, the
237 | Adapter's License You apply. You may satisfy this condition
238 | in any reasonable manner based on the medium, means, and
239 | context in which You Share Adapted Material.
240 |
241 | 3. You may not offer or impose any additional or different terms
242 | or conditions on, or apply any Effective Technological
243 | Measures to, Adapted Material that restrict exercise of the
244 | rights granted under the Adapter's License You apply.
245 |
246 |
247 | Section 4 -- Sui Generis Database Rights.
248 |
249 | Where the Licensed Rights include Sui Generis Database Rights that
250 | apply to Your use of the Licensed Material:
251 |
252 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
253 | to extract, reuse, reproduce, and Share all or a substantial
254 | portion of the contents of the database for NonCommercial purposes
255 | only;
256 |
257 | b. if You include all or a substantial portion of the database
258 | contents in a database in which You have Sui Generis Database
259 | Rights, then the database in which You have Sui Generis Database
260 | Rights (but not its individual contents) is Adapted Material,
261 | including for purposes of Section 3(b); and
262 |
263 | c. You must comply with the conditions in Section 3(a) if You Share
264 | all or a substantial portion of the contents of the database.
265 |
266 | For the avoidance of doubt, this Section 4 supplements and does not
267 | replace Your obligations under this Public License where the Licensed
268 | Rights include other Copyright and Similar Rights.
269 |
270 |
271 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
272 |
273 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
274 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
275 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
276 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
277 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
278 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
279 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
280 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
281 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
282 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
283 |
284 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
285 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
286 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
287 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
288 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
289 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
290 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
291 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
292 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
293 |
294 | c. The disclaimer of warranties and limitation of liability provided
295 | above shall be interpreted in a manner that, to the extent
296 | possible, most closely approximates an absolute disclaimer and
297 | waiver of all liability.
298 |
299 |
300 | Section 6 -- Term and Termination.
301 |
302 | a. This Public License applies for the term of the Copyright and
303 | Similar Rights licensed here. However, if You fail to comply with
304 | this Public License, then Your rights under this Public License
305 | terminate automatically.
306 |
307 | b. Where Your right to use the Licensed Material has terminated under
308 | Section 6(a), it reinstates:
309 |
310 | 1. automatically as of the date the violation is cured, provided
311 | it is cured within 30 days of Your discovery of the
312 | violation; or
313 |
314 | 2. upon express reinstatement by the Licensor.
315 |
316 | For the avoidance of doubt, this Section 6(b) does not affect any
317 | right the Licensor may have to seek remedies for Your violations
318 | of this Public License.
319 |
320 | c. For the avoidance of doubt, the Licensor may also offer the
321 | Licensed Material under separate terms or conditions or stop
322 | distributing the Licensed Material at any time; however, doing so
323 | will not terminate this Public License.
324 |
325 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
326 | License.
327 |
328 |
329 | Section 7 -- Other Terms and Conditions.
330 |
331 | a. The Licensor shall not be bound by any additional or different
332 | terms or conditions communicated by You unless expressly agreed.
333 |
334 | b. Any arrangements, understandings, or agreements regarding the
335 | Licensed Material not stated herein are separate from and
336 | independent of the terms and conditions of this Public License.
337 |
338 |
339 | Section 8 -- Interpretation.
340 |
341 | a. For the avoidance of doubt, this Public License does not, and
342 | shall not be interpreted to, reduce, limit, restrict, or impose
343 | conditions on any use of the Licensed Material that could lawfully
344 | be made without permission under this Public License.
345 |
346 | b. To the extent possible, if any provision of this Public License is
347 | deemed unenforceable, it shall be automatically reformed to the
348 | minimum extent necessary to make it enforceable. If the provision
349 | cannot be reformed, it shall be severed from this Public License
350 | without affecting the enforceability of the remaining terms and
351 | conditions.
352 |
353 | c. No term or condition of this Public License will be waived and no
354 | failure to comply consented to unless expressly agreed to by the
355 | Licensor.
356 |
357 | d. Nothing in this Public License constitutes or may be interpreted
358 | as a limitation upon, or waiver of, any privileges and immunities
359 | that apply to the Licensor or You, including from the legal
360 | processes of any jurisdiction or authority.
361 |
--------------------------------------------------------------------------------
/src_assets/music/BgMusic.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/music/BgMusic.ogg
--------------------------------------------------------------------------------
/src_assets/sounds/Button.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sounds/Button.ogg
--------------------------------------------------------------------------------
/src_assets/sounds/Clear.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sounds/Clear.ogg
--------------------------------------------------------------------------------
/src_assets/sounds/Jump.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sounds/Jump.ogg
--------------------------------------------------------------------------------
/src_assets/sounds/Lasor.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sounds/Lasor.ogg
--------------------------------------------------------------------------------
/src_assets/sounds/Warp.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sounds/Warp.ogg
--------------------------------------------------------------------------------
/src_assets/sprites/BgPattern.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/BgPattern.png
--------------------------------------------------------------------------------
/src_assets/sprites/BlueFade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/BlueFade.png
--------------------------------------------------------------------------------
/src_assets/sprites/BlueWarp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/BlueWarp.png
--------------------------------------------------------------------------------
/src_assets/sprites/GreenFade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/GreenFade.png
--------------------------------------------------------------------------------
/src_assets/sprites/GreenWarp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/GreenWarp.png
--------------------------------------------------------------------------------
/src_assets/sprites/Instructions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/Instructions.png
--------------------------------------------------------------------------------
/src_assets/sprites/Lasor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/Lasor.png
--------------------------------------------------------------------------------
/src_assets/sprites/PinkFade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/PinkFade.png
--------------------------------------------------------------------------------
/src_assets/sprites/PinkWarp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/PinkWarp.png
--------------------------------------------------------------------------------
/src_assets/sprites/Platform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/Platform.png
--------------------------------------------------------------------------------
/src_assets/sprites/PlayerChirp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/PlayerChirp.png
--------------------------------------------------------------------------------
/src_assets/sprites/PlayerRun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/PlayerRun.png
--------------------------------------------------------------------------------
/src_assets/sprites/PlayerStill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/PlayerStill.png
--------------------------------------------------------------------------------
/src_assets/sprites/Puff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/Puff.png
--------------------------------------------------------------------------------
/src_assets/sprites/Star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/Star.png
--------------------------------------------------------------------------------
/src_assets/sprites/Tile_t8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/Tile_t8.png
--------------------------------------------------------------------------------
/src_assets/sprites/WhiteSquare.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SergiusIW/chirperjax/a1a2cb72952fc9c7f62a3657246a4a388705c535/src_assets/sprites/WhiteSquare.png
--------------------------------------------------------------------------------