// Simple 2D blend space for locomotion (direction + speed)
struct BlendSpaceAnimation {
uint32_t animationIndex;
float directionAngle; // In degrees, 0 = forward, 180 = backward
float speed; // In units/second
};
void updateLocomotionBlendSpace(float currentDirection, float currentSpeed) {
// Define our blend space animations
std::vector<BlendSpaceAnimation> blendSpace = {
{0, 0.0f, 0.0f}, // Idle
{1, 0.0f, 1.0f}, // Walk Forward
{2, 0.0f, 3.0f}, // Run Forward
{3, 90.0f, 1.0f}, // Walk Right
{4, 90.0f, 3.0f}, // Run Right
{5, 180.0f, 1.0f}, // Walk Backward
{6, 180.0f, 3.0f}, // Run Backward
{7, 270.0f, 1.0f}, // Walk Left
{8, 270.0f, 3.0f} // Run Left
};
// Find the closest animations and their weights
std::vector<uint32_t> animIndices;
std::vector<float> weights;
// Normalize direction to 0-360 range
currentDirection = fmod(currentDirection + 360.0f, 360.0f);
// Find the 3 closest animations in the blend space
// This is a simplified approach - a real implementation would use triangulation
for (const auto& anim : blendSpace) {
float distDir = std::min(std::abs(currentDirection - anim.directionAngle),
360.0f - std::abs(currentDirection - anim.directionAngle));
float distSpeed = std::abs(currentSpeed - anim.speed);
// Calculate distance in blend space (weighted combination of direction and speed)
float distance = std::sqrt(distDir * distDir * 0.01f + distSpeed * distSpeed);
// Use inverse distance weighting
if (distance < 0.001f) {
// If we're very close to an exact animation, just use that one
animIndices = {anim.animationIndex};
weights = {1.0f};
break;
}
float weight = 1.0f / (distance + 0.1f); // Add small epsilon to avoid division by zero
animIndices.push_back(anim.animationIndex);
weights.push_back(weight);
// Limit to 3 closest animations for performance
// Note: This works because we're inside the loop - we remove one element each time
// the size exceeds 3, maintaining a maximum of 3 elements as we iterate
if (animIndices.size() > 3) {
// Find the smallest weight
auto minIt = std::min_element(weights.begin(), weights.end());
size_t minIdx = std::distance(weights.begin(), minIt);
// Remove the animation with the smallest weight
animIndices.erase(animIndices.begin() + minIdx);
weights.erase(weights.begin() + minIdx);
}
}
// Blend the selected animations
blendMultipleAnimations(animIndices, weights);
}