AdamWhitehurst / bevy_sprite_animation

A simple 2d sprite animation plugin for the bevy game engine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

bevy_sprite_animation

A simple 2d sprite animation plugin for the bevy game engine;

anyone is welcome to make suggestion and corrections to this repositry: esspecialy my spelling :S

this is more or less a copy of Aarthificial's Reanimator for unity but for bevy of course.


subject to change with feedback

Usage

Add AnimationPlugin<T> and other systems to app

fn main() {
    App::build()
        .add_plugin(AnimationPlugin::<MainAnimation>::default())
        .add_startup_system(add_nodes.system())
        .add_startup_system(add_animator.system())
        .add_system(update_animator)
        .add_system(read_animator)
}

Add Nodes to Res<NodeTree<T>>

fn add_nodes(
    asset_server : Res<AssetServer>,
    mut node_tree : ResMut<AnimationNodes<MainAnimation>>,
) {
    //make some image handles
    let mut handles = Vec::new();
    for i in 0..10 {
        handles.push(asset_server.load(format!("SomeSprite_{}", i));
    }

    //add a node created in this system
    //hardcoded like this
    let node = Box::new(IndexNode::new("New Node", &handles));

    //with the nodes id being what ever the node implments for node.id()
    //by default this is a hash_map's DefaultHasher hash of its name
    node_tree.add_node(node);

    //withs a specific NodeID
    //this can be use to have to nodes with the same name.
    //use when loading a node if that node has an NodeID specifide
    node_tree.insert_node(NodeID::from("Node Name"), node);
    
    //load a node
    //from a file
    node_tree.load("example.node");
    //from a str
    node_tree.load_node_from_str("...complex node data...");
    
    //load a node_tree
    //from a file
    node_tree.load("example.nodetree");
    //from a str
    node_tree.load_node_from_str("...any number of chained node data");


}

Create an entity with an AnimationState on it that uses AnimationNodes<T> to pick its next frame

fn add_animator(
    mut commands: Commands,
) {
    //create a default state
    let mut state = AnimationState::default();
    //set starting Attributes
    start.set_attribute(Attribute::FLIP_X, true);
    //you can use custom Attributes
    //attributes can be any type that implments serde::serialize and serde::deserializeOwned
    start.set_attribute(Attribute::from_str("custom_attribute"), "cat");
    //if you use a custom attribute the name will be stored for debuging and sierialization
    start.set_attribute(Attribute::new_attribute("specil_attribute"), 5);

    //set temperary attribute
    //these will be removed if they are not changed each frame
    state.set_temporary(Attribute::from_str("Index(Idel)"));

    //remove temperary attribute
    //by default all attributes are persistent
    state.set_persistent(Attribute::from_str("Index(Idel)"));

    //add a sprite bundle
    commands.spawn_bundle(SpriteBundle::default())
    //add the state
    .insert(state)
    //add the flag for the AnimationNodes<T> to use
    .insert(MainAnimation);
}

Change the state of the AnimationState to controle what frame is picked next update

fn update_animation_state(
    mut animatiors : Query<&mut AnimationState>,
    input : Res<Input<KeyCode>>,
) {
    if input.just_pressed(KeyCode::Space){
    for mut animatior in animatiors.iter(){
      start.set_attribute(Attributes::from_str("custom_attribute"), "dog");
    }}
}

get an attribute from an AnimationState to create logic that happens only on special frames

fn read_animation_state(
    animatiors : Query<(Entity, &AnimationState)>,
) {
    for (entity, animatior) in animatiors.iter(){
      if let Ok(ground_type) = animatior.get_attribute::<GroundType>(Attributes::from_str("step")) {
        println!("{} is on a frame where you should play the sound of someone stepping on {}", entity, ground_type);
      }
    }
}

check if an attribute from AnimationState changed this frame

fn read_animation_change(
    animatiors : Query<(Entity, &AnimationState)>,
    dogs: Query<&mut Dogs>,
) {
    for (entity, animatior) in animatiors.iter(){
        //assuming barke is temporary it will only change when set true.
        //use changed for logic where you dont care what the attribute
        if animatior.changed(Attribures::from_str("barke")) {
            println!("{} is on a frame where you should play a barke sound effect", entity);
        }
    }

    for (entity, animatior) in animatiors.iter(){
        if animatior.changed(Attribures::from_str("dog_breed")) {
            let dog = dogs.get(animatior.get_attribute::<Entity>(Attributes::from_str("dog_breed")));
            //do something to the state bases on the breed it was set to
            println!("{} is on a frame where you should play a barke sound effect", entity);
        }
    }
}

About

A simple 2d sprite animation plugin for the bevy game engine


Languages

Language:Rust 100.0%