1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! A pluggable platforming controller for [game-toolkit](https://github.com/sunsided/game-toolkit):
//! fluid, snappy movement with feel presets, and an animation state graph that follows it.
//!
//! The quickest start is [`Platformer`]: pick a preset, call `update` each frame with your
//! world as a [`sim::Terrain`] (anything that can say what's solid; [`sim::Level`] is a
//! ready-made one), and draw `sprite()` at `position()` (or `draw_debug` until there is
//! art). Underneath, three
//! layers you can also use on their own:
//!
//! - [`sim`]: the movement. A fixed-step, deterministic body: an [`sim::Intent`] in per
//! step, [`sim::Event`]s out. Every feel number and ability switch is in [`sim::Tuning`];
//! [`sim::Preset`]s set them toward the feel of Celeste, Hollow Knight, Silksong or
//! Super Meat Boy (an independent project, not affiliated with those games' makers).
//! - [`anim`]: the animation controller, independent of any game: parameters, clips,
//! conditions, a graph spec compiled into a validated graph, the animator, drivers.
//! - [`hero`]: the binding between them for one character: the built-in graph, its sprite
//! numbers, and the driver that turns movement into graph parameters.
//!
//! With the `toolkit` feature (on by default), [`controls`] reads game-toolkit's keyboard
//! and gamepad through per-preset control schemes. Without it, nothing here depends on
//! anything but std.
//!
//! A complete game with a playable character:
//!
//! ```no_run
//! # #[cfg(feature = "toolkit")] {
//! use game_toolkit::prelude::*;
//! use game_toolkit_platformer::prelude::*;
//!
//! struct MyGame {
//! level: Level,
//! hero: Platformer,
//! }
//!
//! impl Game for MyGame {
//! fn init(_ctx: &mut Context) -> Result<Self> {
//! let level = Level::demo();
//! let hero = Platformer::on(&level, Preset::Precise);
//! Ok(Self { level, hero })
//! }
//!
//! fn update(&mut self, ctx: &mut Context, dt: f32) {
//! self.hero.update(&ctx.input, &mut self.level, dt);
//! for event in self.hero.drain_events() {
//! match event {
//! Event::Jumped { .. } => { /* a sound */ }
//! Event::Landed { drop, .. } if drop > 48 => { /* a thud, some dust */ }
//! _ => {}
//! }
//! }
//! }
//!
//! fn render(&mut self, ctx: &mut Context, frame: &mut Frame) {
//! let mut p = frame.painter(&mut ctx.gfx);
//! p.clear([0.05, 0.04, 0.12, 1.0]);
//! self.level.draw_debug(&mut p, [0.0, 0.0], 3.0);
//! self.hero.draw_debug(&mut p, [0.0, 0.0], 3.0);
//! }
//! }
//!
//! run::<MyGame>(AppConfig::default()).unwrap();
//! # }
//! ```
//!
//! Configured through the builder:
//!
//! ```
//! # #[cfg(feature = "toolkit")] {
//! use game_toolkit_platformer::prelude::*;
//!
//! let hero = Platformer::builder()
//! .preset(Preset::Snappy)
//! .tune(|t| {
//! t.air_jumps = 2;
//! t.dash_speed = 260.0;
//! })
//! .controls(Scheme::PRECISE)
//! .spawn(Spot::TopLeft(40, 160))
//! .respawn(false)
//! .build()
//! .unwrap();
//! assert_eq!(hero.tuning().air_jumps, 2);
//! # }
//! ```
pub use Party;
pub use ;
/// Everything a game needs to get started: `use game_toolkit_platformer::prelude::*;`.
/// The README's code samples, compiled as doc tests.
;
/// The hazards recipe's code, compiled as a doc test.
;
/// The surfaces recipe's code, compiled as a doc test.
;
/// The moving-platforms recipe's code, compiled as a doc test.
;
/// The movement doc's code, compiled as a doc test.
;