Files
Unreal_EmberWild/Source/Survival_projet/Private/PlayerBodyAnimInstance.cpp
T
Mathew 0ffa79efc3 (Feat) Corps 3e personne anime
Le pawn n'avait aucun mesh 3e personne : en coop, les autres joueurs
voyaient un pseudo flotter au-dessus du vide. C'est aussi le prerequis de
la customisation de personnage, qu'on ne peut pas empiler sur un corps
inexistant.

UPlayerBodyAnimInstance publie l'etat du pawn pour ABP_PlayerBody_A, sur
le meme partage des roles que UFpsArmsAnimInstance : le C++ lit et
republie, le Blueprint choisit l'animation. Rien n'est replique -- tout
derive d'un etat que le moteur ou le projet synchronisent deja (Velocity,
bIsCrouched, bIsSprinting, RemoteViewPitch).

VerticalSpeed distingue le SAUT de la CHUTE : bIsFalling vaut vrai dans
les deux cas, le moteur appelant "falling" tout ce qui n'est pas au sol.
Sans son signe, sortir d'une falaise jouerait l'animation de detente.

Le Cast du pawn est relance dans NativeUpdateAnimation : chez un client
le mesh arrive par replication et peut s'animer avant que le pawn soit
la, ce qui figerait le corps de l'ami en pose de reference pour toute la
partie -- invisible en solo comme chez l'hote.

Dev_Scene rejoint MapsToCook : GameLevel peut pointer sur elle le temps
d'un test, et une reference soft n'est pas suivie par le cooker.

Limites connues : pas d'animation accroupie (absente du pack) et le
BlendSpace s'arrete a 500 alors que le sprint est a 650.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 13:53:54 +02:00

94 lines
3.7 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerBodyAnimInstance.h"
#include "FpsPlayer.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "KismetAnimationLibrary.h"
void UPlayerBodyAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
OwningPlayer = Cast<AFpsPlayer>(TryGetPawnOwner());
}
void UPlayerBodyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
// Chez un CLIENT, le mesh arrive par replication et peut commencer a
// s'animer avant que le pawn soit completement initialise : le Cast du
// NativeInitialize rend alors nullptr, une fois pour toutes, et le corps de
// l'ami reste fige en pose de reference pour le reste de la partie. On
// reessaie donc tant qu'on n'a rien -- le cout est un Cast par frame
// uniquement pendant les quelques frames ou le pawn manque encore.
if (!OwningPlayer.IsValid())
{
OwningPlayer = Cast<AFpsPlayer>(TryGetPawnOwner());
if (!OwningPlayer.IsValid())
{
return;
}
}
const AFpsPlayer* BodyOwner = OwningPlayer.Get();
const UCharacterMovementComponent* Movement = BodyOwner->GetCharacterMovement();
if (!Movement)
{
return;
}
// Composante horizontale seule : en pleine chute la vitesse verticale
// depasse largement la vitesse de course, et un BlendSpace indexe dessus
// jouerait un sprint en l'air.
const FVector Velocity = BodyOwner->GetVelocity();
const FVector HorizontalVelocity(Velocity.X, Velocity.Y, 0.f);
GroundSpeed = HorizontalVelocity.Size();
// L'acceleration, et pas seulement la vitesse : elle tombe a zero des que la
// touche est relachee, alors que la vitesse decroit encore pendant tout le
// freinage. Sans elle le cycle de marche continuerait de tourner sur un
// personnage qui glisse jusqu'a l'arret.
bIsMoving = GroundSpeed > MovingSpeedThreshold
&& !Movement->GetCurrentAcceleration().IsNearlyZero();
bIsFalling = Movement->IsFalling();
// Prise telle quelle, sans seuil : c'est le Blueprint qui decide ou placer la
// bascule saut / chute. Une valeur brute reste une valeur brute -- lui donner
// un seuil ici, ce serait decider a la place de la machine a etats, et il
// faudrait recompiler pour le regler.
VerticalSpeed = Velocity.Z;
// Les deux etats du pawn, repliques chacun de leur cote : bIsCrouched par le
// moteur, bIsSprinting par AFpsPlayer. On les lit ici plutot que de deviner
// l'accroupissement a la hauteur de capsule, qui est en pleine interpolation
// pendant toute la transition.
bIsCrouching = BodyOwner->bIsCrouched;
bIsSprinting = BodyOwner->IsSprinting();
// Direction relative au CORPS et non a la vitesse du monde : c'est ce que
// demande un BlendSpace directionnel. GetActorRotation() suffit comme
// reference parce que bUseControllerRotationYaw garde le corps aligne sur le
// regard -- sur un jeu a la 3e personne libre, il faudrait la rotation de
// controle a la place.
//
// UKismetAnimationLibrary et pas UAnimInstance::CalculateDirection, depreciee
// en 5.8 : le calcul est le meme, mais l'ancienne cassera la compilation a la
// prochaine version du moteur.
LocomotionDirection = UKismetAnimationLibrary::CalculateDirection(HorizontalVelocity, BodyOwner->GetActorRotation());
// GetBaseAimRotation et pas GetControlRotation : le second n'existe que sur
// la machine qui possede le pawn, le premier retombe sur RemoteViewPitch
// pour les pawns des autres joueurs. NormalizeAxis ramene les 350 degres
// d'un regard vers le bas a -10, seule forme exploitable par un AimOffset.
AimPitch = FRotator::NormalizeAxis(BodyOwner->GetBaseAimRotation().Pitch);
LocomotionPlayRate = FMath::Clamp(
GroundSpeed / ReferenceLocomotionSpeed,
MinLocomotionPlayRate,
MaxLocomotionPlayRate);
}