mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-22 20:00:53 +00:00
4afa0f5d7d
* feat(animation): added example & boilerplate * moved animations specific code to a different module * added multiple robots & foxes * added example of controlling animation based on distance from the player * removed obsolete files * added information about animation to READMEs * updated dependencies closes #26
303 lines
11 KiB
Rust
303 lines
11 KiB
Rust
use bevy_rapier3d::prelude::Velocity;
|
|
use rand::Rng;
|
|
use std::time::Duration;
|
|
|
|
use bevy::prelude::*;
|
|
|
|
use crate::{
|
|
assets::GameAssets,
|
|
state::{GameState, InAppRunning},
|
|
};
|
|
use bevy_gltf_blueprints::{
|
|
AnimationPlayerLink, Animations, BluePrintBundle, BlueprintName, GameWorldTag,
|
|
};
|
|
|
|
use super::{Fox, Player, Robot};
|
|
|
|
pub fn setup_game(
|
|
mut commands: Commands,
|
|
game_assets: Res<GameAssets>,
|
|
mut next_game_state: ResMut<NextState<GameState>>,
|
|
) {
|
|
println!("setting up all stuff");
|
|
commands.insert_resource(AmbientLight {
|
|
color: Color::WHITE,
|
|
brightness: 0.2,
|
|
});
|
|
// here we actually spawn our game world/level
|
|
|
|
commands.spawn((
|
|
SceneBundle {
|
|
scene: game_assets.world.clone(),
|
|
..default()
|
|
},
|
|
bevy::prelude::Name::from("world"),
|
|
GameWorldTag,
|
|
InAppRunning,
|
|
));
|
|
|
|
next_game_state.set(GameState::InGame)
|
|
}
|
|
|
|
pub fn spawn_test(
|
|
keycode: Res<Input<KeyCode>>,
|
|
mut commands: Commands,
|
|
|
|
mut game_world: Query<(Entity, &Children), With<GameWorldTag>>,
|
|
) {
|
|
if keycode.just_pressed(KeyCode::T) {
|
|
let world = game_world.single_mut();
|
|
let world = world.1[0];
|
|
|
|
let mut rng = rand::thread_rng();
|
|
let range = 8.5;
|
|
let x: f32 = rng.gen_range(-range..range);
|
|
let y: f32 = rng.gen_range(-range..range);
|
|
|
|
let mut rng = rand::thread_rng();
|
|
let range = 0.8;
|
|
let vel_x: f32 = rng.gen_range(-range..range);
|
|
let vel_y: f32 = rng.gen_range(2.0..2.5);
|
|
let vel_z: f32 = rng.gen_range(-range..range);
|
|
|
|
let name_index: u64 = rng.gen();
|
|
|
|
let new_entity = commands
|
|
.spawn((
|
|
BluePrintBundle {
|
|
blueprint: BlueprintName("Fox".to_string()),
|
|
transform: TransformBundle::from_transform(Transform::from_xyz(x, 0.0, y)),
|
|
..Default::default()
|
|
},
|
|
bevy::prelude::Name::from(format!("Spawned{}", name_index)),
|
|
// BlueprintName("Health_Pickup".to_string()),
|
|
// SpawnHere,
|
|
// TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
|
|
Velocity {
|
|
linvel: Vec3::new(vel_x, vel_y, vel_z),
|
|
angvel: Vec3::new(0.0, 0.0, 0.0),
|
|
},
|
|
))
|
|
.id();
|
|
commands.entity(world).add_child(new_entity);
|
|
}
|
|
}
|
|
|
|
// example of changing animation of entities based on proximity to the player, for "fox" entities (Tag component)
|
|
pub fn animation_change_on_proximity_foxes(
|
|
players: Query<&GlobalTransform, With<Player>>,
|
|
animated_foxes: Query<(&GlobalTransform, &AnimationPlayerLink, &Animations), With<Fox>>,
|
|
|
|
mut animation_players: Query<&mut AnimationPlayer>,
|
|
) {
|
|
for player_transforms in players.iter() {
|
|
for (fox_tranforms, link, animations) in animated_foxes.iter() {
|
|
let distance = player_transforms
|
|
.translation()
|
|
.distance(fox_tranforms.translation());
|
|
let mut anim_name = "Walk";
|
|
if distance < 8.5 {
|
|
anim_name = "Run";
|
|
} else if distance >= 8.5 && distance < 10.0 {
|
|
anim_name = "Walk";
|
|
} else if distance >= 10.0 && distance < 15.0 {
|
|
anim_name = "Survey";
|
|
}
|
|
// now play the animation based on the chosen animation name
|
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
animation_player
|
|
.play_with_transition(
|
|
animations
|
|
.named_animations
|
|
.get(anim_name)
|
|
.expect("animation name should be in the list")
|
|
.clone(),
|
|
Duration::from_secs(3),
|
|
)
|
|
.repeat();
|
|
}
|
|
}
|
|
}
|
|
|
|
// example of changing animation of entities based on proximity to the player, this time for the "robot" entities (Tag component)
|
|
pub fn animation_change_on_proximity_robots(
|
|
players: Query<&GlobalTransform, With<Player>>,
|
|
animated_robots: Query<(&GlobalTransform, &AnimationPlayerLink, &Animations), With<Robot>>,
|
|
|
|
mut animation_players: Query<&mut AnimationPlayer>,
|
|
) {
|
|
for player_transforms in players.iter() {
|
|
for (robot_tranforms, link, animations) in animated_robots.iter() {
|
|
let distance = player_transforms
|
|
.translation()
|
|
.distance(robot_tranforms.translation());
|
|
|
|
let mut anim_name = "Idle";
|
|
if distance < 8.5 {
|
|
anim_name = "Jump";
|
|
} else if distance >= 8.5 && distance < 10.0 {
|
|
anim_name = "Scan";
|
|
} else if distance >= 10.0 && distance < 15.0 {
|
|
anim_name = "Idle";
|
|
}
|
|
|
|
// now play the animation based on the chosen animation name
|
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
animation_player
|
|
.play_with_transition(
|
|
animations
|
|
.named_animations
|
|
.get(anim_name)
|
|
.expect("animation name should be in the list")
|
|
.clone(),
|
|
Duration::from_secs(3),
|
|
)
|
|
.repeat();
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn animation_control(
|
|
animated_enemies: Query<(&AnimationPlayerLink, &Animations), With<Robot>>,
|
|
animated_foxes: Query<(&AnimationPlayerLink, &Animations), With<Fox>>,
|
|
|
|
mut animation_players: Query<&mut AnimationPlayer>,
|
|
|
|
keycode: Res<Input<KeyCode>>,
|
|
// mut entities_with_animations : Query<(&mut AnimationPlayer, &mut Animations)>,
|
|
) {
|
|
// robots
|
|
if keycode.just_pressed(KeyCode::B) {
|
|
for (link, animations) in animated_enemies.iter() {
|
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
let anim_name = "Scan";
|
|
animation_player
|
|
.play_with_transition(
|
|
animations
|
|
.named_animations
|
|
.get(anim_name)
|
|
.expect("animation name should be in the list")
|
|
.clone(),
|
|
Duration::from_secs(5),
|
|
)
|
|
.repeat();
|
|
}
|
|
}
|
|
|
|
// foxes
|
|
if keycode.just_pressed(KeyCode::W) {
|
|
for (link, animations) in animated_foxes.iter() {
|
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
let anim_name = "Walk";
|
|
animation_player
|
|
.play_with_transition(
|
|
animations
|
|
.named_animations
|
|
.get(anim_name)
|
|
.expect("animation name should be in the list")
|
|
.clone(),
|
|
Duration::from_secs(5),
|
|
)
|
|
.repeat();
|
|
}
|
|
}
|
|
|
|
if keycode.just_pressed(KeyCode::X) {
|
|
for (link, animations) in animated_foxes.iter() {
|
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
let anim_name = "Run";
|
|
animation_player
|
|
.play_with_transition(
|
|
animations
|
|
.named_animations
|
|
.get(anim_name)
|
|
.expect("animation name should be in the list")
|
|
.clone(),
|
|
Duration::from_secs(5),
|
|
)
|
|
.repeat();
|
|
}
|
|
}
|
|
|
|
if keycode.just_pressed(KeyCode::C) {
|
|
for (link, animations) in animated_foxes.iter() {
|
|
let mut animation_player = animation_players.get_mut(link.0).unwrap();
|
|
let anim_name = "Survey";
|
|
animation_player
|
|
.play_with_transition(
|
|
animations
|
|
.named_animations
|
|
.get(anim_name)
|
|
.expect("animation name should be in the list")
|
|
.clone(),
|
|
Duration::from_secs(5),
|
|
)
|
|
.repeat();
|
|
}
|
|
}
|
|
|
|
/* Improveement ideas for the future
|
|
// a bit more ideal API
|
|
if keycode.just_pressed(KeyCode::B) {
|
|
for (animation_player, animations) in animated_enemies.iter() {
|
|
let anim_name = "Scan";
|
|
if animations.named_animations.contains_key(anim_name) {
|
|
let clip = animations.named_animations.get(anim_name).unwrap();
|
|
animation_player.play_with_transition(clip.clone(), Duration::from_secs(5)).repeat();
|
|
}
|
|
}
|
|
}
|
|
|
|
// even better API
|
|
if keycode.just_pressed(KeyCode::B) {
|
|
for (animation_player, animations) in animated_enemies.iter() {
|
|
animation_player.play_with_transition("Scan", Duration::from_secs(5)).repeat(); // with a merged animationPlayer + animations storage
|
|
// alternative, perhaps more realistic, and better seperation of concerns
|
|
animation_player.play_with_transition(animations, "Scan", Duration::from_secs(5)).repeat();
|
|
|
|
}
|
|
}*/
|
|
|
|
/*for (mut anim_player, animations) in entities_with_animations.iter_mut(){
|
|
|
|
if keycode.just_pressed(KeyCode::W) {
|
|
let anim_name = "Walk";
|
|
if animations.named_animations.contains_key(anim_name) {
|
|
let clip = animations.named_animations.get(anim_name).unwrap();
|
|
anim_player.play_with_transition(clip.clone(), Duration::from_secs(5)).repeat();
|
|
}
|
|
}
|
|
if keycode.just_pressed(KeyCode::X) {
|
|
let anim_name = "Run";
|
|
if animations.named_animations.contains_key(anim_name) {
|
|
let clip = animations.named_animations.get(anim_name).unwrap();
|
|
anim_player.play_with_transition(clip.clone(), Duration::from_secs(5)).repeat();
|
|
}
|
|
}
|
|
if keycode.just_pressed(KeyCode::C) {
|
|
let anim_name = "Survey";
|
|
if animations.named_animations.contains_key(anim_name) {
|
|
let clip = animations.named_animations.get(anim_name).unwrap();
|
|
anim_player.play_with_transition(clip.clone(), Duration::from_secs(5)).repeat();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if keycode.just_pressed(KeyCode::S) {
|
|
let anim_name = "Scan";
|
|
if animations.named_animations.contains_key(anim_name) {
|
|
let clip = animations.named_animations.get(anim_name).unwrap();
|
|
anim_player.play_with_transition(clip.clone(), Duration::from_secs(5)).repeat();
|
|
}
|
|
}
|
|
if keycode.just_pressed(KeyCode::I) {
|
|
let anim_name = "Idle";
|
|
if animations.named_animations.contains_key(anim_name) {
|
|
let clip = animations.named_animations.get(anim_name).unwrap();
|
|
anim_player.play_with_transition(clip.clone(), Duration::from_secs(5)).repeat();
|
|
}
|
|
}
|
|
}*/
|
|
}
|