pub struct Assets { /* private fields */ }Expand description
Everything Config::with_assets loaded, by
name across all sources.
A name only one source used is read bare, "Ship"; a name more than
one shares needs its source, "props#Ship".
Implementations§
Source§impl Assets
impl Assets
Sourcepub fn mesh<P: Part>(&self, name: &str) -> MeshData<P, NoClips>
pub fn mesh<P: Part>(&self, name: &str) -> MeshData<P, NoClips>
The mesh a source loaded under name, its material names resolved
to the parts P.
A part names exactly one material; one that resolves to no part is drawn as authored unless a draw repaints every slot. A missing or ambiguous name, a part no material resolves to, and a part two materials resolve to each return empty data, which carries the name into the startup error.
Examples found in repository?
728 fn build(&self, assets: &Assets) -> MeshData {
729 assets.mesh(DOOR_MESH)
730 }
731}
732
733/// The loaded gem, repainted whole per draw so its glow color shifts.
734#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
735struct Gem;
736
737impl Mesh for Gem {
738 fn build(&self, assets: &Assets) -> MeshData {
739 assets.mesh(GEM_MESH)
740 }More examples
Sourcepub fn model<P: Part, C: Clip>(&self, name: &str) -> MeshData<P, C>
pub fn model<P: Part, C: Clip>(&self, name: &str) -> MeshData<P, C>
The model a source loaded under name: the mesh of one of its root
nodes, the joints that pose it, and one animation per clip of C.
Material names resolve to the parts P as mesh
resolves them, and each clip resolves the one animation of the source
whose name it matches. An animation no clip matches is left alone; a
clip that matches none, a clip two animations match, and a clip whose
animation moves no joint of this model each return empty data, which
carries the name into the startup error.
Examples found in repository?
284 fn build(&self, assets: &Assets) -> MeshData<NoParts, ElfClip> {
285 assets.model(ELF_ROOT)
286 }
287}
288
289/// What the game fills each tick to move `ElfState` on.
290#[derive(Default)]
291struct ElfInput {
292 /// The elf's speed this tick, a fraction of [`ELF_SPEED`].
293 speed: f32,
294 attack: bool,
295 /// True the tick a hurt patch is stepped onto and [`FATAL_HITS`] have
296 /// not yet landed.
297 hit: bool,
298 /// True the tick a hurt patch is stepped onto the third time, which
299 /// [`FATAL_HITS`] counts.
300 dying: bool,
301 jump: bool,
302 /// True the tick `Jump`'s own height curve returns the elf to the
303 /// ground after it launches.
304 landed: bool,
305 dance: bool,
306 /// `Button::Interact`, read as sitting down, standing back up, or
307 /// nothing, by the state it reaches.
308 interact: bool,
309 /// Whether the elf stands close enough to the cube to sit on it.
310 near_seat: bool,
311}
312
313#[derive(Clone, Copy, Eq, PartialEq, Debug)]
314enum ElfState {
315 Idle,
316 Locomotion,
317 Attack,
318 Hit,
319 Death,
320 SitDown,
321 Sit,
322 StandUp,
323 Jump,
324 Dance,
325}
326
327impl ElfState {
328 /// Whether the elf is on the seat, or on its way onto or off it.
329 fn seated(self) -> bool {
330 matches!(self, Self::SitDown | Self::Sit | Self::StandUp)
331 }
332
333 /// `Locomotion` where `input` reads a walk or a run, `Idle` at rest:
334 /// where a grounded state returns once whatever interrupted it ends.
335 fn grounded(input: &ElfInput) -> Self {
336 match input.speed > WALK_THRESHOLD {
337 true => Self::Locomotion,
338 false => Self::Idle,
339 }
340 }
341}
342
343impl AnimationStates for ElfState {
344 type Clip = ElfClip;
345 type Input = ElfInput;
346
347 fn entry() -> Self {
348 Self::Idle
349 }
350
351 fn motion(&self, input: &ElfInput) -> Motion<ElfClip> {
352 match self {
353 Self::Idle => Motion::looping(ElfClip::Idle),
354 Self::Locomotion => {
355 Motion::blend(ElfClip::Walk, ElfClip::Jog, input.speed).paced(input.speed)
356 }
357 Self::Attack => Motion::once(ElfClip::Attack),
358 Self::Hit => Motion::once(ElfClip::Hit),
359 Self::Death => Motion::once(ElfClip::Death),
360 Self::SitDown => Motion::once(ElfClip::SitDown),
361 Self::Sit => Motion::looping(ElfClip::Sit),
362 Self::StandUp => Motion::once(ElfClip::StandUp),
363 Self::Jump => Motion::once(ElfClip::Jump),
364 Self::Dance => Motion::looping(ElfClip::Dance),
365 }
366 }
367
368 fn next(&self, input: &ElfInput, at: Progress) -> Option<Transition<Self>> {
369 match (self, input) {
370 (Self::Death, _) => None,
371 (_, ElfInput { dying: true, .. }) => Some(Self::Death.fade(DEATH_FADE)),
372 (_, ElfInput { hit: true, .. }) if *self != Self::Hit => {
373 Some(Self::Hit.fade(HIT_ENTER_FADE))
374 }
375 (Self::Hit, _) if at.ended() => Some(ElfState::grounded(input).fade(HIT_EXIT_FADE)),
376 (Self::Attack, ElfInput { attack: true, .. }) if at.past(ATTACK_RELEASE) => Some(
377 Self::Attack
378 .restarted()
379 .entering_at(ATTACK_CHAIN_ENTRY)
380 .fade(ATTACK_CHAIN_FADE),
381 ),
382 (Self::Attack, _) if at.past(ATTACK_RELEASE) => {
383 Some(ElfState::grounded(input).fade(ATTACK_EXIT_FADE))
384 }
385 (Self::SitDown | Self::Sit | Self::StandUp, i) if i.speed > WALK_THRESHOLD => {
386 Some(Self::Locomotion.fade(STAND_EXIT_FADE))
387 }
388 (Self::SitDown | Self::Sit | Self::StandUp, ElfInput { attack: true, .. }) => {
389 Some(Self::Attack.fade(ATTACK_ENTER_FADE))
390 }
391 (Self::SitDown | Self::Sit | Self::StandUp, ElfInput { jump: true, .. }) => {
392 Some(Self::Jump.fade(JUMP_ENTER_FADE))
393 }
394 (Self::SitDown, _) if at.ended() => Some(Self::Sit.at_once()),
395 (Self::Sit, ElfInput { interact: true, .. }) => Some(Self::StandUp.fade(STAND_UP_FADE)),
396 (Self::StandUp, _) if at.ended() => Some(Self::Idle.fade(STAND_EXIT_FADE)),
397 (Self::Jump, ElfInput { landed: true, .. }) => {
398 Some(ElfState::grounded(input).fade(JUMP_EXIT_FADE))
399 }
400 (Self::Jump, _) if at.ended() => Some(ElfState::grounded(input).fade(JUMP_EXIT_FADE)),
401 (
402 Self::Idle | Self::Locomotion,
403 ElfInput {
404 interact: true,
405 near_seat: true,
406 ..
407 },
408 ) => Some(Self::SitDown.fade(SIT_DOWN_FADE)),
409 (Self::Idle | Self::Locomotion, ElfInput { attack: true, .. }) => {
410 Some(Self::Attack.fade(ATTACK_ENTER_FADE))
411 }
412 (Self::Idle | Self::Locomotion, ElfInput { jump: true, .. }) => {
413 Some(Self::Jump.fade(JUMP_ENTER_FADE))
414 }
415 (Self::Idle, ElfInput { dance: true, .. }) => Some(Self::Dance.fade(DANCE_FADE)),
416 (Self::Dance, i) if i.speed > WALK_THRESHOLD => {
417 Some(Self::Locomotion.fade(IDLE_LOCOMOTION_FADE))
418 }
419 (Self::Idle, i) if i.speed > WALK_THRESHOLD => {
420 Some(Self::Locomotion.fade(IDLE_LOCOMOTION_FADE))
421 }
422 (Self::Locomotion, i) if i.speed <= WALK_THRESHOLD => {
423 Some(Self::Idle.fade(IDLE_LOCOMOTION_FADE))
424 }
425 _ => None,
426 }
427 }
428}
429
430/// A machine of one state, posed by nothing but the value it scrubs.
431#[derive(Clone, Copy, Eq, PartialEq, Debug)]
432enum ScrubbedState {
433 SitDown,
434}
435
436/// What the game fills each tick to move `ScrubbedState` on.
437#[derive(Default)]
438struct ScrubbedInput {
439 /// How far into sitting down the second elf reads, a fraction in
440 /// `0.0..=1.0`.
441 settled: f32,
442}
443
444impl AnimationStates for ScrubbedState {
445 type Clip = ElfClip;
446 type Input = ScrubbedInput;
447
448 fn entry() -> Self {
449 Self::SitDown
450 }
451
452 fn motion(&self, input: &ScrubbedInput) -> Motion<ElfClip> {
453 Motion::scrubbed(ElfClip::SitDown, input.settled)
454 }
455
456 fn next(&self, _input: &ScrubbedInput, _at: Progress) -> Option<Transition<Self>> {
457 None
458 }
459}
460
461#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
462struct Butterfly;
463
464/// The one clip `FlyingState` plays, named as the source names it.
465#[derive(Clip, Clone, Debug, PartialEq, Eq, Hash)]
466enum ButterflyClip {
467 #[clip("fly")]
468 Fly,
469}
470
471impl Mesh<NoParts, ButterflyClip> for Butterfly {
472 fn build(&self, assets: &Assets) -> MeshData<NoParts, ButterflyClip> {
473 assets.model(BUTTERFLY_ROOT)
474 }More examples
Sourcepub fn texture(&self, name: &str) -> TextureData
pub fn texture(&self, name: &str) -> TextureData
The texture a source loaded under name.
A missing name returns empty pixels carrying the name into the startup error.
Examples found in repository?
More examples
569 fn build(&self, assets: &Assets) -> MeshData {
570 Plane
571 .build(assets)
572 .with_texture(assets.texture(GROUND_SHEET).pixelated())
573 }
574}
575
576/// The shoreline sprite laid over the pond's styled water, cutout so the
577/// water shows through its cleared middle.
578#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
579struct Shore;
580
581impl Mesh for Shore {
582 fn build(&self, assets: &Assets) -> MeshData {
583 Plane
584 .build(assets)
585 .with_texture(assets.texture(POND_SHEET).pixelated())
586 .with_material(Material::lit(Color::WHITE).cutout())
587 }
588}
589
590/// A crate prop, its texture drawn over a cube.
591#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
592struct Crate;
593
594impl Mesh for Crate {
595 fn build(&self, assets: &Assets) -> MeshData {
596 Cube.build(assets)
597 .with_texture(assets.texture(CRATE_TEXTURE).pixelated())
598 }
599}
600
601/// The well's rim.
602#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
603struct Well;
604
605impl Mesh for Well {
606 fn build(&self, assets: &Assets) -> MeshData {
607 Cube.build(assets)
608 .with_texture(assets.texture(WELL_SHEET).pixelated())
609 }
610}
611
612/// The well's mouth, laid flat over the rim's top face.
613#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
614struct WellMouth;
615
616impl Mesh for WellMouth {
617 fn build(&self, assets: &Assets) -> MeshData {
618 Plane
619 .build(assets)
620 .with_texture(assets.texture(WELL_SHEET).pixelated())
621 }
622}
623
624/// A stone box: the mouth's pillars and lintel.
625#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
626struct Stone;
627
628impl Mesh for Stone {
629 fn build(&self, assets: &Assets) -> MeshData {
630 Cube.build(assets)
631 .with_texture(assets.texture(STONE_SHEET).pixelated())
632 }
633}
634
635/// A bush sprite, cutout with its own relief.
636#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
637struct Bush;
638
639impl Mesh for Bush {
640 fn build(&self, assets: &Assets) -> MeshData {
641 Quad.build(assets)
642 .with_texture(assets.texture(BUSH_SPRITE).pixelated())
643 .with_relief(assets.relief(BUSH_RELIEF))
644 .with_material(Material::lit(Color::WHITE).cutout())
645 }
646}
647
648/// A rock sprite, cutout with its own relief.
649#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
650struct Rock;
651
652impl Mesh for Rock {
653 fn build(&self, assets: &Assets) -> MeshData {
654 Quad.build(assets)
655 .with_texture(assets.texture(ROCK_SPRITE).pixelated())
656 .with_relief(assets.relief(ROCK_RELIEF))
657 .with_material(Material::lit(Color::WHITE).cutout())
658 }
659}
660
661/// A torch's post sprite, cutout with its own relief.
662#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
663struct Torch;
664
665impl Mesh for Torch {
666 fn build(&self, assets: &Assets) -> MeshData {
667 Quad.build(assets)
668 .with_texture(assets.texture(TORCH_SPRITE).pixelated())
669 .with_relief(assets.relief(TORCH_RELIEF))
670 .with_material(Material::lit(Color::WHITE).cutout())
671 }
672}
673
674/// A torch's flame sprite, added over the dark rather than lit.
675#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
676struct Flame;
677
678impl Mesh for Flame {
679 fn build(&self, assets: &Assets) -> MeshData {
680 Quad.build(assets)
681 .with_texture(assets.texture(FLAME_SHEET).pixelated())
682 .with_material(Material::color(FLAME_TINT).additive())
683 }
684}
685
686/// The player's sprite, cutout with its own relief, its sheet shared
687/// with `examples/isometric-board.rs`.
688#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
689struct Walker;
690
691impl Mesh for Walker {
692 fn build(&self, assets: &Assets) -> MeshData {
693 Quad.build(assets)
694 .with_texture(assets.texture(WALKER_SHEET).pixelated())
695 .with_relief(assets.relief(WALKER_RELIEF))
696 .with_material(Material::lit(Color::WHITE).cutout())
697 }
698}
699
700/// The cave floor tile.
701#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
702struct CaveFloor;
703
704impl Mesh for CaveFloor {
705 fn build(&self, assets: &Assets) -> MeshData {
706 Plane
707 .build(assets)
708 .with_texture(assets.texture(CAVE_SHEET).pixelated())
709 }
710}
711
712/// The cave wall face.
713#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
714struct CaveWall;
715
716impl Mesh for CaveWall {
717 fn build(&self, assets: &Assets) -> MeshData {
718 Cube.build(assets)
719 .with_texture(assets.texture(CAVE_SHEET).pixelated())
720 }Sourcepub fn relief(&self, name: &str) -> ReliefData
pub fn relief(&self, name: &str) -> ReliefData
The texture a source loaded under name, read as a relief holding a
normal and a depth per texel.
A missing name returns empty pixels carrying the name into the startup error.
Examples found in repository?
640 fn build(&self, assets: &Assets) -> MeshData {
641 Quad.build(assets)
642 .with_texture(assets.texture(BUSH_SPRITE).pixelated())
643 .with_relief(assets.relief(BUSH_RELIEF))
644 .with_material(Material::lit(Color::WHITE).cutout())
645 }
646}
647
648/// A rock sprite, cutout with its own relief.
649#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
650struct Rock;
651
652impl Mesh for Rock {
653 fn build(&self, assets: &Assets) -> MeshData {
654 Quad.build(assets)
655 .with_texture(assets.texture(ROCK_SPRITE).pixelated())
656 .with_relief(assets.relief(ROCK_RELIEF))
657 .with_material(Material::lit(Color::WHITE).cutout())
658 }
659}
660
661/// A torch's post sprite, cutout with its own relief.
662#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
663struct Torch;
664
665impl Mesh for Torch {
666 fn build(&self, assets: &Assets) -> MeshData {
667 Quad.build(assets)
668 .with_texture(assets.texture(TORCH_SPRITE).pixelated())
669 .with_relief(assets.relief(TORCH_RELIEF))
670 .with_material(Material::lit(Color::WHITE).cutout())
671 }
672}
673
674/// A torch's flame sprite, added over the dark rather than lit.
675#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
676struct Flame;
677
678impl Mesh for Flame {
679 fn build(&self, assets: &Assets) -> MeshData {
680 Quad.build(assets)
681 .with_texture(assets.texture(FLAME_SHEET).pixelated())
682 .with_material(Material::color(FLAME_TINT).additive())
683 }
684}
685
686/// The player's sprite, cutout with its own relief, its sheet shared
687/// with `examples/isometric-board.rs`.
688#[derive(Catalog, Clone, PartialEq, Eq, Hash)]
689struct Walker;
690
691impl Mesh for Walker {
692 fn build(&self, assets: &Assets) -> MeshData {
693 Quad.build(assets)
694 .with_texture(assets.texture(WALKER_SHEET).pixelated())
695 .with_relief(assets.relief(WALKER_RELIEF))
696 .with_material(Material::lit(Color::WHITE).cutout())
697 }Sourcepub fn skybox(&self, name: &str) -> SkyboxData
pub fn skybox(&self, name: &str) -> SkyboxData
The same pixels read as the whole sky: the whole way around across the image, and zenith to nadir down it.
A missing name returns a black sky carrying that name into the startup error, and so does an image that is no sky at all, under the name of the skybox it was built for.
Examples found in repository?
589 fn build(&self, assets: &Assets) -> SkyboxData {
590 let sky = match self {
591 Self::Dawn => SkyboxData::gradient(
592 Color::rgb(0.55, 0.55, 0.75),
593 Color::rgb(0.95, 0.6, 0.35),
594 Color::rgb(0.12, 0.08, 0.06),
595 ),
596 Self::Noon => SkyboxData::gradient(
597 Color::rgb(0.2, 0.45, 0.85),
598 Color::rgb(0.75, 0.82, 0.9),
599 Color::rgb(0.3, 0.3, 0.28),
600 ),
601 Self::Dusk => SkyboxData::gradient(
602 Color::rgb(0.18, 0.1, 0.3),
603 Color::rgb(0.85, 0.35, 0.2),
604 Color::rgb(0.03, 0.02, 0.03),
605 ),
606 Self::Night => SkyboxData::gradient(
607 Color::rgb(0.02, 0.02, 0.06),
608 Color::rgb(0.05, 0.05, 0.1),
609 Color::rgb(0.0, 0.0, 0.0),
610 ),
611 Self::Clear => assets.skybox("sky-clear"),
612 Self::Classic => assets.skybox("sky-classic"),
613 Self::ImageDawn => assets.skybox("sky-dawn"),
614 Self::Sinister => assets.skybox("sky-sinister"),
615 Self::LightBlueStars => assets.skybox("sky-stars-lightblue"),
616 Self::BlueStars => assets.skybox("sky-stars-blue"),
617 Self::Default => SkyboxData::gradient(DEFAULT_SKY, DEFAULT_SKY, DEFAULT_SKY),
618 };
619 let sky = match self.ground() {
620 Some(ground) => sky.with_ground(ground),
621 None => sky,
622 };
623
624 sky.lit_by(self.light())
625 }Sourcepub fn sound(&self, name: &str) -> SoundData
pub fn sound(&self, name: &str) -> SoundData
The sound a source loaded under name.
A missing name returns silence, which carries the name into the startup error.
Examples found in repository?
More examples
205 fn build(&self, assets: &Assets) -> SoundData {
206 match self {
207 Sound::Serve => assets.sound("serve"),
208 Sound::BallLost => assets.sound("lost"),
209 Sound::LevelClear => assets.sound("win"),
210 Sound::GameOver => assets.sound("gameover"),
211 Sound::Bounce => assets.sound("bounce"),
212 Sound::BrickBreak => assets.sound("break"),
213 Sound::Music => assets.sound("music").streamed(),
214 Sound::MenuMusic => assets.sound("menu_music").streamed(),
215 Sound::Click => assets.sound("click"),
216 }
217 }273 fn build(&self, assets: &Assets) -> SoundData {
274 match self {
275 Sound::Bounce => assets.sound("bounce"),
276 Sound::Break => assets.sound("break"),
277 Sound::Serve => assets.sound("serve"),
278 Sound::GameOver => assets.sound("gameover"),
279 Sound::Lost => assets.sound("lost"),
280 Sound::Win => assets.sound("win"),
281 Sound::Click => assets.sound("click"),
282 Sound::Theme => assets.sound("music").streamed(),
283 Sound::ThemeDecoded => assets.sound("music"),
284 Sound::MenuTheme => assets.sound("menu_music").streamed(),
285 Sound::Pulse => assets.sound("break"),
286 }
287 }Trait Implementations§
Auto Trait Implementations§
impl Freeze for Assets
impl RefUnwindSafe for Assets
impl Send for Assets
impl Sync for Assets
impl Unpin for Assets
impl UnsafeUnpin for Assets
impl UnwindSafe for Assets
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more