Implement root motion into grounded attacks and implement dash attack
This commit is contained in:
@@ -122,6 +122,10 @@ pub struct FighterBoneMatrices {
|
||||
model_matrices: Vec<Option<FixedMat4>>,
|
||||
presentation_kind: Option<AnimKind>,
|
||||
previous_animation_frame: Option<FighterAnimationFrame>,
|
||||
/// The raw, scaled model-space root translation used as the baseline for
|
||||
/// root-motion extraction. This is kept separately because the published
|
||||
/// pose has the root translation removed.
|
||||
previous_root_motion_translation: Option<FGVec3>,
|
||||
root_motion_delta: crate::math::vec3::FGVec3,
|
||||
}
|
||||
|
||||
@@ -351,6 +355,17 @@ impl FighterBoneMatrices {
|
||||
}
|
||||
self.local_matrices.clear();
|
||||
self.local_matrices.extend_from_slice(local);
|
||||
|
||||
let root_index = if root_motion_bone.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
self.bone_names
|
||||
.iter()
|
||||
.position(|name| name == root_motion_bone)
|
||||
.expect("configured root motion bone should exist"),
|
||||
)
|
||||
};
|
||||
self.model_matrices.resize(local.len(), None);
|
||||
self.model_matrices.fill(None);
|
||||
for index in 0..local.len() {
|
||||
@@ -365,6 +380,26 @@ impl FighterBoneMatrices {
|
||||
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
|
||||
],
|
||||
};
|
||||
let raw_root_motion_translation = root_index.map(|root_index| {
|
||||
model_scale
|
||||
.mul(
|
||||
self.model_matrices[root_index]
|
||||
.expect("baked bone hierarchy should be valid"),
|
||||
)
|
||||
.get_translation()
|
||||
});
|
||||
|
||||
// Gameplay owns the root's displacement. Keep rotation and scale in
|
||||
// the animation, but remove its translation before publishing the pose
|
||||
// used by visuals and gameplay volumes.
|
||||
if let Some(root_index) = root_index {
|
||||
self.local_matrices[root_index].translate(FGVec3::ZERO);
|
||||
self.model_matrices.fill(None);
|
||||
for index in 0..local.len() {
|
||||
resolve_model_transform(index, parents, &self.local_matrices, &mut self.model_matrices)
|
||||
.expect("baked bone hierarchy should be valid");
|
||||
}
|
||||
}
|
||||
self.matrices.clear();
|
||||
self.matrices.extend(
|
||||
self.model_matrices.iter().map(|matrix| {
|
||||
@@ -374,15 +409,12 @@ impl FighterBoneMatrices {
|
||||
self.root_motion_delta = if advance_history
|
||||
&& !animation_changed
|
||||
&& self.previous_animation_frame.is_some()
|
||||
&& !root_motion_bone.is_empty()
|
||||
&& let (Some(current), Some(previous)) = (
|
||||
raw_root_motion_translation,
|
||||
self.previous_root_motion_translation,
|
||||
)
|
||||
{
|
||||
let root_index = self
|
||||
.bone_names
|
||||
.iter()
|
||||
.position(|name| name == root_motion_bone)
|
||||
.expect("configured root motion bone should exist");
|
||||
let mut delta = self.matrices[root_index].get_translation()
|
||||
- self.previous_frame_matrices[root_index].get_translation();
|
||||
let mut delta = current - previous;
|
||||
if animation_frame.repeat
|
||||
&& self.previous_animation_frame.is_some_and(|previous| {
|
||||
previous.frame.saturating_add(1) == animation_frame.frame
|
||||
@@ -395,6 +427,7 @@ impl FighterBoneMatrices {
|
||||
} else {
|
||||
FGVec3::ZERO
|
||||
};
|
||||
self.previous_root_motion_translation = raw_root_motion_translation;
|
||||
if advance_history {
|
||||
self.previous_animation_frame = Some(animation_frame);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user