state_machine

Function state_machine 

Source
pub fn state_machine(name: &str, states: impl Into<Vec<State>>) -> StateMachine
Examples found in repository?
examples/compiler_global.rs (line 20)
12    fn construct_data() -> AnimGraph {
13        fn global_number(name: &str) -> Expression {
14            Expression::CompilerGlobal(name.to_owned())
15        }
16
17        let condition = bind_parameter::<f32>("a").ge(global_number(ALMOST_PI));
18        let endpoint = endpoint(state_event(TEST_EVENT, condition, EventEmit::Always));
19
20        let machines = [state_machine("Root", [state("StateA").with(endpoint, [])])];
21
22        AnimGraph {
23            state_machines: machines.into(),
24            ..Default::default()
25        }
26    }
More examples
Hide additional examples
examples/third_person.rs (lines 570-573)
530fn create_locomotion_graph() -> AnimGraph {
531    let resources = init_res([
532        SKELETON,
533        IDLE_CLIP,
534        WALKING_CLIP,
535        RUNNING_CLIP,
536        JUMPING_CLIP,
537        FALLING_CLIP,
538        DANCING_CLIP,
539        DANCING_UPPER_CLIP,
540        UPPER_BODY_MASK,
541    ]);
542
543    let parameters = vec![
544        init("grounded", true),
545        init("falling", true),
546        init("locomotion_speed", 0.0f32),
547        init("overdrive", 1.0f32),
548        init("moving", false),
549        init("dance", false),
550    ];
551
552    let locomotion_layer = {
553        let idle_node = alias("Idle", animation_pose(IDLE_CLIP));
554        let walking_node = alias("Walking", animation_pose(WALKING_CLIP));
555        let running_node = alias("Running", animation_pose(RUNNING_CLIP));
556
557        let locomotion_blend = endpoint(alias(
558            "locomotion",
559            blend_ranges(
560                bind_parameter("locomotion_speed"),
561                [(0.0, idle_node), (2.0, walking_node), (6.0, running_node)],
562            ),
563        ));
564
565        let speed_scaled_locomotion = preprocess(
566            speed_scale(bind_parameter("overdrive"), ALPHA_ONE),
567            locomotion_blend,
568        );
569
570        state_machine(
571            "Locomotion",
572            [state("Blend").with(speed_scaled_locomotion, [])],
573        )
574    };
575
576    let jump_layer = {
577        const STATE_FALLING: &str = "Falling";
578        const STATE_JUMPING: &str = "Jumping";
579        const STATE_OFF: &str = "Off";        
580
581        let not_grounded = bind_parameter::<bool>("grounded").not();
582        let has_fallen = bind_parameter::<bool>("falling").and(not_grounded.clone());
583
584        let state_off = state(STATE_OFF)
585            .with_branch(endpoint(inactive_layer()))
586            .with_transitions([
587                has_fallen.transition(STATE_FALLING, TRANSITION_DURATION),
588                not_grounded.transition(STATE_JUMPING, TRANSITION_DURATION),
589            ]);
590
591        let is_grounded = bind_parameter::<bool>("grounded").as_expr();
592        let is_falling = bind_parameter::<bool>("falling").as_expr();
593        let state_jumping = state(STATE_JUMPING)
594            .with_branch(endpoint(tree([
595                animation_pose(JUMPING_CLIP),
596                state_event("jumped", true, EventEmit::Entry),
597            ])))
598            .with_transitions([
599                is_grounded
600                    .clone()
601                    .transition(STATE_OFF, TRANSITION_DURATION),
602                is_falling.transition(STATE_FALLING, TRANSITION_DURATION),
603            ]);
604
605        let state_falling = state(STATE_FALLING)
606            .with_branch(endpoint(animation_pose(FALLING_CLIP)))
607            .with_transitions([is_grounded.transition(STATE_OFF, TRANSITION_DURATION)]);
608
609        state_machine("Jump", [state_off, state_jumping, state_falling])
610    };
611
612    let dance_layer = {
613        const STATE_OFF: &str = "Off";
614        const STATE_FULL: &str = "Full Body";
615        const STATE_UPPER: &str = "Upper Body";
616
617        let is_dancing =
618            bind_parameter::<bool>("dance").and(state_is("::Dance::Off", QueryType::Entered));
619        let is_moving_and_dancing = bind_parameter::<bool>("moving")
620            .or(bind_route::<bool>("action_active"))
621            .and(is_dancing.clone());
622        let state_off = state(STATE_OFF)
623            .with_branch(endpoint(inactive_layer()))
624            .with_transitions([
625                is_moving_and_dancing.transition(STATE_UPPER, TRANSITION_DURATION),
626                is_dancing.transition(STATE_FULL, TRANSITION_DURATION),
627            ]);
628
629        let state_full = {
630            let dancing_pose = endpoint(animation_pose(DANCING_CLIP));
631            let not_dancing = bind_parameter::<bool>("dance").not();
632            let is_moving = bind_parameter::<bool>("moving");
633            state(STATE_FULL)
634                .with_branch(dancing_pose)
635                .with_transitions([
636                    not_dancing.transition(STATE_OFF, FADE_OUT_DURATION),
637                    is_moving.transition(STATE_UPPER, TRANSITION_DURATION),
638                ])
639        };
640
641        let state_upper = {
642            let dancing_upper = endpoint(tree([
643                animation_pose(DANCING_UPPER_CLIP),
644                pose_mask(UPPER_BODY_MASK),
645            ]));
646            let is_idle_or_not_dancing =
647                bind_parameter::<bool>("dance")
648                    .not()
649                    .or(bind_parameter::<bool>("moving")
650                        .not()
651                        .and(bind_route::<bool>("action_active").not()));
652
653            state(STATE_UPPER)
654                .with_branch(dancing_upper)
655                .with_transitions([is_idle_or_not_dancing.transition(STATE_OFF, FADE_OUT_DURATION)])
656        };
657
658        state_machine("Dance", [state_off, state_upper, state_full])
659    };
660
661    let action_layer = {
662        const STATE_OFF: &str = "Off";
663        const STATE_FULL: &str = "Full Body";
664        const STATE_UPPER: &str = "Upper Body";
665
666        state_machine(
667            "Action",
668            [
669                state(STATE_OFF)
670                    .with_branch(endpoint(inactive_layer()))
671                    .with_transitions([
672                        bind_route::<bool>("action_active").transition(STATE_FULL, TRANSITION_DURATION),
673                        bind_route::<bool>("upper_body_action_active")
674                            .transition(STATE_UPPER, TRANSITION_DURATION),
675                    ]),
676                state(STATE_FULL)
677                    .with_branch(endpoint(reference_pose()))
678                    .with_transitions([bind_route::<bool>("action_active")
679                        .not()
680                        .or(bind_parameter::<bool>("moving"))
681                        .transition(STATE_OFF, TRANSITION_DURATION)]),
682                state(STATE_UPPER)
683                    .with_branch(endpoint(tree([
684                        reference_pose(),
685                        pose_mask(UPPER_BODY_MASK),
686                    ])))
687                    .with_transitions([bind_route::<bool>("upper_body_action_active")
688                        .not()
689                        .or(bind_route::<bool>("action_active"))
690                        .or(bind_parameter::<bool>("moving"))
691                        .transition(STATE_OFF, FADE_OUT_DURATION * 2.0)]),
692            ],
693        )
694    };
695
696    let root = state_machine(
697        "Root",
698        [state("Layers").with_layers([
699            submachine("Locomotion"),
700            submachine("Jump"),
701            preprocess(
702                tree([
703                    alias("action_active", event_emitted(ACTION_EVENT)),
704                    alias(
705                        "upper_body_action_active",
706                        event_emitted(UPPER_BODY_ACTION_EVENT),
707                    ),
708                ]),
709                submachine("Action"),
710            ),
711            submachine("Dance"),
712        ])],
713    );
714
715    AnimGraph {
716        resources,
717        parameters,
718        state_machines: vec![
719            root,
720            locomotion_layer,
721            jump_layer,
722            action_layer,
723            dance_layer,
724        ],
725        ..Default::default()
726    }
727}
728
729fn create_action_graph() -> AnimGraph {
730    let resources = init_res([
731        SKELETON,
732        SITTING_CLIP,
733        TURN_AND_SIT_CLIP,
734        POINTING_FORWARD_CLIP,
735        UPPER_BODY_MASK,
736    ]);
737
738    let parameters = vec![
739        init(
740            "fade_out",
741            InitialParameterValue::Event(FADE_OUT_EVENT.into()),
742        ),
743        init("turn_and_sit", false),
744        init("sit", InitialParameterValue::Event(SIT_EVENT.into())),
745        init("point_of_interest", InitialParameterValue::Vector([0.0; 3])),
746        init("enable_point_of_interest", false),
747        init(
748            "poi_cooldown",
749            InitialParameterValue::Event(COOLDOWN_EVENT.into()),
750        ),
751    ];
752
753    const COOLDOWN_EVENT: &str = "cooldown";
754    const FADE_OUT_EVENT: &str = "fade_out";
755    const SIT_EVENT: &str = "sit";
756
757    const POINTED_EVENT: &str = "pointed";
758
759    let pointing_cooldown = endpoint(tree([
760        reference_pose(),
761        state_event(COOLDOWN_EVENT, true, EventEmit::Entry),
762        alias("bounce_back", blend_in(ALPHA_ZERO, Seconds(5.0))),
763    ]));
764
765    let off_pose = endpoint(tree([
766        reference_pose(),
767        alias(
768            "poi_offset",
769            transform_offset("Hips", bind_parameter("point_of_interest")),
770        ),
771    ]));
772
773    const EMIT_ON_ENTER: EventEmit = EventEmit::Or(FlowState::Entering, FlowState::Entered);
774
775    let sitting_pose = endpoint(tree([
776        animation_pose(SITTING_CLIP),
777        state_event(ACTION_EVENT, true, EMIT_ON_ENTER),
778    ]));
779    let turn_and_sit_pose = endpoint(tree([
780        animation_pose(TURN_AND_SIT_CLIP),
781        state_event(ACTION_EVENT, true, EMIT_ON_ENTER),
782    ]));
783    let pointing_forward = endpoint(tree([
784        animation_pose(POINTING_FORWARD_CLIP),
785        remaining_event(
786            bind_route("animation_pose"),
787            POINTED_EVENT,
788            true,
789            TRANSITION_DURATION,
790            EventEmit::Never,
791        ),
792        state_event(UPPER_BODY_ACTION_EVENT, true, EMIT_ON_ENTER),
793    ]));
794    use QueryType::*;
795
796    const POINTING_STATE: &str = "Pointing";
797    const COOLDOWN_STATE: &str = "Cooldown";
798    let idling = state_machine(
799        "Idle",
800        [
801            state(OFF_STATE).with_branch(off_pose).with_transitions([
802                bind_route::<f32>("bounce_back")
803                    .not_equal(1.0)
804                    .immediate_transition(COOLDOWN_STATE),
805                bind_parameter::<bool>("enable_point_of_interest")
806                    .and(contains_inclusive(
807                        (0.4, 1.5),
808                        bind_route::<[f32; 3]>("poi_offset").projection(Projection::Length),
809                    ))
810                    .and(
811                        bind_route::<[f32; 3]>("poi_offset")
812                            .projection(Projection::Back)
813                            .gt(0.1),
814                    )
815                    .transition(POINTING_STATE, FADE_OUT_DURATION),
816            ]),
817            state(POINTING_STATE)
818                .with_branch(pointing_forward)
819                .with_transitions([bind_parameter::<bool>("enable_point_of_interest")
820                    .not()
821                    .or(event_is(POINTED_EVENT, QueryType::Active))
822                    .transition(COOLDOWN_STATE, FADE_OUT_DURATION * 2.0)]),
823            state(COOLDOWN_STATE)
824                .with_branch(pointing_cooldown)
825                .with_transitions([bind_route::<f32>("bounce_back")
826                    .equals(1.0)
827                    .immediate_transition(OFF_STATE)]),
828        ],
829    );
830
831    const OFF_STATE: &str = "Off";
832    const TURN_AND_SIT_STATE: &str = "Turn and sit";
833    const SITTING_STATE: &str = "Sitting";
834
835    let root = state_machine(
836        "Root",
837        [
838            state(OFF_STATE)
839                .with_branch(submachine("Idle"))
840                .with_transitions([
841                    event_is(FADE_OUT_EVENT, Exited)
842                        .and(event_is(SIT_EVENT, Active))
843                        .transition(SITTING_STATE, TRANSITION_DURATION),
844                    event_is(FADE_OUT_EVENT, Exited)
845                        .and(bind_parameter::<bool>("turn_and_sit"))
846                        .transition(TURN_AND_SIT_STATE, TRANSITION_DURATION),
847                ]),
848            state(SITTING_STATE)
849                .with_branch(sitting_pose)
850                .with_global_condition(
851                    event_is(FADE_OUT_EVENT, Exited).and(event_is(SIT_EVENT, Active)),
852                )
853                .with_transitions([event_is(SIT_EVENT, Exited)
854                    .as_expr()
855                    .transition(OFF_STATE, FADE_OUT_DURATION)]),
856            state(TURN_AND_SIT_STATE)
857                .with_branch(turn_and_sit_pose)
858                .with_global_condition(
859                    event_is(FADE_OUT_EVENT, Exited).and(bind_parameter::<bool>("turn_and_sit")),
860                )
861                .with_transitions([
862                    event_is(FADE_OUT_EVENT, Active)
863                        .as_expr()
864                        .transition(OFF_STATE, FADE_OUT_DURATION),
865                    event_is(SIT_EVENT, Active)
866                        .as_expr()
867                        .transition(SITTING_STATE, TRANSITION_DURATION),
868                ]),
869        ],
870    );
871
872    AnimGraph {
873        resources,
874        parameters,
875        state_machines: vec![root, idling],
876        ..Default::default()
877    }
878}