2024-04-22 17:42:51 +00:00
|
|
|
// ▄████████▄ + ███ + ▄█████████ ███ +
|
|
|
|
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
|
|
|
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
|
|
|
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
|
|
|
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
|
|
|
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
|
|
|
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
|
|
|
// + + + ███
|
|
|
|
// + ▀████████████████████████████████████████████████████▀
|
|
|
|
|
2024-04-22 19:01:27 +00:00
|
|
|
use bevy::ecs::system::EntityCommands;
|
2024-04-22 17:42:51 +00:00
|
|
|
use bevy::prelude::*;
|
2024-04-22 19:01:27 +00:00
|
|
|
|
2024-04-22 21:09:50 +00:00
|
|
|
pub struct SkeletonPlugin;
|
|
|
|
impl Plugin for SkeletonPlugin {
|
|
|
|
fn build(&self, app: &mut App) {
|
|
|
|
app.add_systems(Update, animate_skeleton_parts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 19:01:27 +00:00
|
|
|
pub fn asset_name_to_path(name: &str) -> &'static str {
|
|
|
|
match name {
|
|
|
|
"suit" => "models/suit_with_collider.glb#Scene0",
|
|
|
|
"suit_ar_chefhat" => "models/suit_ar_chefhat.glb#Scene0",
|
|
|
|
"asteroid1" => "models/asteroid.glb#Scene0",
|
|
|
|
"asteroid2" => "models/asteroid2.glb#Scene0",
|
|
|
|
"asteroid_lum" => "models/asteroid_lum.glb#Scene0",
|
|
|
|
"moonlet" => "models/moonlet.glb#Scene0",
|
|
|
|
"monolith" => "models/monolith_neon.glb#Scene0",
|
|
|
|
"lightorb" => "models/lightorb.glb#Scene0",
|
|
|
|
"orb_busstop" => "models/orb_busstop.glb#Scene0",
|
|
|
|
"orb_busstop_dim" => "models/orb_busstop_dim.glb#Scene0",
|
|
|
|
"MeteorAceGT" => "models/MeteorAceGT.glb#Scene0",
|
|
|
|
"satellite" => "models/satellite.glb#Scene0",
|
|
|
|
"pizzeria" => "models/pizzeria2.glb#Scene0",
|
|
|
|
"pizzasign" => "models/pizzasign.glb#Scene0",
|
|
|
|
"selectagon" => "models/selectagon.glb#Scene0",
|
|
|
|
"orbitring" => "models/orbitring.glb#Scene0",
|
|
|
|
"clippy" => "models/clippy.glb#Scene0",
|
|
|
|
"clippy_ar" => "models/clippy_ar.glb#Scene0",
|
|
|
|
"whale" => "models/whale.glb#Scene0",
|
|
|
|
"point_of_interest" => "models/point_of_interest.glb#Scene0",
|
|
|
|
_ => "models/error.glb#Scene0",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 19:09:05 +00:00
|
|
|
pub fn skeleton_name_to_skeletondef(name: &str) -> Option<SkeletonDef> {
|
|
|
|
match name {
|
2024-04-22 20:21:18 +00:00
|
|
|
"suitv1" => Some(SkeletonDef::Human(HumanDef {
|
|
|
|
collider: "skeleton/suit_v1/collider.glb#Scene0".into(),
|
|
|
|
base: "skeleton/suit_v1/base.glb#Scene0".into(),
|
|
|
|
limbs: vec![
|
|
|
|
LimbDef {
|
|
|
|
class: Limb::Head,
|
|
|
|
path: "skeleton/suit_v1/head.glb#Scene0".into(),
|
|
|
|
pos: Vec3::new(0.0, 0.5, 0.0),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
LimbDef {
|
|
|
|
class: Limb::UpperArmLeft,
|
|
|
|
path: "skeleton/suit_v1/upper_arm.glb#Scene0".into(),
|
2024-04-22 21:11:41 +00:00
|
|
|
pos: Vec3::new(0.22, 0.3, 0.0),
|
2024-04-22 20:21:18 +00:00
|
|
|
mirror: true,
|
|
|
|
children: vec![LimbDef {
|
|
|
|
class: Limb::LowerArmLeft,
|
|
|
|
path: "skeleton/suit_v1/lower_arm.glb#Scene0".into(),
|
|
|
|
pos: Vec3::new(-0.33, 0.0, 0.0),
|
|
|
|
..default()
|
|
|
|
}],
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
LimbDef {
|
|
|
|
class: Limb::UpperArmRight,
|
|
|
|
path: "skeleton/suit_v1/upper_arm.glb#Scene0".into(),
|
2024-04-22 21:11:41 +00:00
|
|
|
pos: Vec3::new(-0.22, 0.3, 0.0),
|
2024-04-22 20:21:18 +00:00
|
|
|
children: vec![LimbDef {
|
|
|
|
class: Limb::LowerArmRight,
|
|
|
|
path: "skeleton/suit_v1/lower_arm.glb#Scene0".into(),
|
|
|
|
pos: Vec3::new(-0.33, 0.0, 0.0),
|
|
|
|
..default()
|
|
|
|
}],
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
LimbDef {
|
|
|
|
class: Limb::UpperLegLeft,
|
|
|
|
path: "skeleton/suit_v1/upper_leg.glb#Scene0".into(),
|
|
|
|
pos: Vec3::new(0.15, -0.25, 0.0),
|
|
|
|
mirror: true,
|
|
|
|
children: vec![LimbDef {
|
|
|
|
class: Limb::LowerLegLeft,
|
|
|
|
path: "skeleton/suit_v1/lower_leg.glb#Scene0".into(),
|
|
|
|
pos: Vec3::new(0.0, -0.3, 0.0),
|
|
|
|
..default()
|
|
|
|
}],
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
LimbDef {
|
|
|
|
class: Limb::UpperLegRight,
|
|
|
|
path: "skeleton/suit_v1/upper_leg.glb#Scene0".into(),
|
|
|
|
pos: Vec3::new(-0.15, -0.25, 0.0),
|
|
|
|
children: vec![LimbDef {
|
|
|
|
class: Limb::LowerLegRight,
|
|
|
|
path: "skeleton/suit_v1/lower_leg.glb#Scene0".into(),
|
|
|
|
pos: Vec3::new(0.0, -0.3, 0.0),
|
|
|
|
..default()
|
|
|
|
}],
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
],
|
|
|
|
})),
|
2024-04-22 19:09:05 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
2024-04-22 19:01:27 +00:00
|
|
|
}
|
2024-04-22 17:42:51 +00:00
|
|
|
|
2024-04-22 19:01:27 +00:00
|
|
|
#[derive(Component)] pub struct SkeletonLimb;
|
2024-04-22 21:09:50 +00:00
|
|
|
#[derive(Component)] pub struct MirroredLimb;
|
2024-04-22 20:21:18 +00:00
|
|
|
pub enum SkeletonDef {
|
|
|
|
Human(HumanDef)
|
2024-04-22 19:09:05 +00:00
|
|
|
}
|
2024-04-22 19:01:27 +00:00
|
|
|
|
2024-04-22 20:21:18 +00:00
|
|
|
pub struct HumanDef {
|
|
|
|
collider: String,
|
|
|
|
base: String,
|
|
|
|
limbs: Vec<LimbDef>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct LimbDef {
|
|
|
|
path: String,
|
|
|
|
pos: Vec3,
|
|
|
|
class: Limb,
|
|
|
|
mirror: bool,
|
|
|
|
children: Vec<LimbDef>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Component, Default)]
|
|
|
|
pub enum Limb {
|
|
|
|
#[default]
|
|
|
|
Base,
|
|
|
|
Head,
|
|
|
|
UpperArmRight,
|
|
|
|
UpperArmLeft,
|
|
|
|
LowerArmRight,
|
|
|
|
LowerArmLeft,
|
|
|
|
UpperLegRight,
|
|
|
|
UpperLegLeft,
|
|
|
|
LowerLegRight,
|
|
|
|
LowerLegLeft,
|
|
|
|
}
|
2024-04-22 19:01:27 +00:00
|
|
|
|
|
|
|
pub fn load(
|
|
|
|
name: &str,
|
|
|
|
entity_commands: &mut EntityCommands,
|
|
|
|
asset_server: &AssetServer,
|
|
|
|
) {
|
2024-04-22 19:09:05 +00:00
|
|
|
if let Some(skel) = skeleton_name_to_skeletondef(name) {
|
2024-04-22 20:21:18 +00:00
|
|
|
match skel {
|
|
|
|
SkeletonDef::Human(human) => {
|
|
|
|
entity_commands.insert(load_scene_by_path(human.collider.as_str(), asset_server));
|
|
|
|
entity_commands.with_children(|parent| {
|
|
|
|
parent.spawn((
|
|
|
|
Limb::Base,
|
|
|
|
SceneBundle {
|
|
|
|
scene: load_scene_by_path(human.base.as_str(), asset_server),
|
|
|
|
..default()
|
|
|
|
}
|
|
|
|
));
|
|
|
|
for limb in human.limbs {
|
|
|
|
let rot = if limb.mirror {
|
|
|
|
Quat::from_rotation_y(180.0f32.to_radians())
|
|
|
|
} else {
|
|
|
|
Quat::IDENTITY
|
|
|
|
};
|
|
|
|
let mut parent_limb = parent.spawn((
|
|
|
|
limb.class,
|
|
|
|
SceneBundle {
|
|
|
|
scene: load_scene_by_path(limb.path.as_str(), asset_server),
|
|
|
|
transform: Transform::from_translation(limb.pos).with_rotation(rot),
|
|
|
|
..default()
|
|
|
|
}
|
|
|
|
));
|
2024-04-22 21:09:50 +00:00
|
|
|
if limb.mirror {
|
|
|
|
parent_limb.insert(MirroredLimb);
|
|
|
|
}
|
2024-04-22 20:21:18 +00:00
|
|
|
if !limb.children.is_empty() {
|
|
|
|
parent_limb.with_children(|parent| {
|
|
|
|
for child_limb in limb.children {
|
|
|
|
let rot = if child_limb.mirror {
|
|
|
|
Quat::from_rotation_y(180.0f32.to_radians())
|
|
|
|
} else {
|
|
|
|
Quat::IDENTITY
|
|
|
|
};
|
2024-04-22 21:09:50 +00:00
|
|
|
let mut entity_commands = parent.spawn((
|
2024-04-22 20:21:18 +00:00
|
|
|
child_limb.class,
|
|
|
|
SceneBundle {
|
|
|
|
scene: load_scene_by_path(child_limb.path.as_str(), asset_server),
|
|
|
|
transform: Transform::from_translation(child_limb.pos).with_rotation(rot),
|
|
|
|
..default()
|
|
|
|
}
|
|
|
|
));
|
2024-04-22 21:09:50 +00:00
|
|
|
if child_limb.mirror {
|
|
|
|
entity_commands.insert(MirroredLimb);
|
|
|
|
}
|
2024-04-22 20:21:18 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2024-04-22 19:09:05 +00:00
|
|
|
} else {
|
2024-04-22 19:01:27 +00:00
|
|
|
entity_commands.insert(load_scene_by_path(asset_name_to_path(name), asset_server));
|
2024-04-22 17:42:51 +00:00
|
|
|
}
|
2024-04-22 19:01:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//pub fn load_scene(
|
|
|
|
// path: &str,
|
|
|
|
// asset_server: &AssetServer
|
|
|
|
//) -> Handle<Scene> {
|
|
|
|
// load_scene_by_path(asset_name_to_path(path), asset_server)
|
|
|
|
//}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn load_scene_by_path(
|
|
|
|
path: &str,
|
|
|
|
asset_server: &AssetServer
|
|
|
|
) -> Handle<Scene> {
|
|
|
|
let path_string = path.to_string();
|
|
|
|
if let Some(handle) = asset_server.get_handle(&path_string) {
|
|
|
|
handle
|
|
|
|
} else {
|
|
|
|
asset_server.load(&path_string)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn _build_body(
|
|
|
|
_name: String,
|
|
|
|
mut _entity_commands: EntityCommands,
|
|
|
|
) {
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn animate_skeleton_parts(
|
2024-04-22 21:09:50 +00:00
|
|
|
time: Res<Time>,
|
|
|
|
mut q_limb: Query<(&mut Transform, &Limb, Option<&MirroredLimb>)>,
|
2024-04-22 19:01:27 +00:00
|
|
|
) {
|
2024-04-22 21:09:50 +00:00
|
|
|
let t = time.elapsed_seconds();
|
|
|
|
for (mut trans, limb, mirror) in &mut q_limb {
|
|
|
|
let mirror = mirror.is_some();
|
|
|
|
let m = {|angle| if mirror { 180f32 + angle } else { angle }};
|
|
|
|
let mut rot = {|x: f32, y: f32, z: f32|
|
|
|
|
trans.rotation = Quat::from_euler(EulerRot::XYZ,
|
|
|
|
x.to_radians(), y.to_radians(), z.to_radians())
|
|
|
|
};
|
|
|
|
// x: lean head forward/backward
|
|
|
|
// y: close/open arms together in front of the torso
|
|
|
|
// z: spread legs sidewards
|
|
|
|
match limb {
|
|
|
|
Limb::UpperArmRight => rot(
|
|
|
|
0.0,
|
|
|
|
m(40.0 + 5.0 * (t * 0.5).sin()),
|
|
|
|
20.0 + 10.0 * (t * 0.5).sin(),
|
|
|
|
),
|
|
|
|
Limb::UpperArmLeft => rot(
|
|
|
|
0.0,
|
|
|
|
m(-(40.0 + 5.0 * (t * 0.5).sin())),
|
|
|
|
20.0 + 10.0 * (t * 0.5).sin(),
|
|
|
|
),
|
|
|
|
Limb::LowerArmRight => rot(
|
|
|
|
0.0,
|
|
|
|
m(20.0),
|
|
|
|
-20.0,
|
|
|
|
),
|
|
|
|
Limb::LowerArmLeft => rot(
|
|
|
|
0.0,
|
|
|
|
m(-20.0),
|
|
|
|
-20.0,
|
|
|
|
),
|
|
|
|
Limb::UpperLegRight => rot(
|
|
|
|
-30.0 + 10.0 * (t * 0.5).sin(),
|
|
|
|
0.0,
|
|
|
|
-25.0 + 2.5 * (t * 0.5).cos(),
|
|
|
|
),
|
|
|
|
Limb::UpperLegLeft => rot(
|
|
|
|
-30.0 + 10.0 * (t * 0.5).sin(),
|
|
|
|
0.0,
|
|
|
|
25.0 - 2.5 * (t * 0.5).cos(),
|
|
|
|
),
|
|
|
|
Limb::LowerLegRight => rot(
|
|
|
|
30.0,
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
),
|
|
|
|
Limb::LowerLegLeft => rot(
|
|
|
|
30.0,
|
|
|
|
0.0,
|
|
|
|
0.0,
|
|
|
|
),
|
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
}
|
2024-04-22 17:42:51 +00:00
|
|
|
}
|