(Feat) Add Animation Fps Charater
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "HeadBobComponent.generated.h"
|
||||
|
||||
class ACharacter;
|
||||
class UCharacterMovementComponent;
|
||||
|
||||
/**
|
||||
* Les reglages d'un etat de deplacement : immobile, marche, sprint, accroupi, en l'air.
|
||||
*
|
||||
* Regroupes dans une struct plutot qu'a plat sur le composant pour deux raisons.
|
||||
* D'abord le Details panel : cinq etats x cinq valeurs a plat feraient vingt-cinq
|
||||
* lignes melangees, alors que la struct donne un repli par etat. Ensuite le code :
|
||||
* passer d'un etat a l'autre est une interpolation champ a champ, et une struct
|
||||
* permet de l'ecrire une seule fois au lieu d'une par valeur.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHeadBobProfile
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FHeadBobProfile() = default;
|
||||
|
||||
FHeadBobProfile(float InStrideFrequency, float InVerticalAmount, float InLateralAmount, float InRollAmount, float InPitchAmount)
|
||||
: StrideFrequency(InStrideFrequency)
|
||||
, VerticalAmount(InVerticalAmount)
|
||||
, LateralAmount(InLateralAmount)
|
||||
, RollAmount(InRollAmount)
|
||||
, PitchAmount(InPitchAmount)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Foulees par seconde. Une foulee compte DEUX pas : l'oscillation verticale
|
||||
* bat donc au double de cette valeur, une bosse par pied qui touche le sol.
|
||||
* A 1.1, les pas tombent a 2.2 Hz, ce qui correspond a une marche normale.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob", meta = (ClampMin = "0", UIMax = "4"))
|
||||
float StrideFrequency = 1.1f;
|
||||
|
||||
/** Amplitude verticale en cm, mesuree du repos au sommet (le debattement total vaut le double). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob", meta = (ClampMin = "0", UIMax = "10"))
|
||||
float VerticalAmount = 1.6f;
|
||||
|
||||
/** Amplitude laterale en cm : le balancement gauche-droite du buste. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob", meta = (ClampMin = "0", UIMax = "10"))
|
||||
float LateralAmount = 1.2f;
|
||||
|
||||
/** Roulis en degres au pic du balancement lateral. La tete penche dans le sens du pas. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob", meta = (UIMin = "-3", UIMax = "3"))
|
||||
float RollAmount = 0.4f;
|
||||
|
||||
/**
|
||||
* Tangage en degres au pic vertical. A 0 par defaut, et ce n'est pas un oubli :
|
||||
* le tangage deplace le reticule, donc il degrade la visee. A n'ouvrir que si
|
||||
* l'on assume un jeu ou l'on ne vise pas au pixel.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob", meta = (UIMin = "-3", UIMax = "3"))
|
||||
float PitchAmount = 0.f;
|
||||
};
|
||||
|
||||
/**
|
||||
* Balancement de tete procedural, sans la moindre animation authoree.
|
||||
*
|
||||
* Le principe tient en une phase unique, avancee chaque frame par la frequence de
|
||||
* l'etat courant, et une amplitude qui glisse d'un etat a l'autre. C'est ce qui
|
||||
* rend le passage marche -> sprint continu : ce n'est pas une animation qu'on
|
||||
* coupe pour en lancer une autre, ce sont deux jeux de coefficients entre lesquels
|
||||
* on interpole pendant que la phase, elle, ne s'interrompt jamais. Remettre la
|
||||
* phase a zero a chaque changement d'etat produirait exactement le "clac" qu'on
|
||||
* cherche a eviter.
|
||||
*
|
||||
* Le composant ne touche PAS a la camera. Il expose un decalage de position et un
|
||||
* decalage de rotation, que AFpsPlayer::ApplyCameraTransform additionne aux siens.
|
||||
* C'est la condition pour que cette fonction reste le seul endroit du projet qui
|
||||
* ecrit la transform de la camera -- elle est rappelee depuis CalcCamera, et deux
|
||||
* ecrivains se marcheraient dessus une frame sur deux.
|
||||
*
|
||||
* Rien n'est replique et rien n'a a l'etre : le balancement n'existe que dans les
|
||||
* yeux du joueur local. Les bras suivent gratuitement, puisqu'ils sont attaches a
|
||||
* la camera.
|
||||
*/
|
||||
UCLASS(ClassGroup = (Survival), meta = (BlueprintSpawnableComponent))
|
||||
class EMBERWILD_API UHeadBobComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UHeadBobComponent();
|
||||
|
||||
/**
|
||||
* Fait avancer la phase et recalcule les decalages.
|
||||
*
|
||||
* Appelee par le pawn depuis son Tick, et surtout PAS depuis un TickComponent a
|
||||
* lui : l'ordre de tick entre un acteur et ses composants n'est pas garanti sans
|
||||
* dependance explicite, et le resultat serait un decalage lu une frame apres
|
||||
* avoir ete calcule -- invisible a 120 fps, franchement mou a 30.
|
||||
*/
|
||||
void UpdateBob(float DeltaTime);
|
||||
|
||||
/** Decalage a ajouter a la position RELATIVE de la camera (X avant, Y droite, Z haut), en cm. */
|
||||
UFUNCTION(BlueprintPure, Category = "Head Bob")
|
||||
FVector GetLocationOffset() const { return LocationOffset; }
|
||||
|
||||
/** Decalage a ajouter a la rotation de la camera, en degres. */
|
||||
UFUNCTION(BlueprintPure, Category = "Head Bob")
|
||||
FRotator GetRotationOffset() const { return RotationOffset; }
|
||||
|
||||
/**
|
||||
* Remet le balancement au repos sans transition.
|
||||
* Pour une teleportation ou une prise de controle : on ne veut pas que la tete
|
||||
* finisse le pas d'avant a l'autre bout de la carte.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Head Bob")
|
||||
void ResetBob();
|
||||
|
||||
/**
|
||||
* Facteur global pousse par les reglages joueur (curseur "secousses de camera").
|
||||
* A 0 la tete ne bouge plus du tout : c'est un confort d'accessibilite, pas une
|
||||
* option cosmetique, et il doit valoir pour le balancement comme pour les chocs.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "Head Bob")
|
||||
void SetIntensityScale(float NewScale);
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Reglages generaux
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/** Coupe entierement l'effet, sans avoir a remettre les cinq profils a zero. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob")
|
||||
bool bEnableHeadBob = true;
|
||||
|
||||
/**
|
||||
* Multiplicateur d'amplitude commun aux cinq profils.
|
||||
* C'est le curseur a bouger pour un reglage d'ensemble ("un peu moins de tout")
|
||||
* sans avoir a retoucher vingt valeurs une par une.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob", meta = (ClampMin = "0", UIMax = "3"))
|
||||
float GlobalIntensity = 1.f;
|
||||
|
||||
/**
|
||||
* Vitesse de fondu d'un profil vers un autre (facteur d'interpolation
|
||||
* exponentielle, par seconde). Plus haut = le sprint prend son amplitude plus
|
||||
* vite. Trop haut, le changement d'etat redevient une cassure.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob", meta = (ClampMin = "0.1", UIMax = "20"))
|
||||
float ProfileBlendSpeed = 6.f;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Seuils de choix d'etat
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* En dessous de cette vitesse horizontale (cm/s), on est considere immobile.
|
||||
* Le seuil se lit sur la vitesse REELLE et non sur la touche enfoncee : marcher
|
||||
* dans un mur laisse l'input actif alors que le corps ne bouge plus, et sans ce
|
||||
* detail la tete continuerait de gigoter face a la cloison.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob|Seuils", meta = (ClampMin = "0"))
|
||||
float IdleSpeedThreshold = 10.f;
|
||||
|
||||
/**
|
||||
* Au-dessus de cette vitesse horizontale (cm/s), on bascule sur le profil de
|
||||
* sprint. A regler entre WalkSpeed et SprintSpeed du pawn -- 400 et 650 par
|
||||
* defaut, d'ou ces 520 : assez haut pour que la phase d'acceleration ne compte
|
||||
* pas comme du sprint, assez bas pour que le sprint reel soit toujours detecte.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob|Seuils", meta = (ClampMin = "0"))
|
||||
float SprintSpeedThreshold = 520.f;
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Profils, un par etat. Valeurs par defaut dans le constructeur.
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/** Immobile : une respiration lente, quasi purement verticale. C'est ce qui evite la statue. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob|Profils")
|
||||
FHeadBobProfile IdleProfile;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob|Profils")
|
||||
FHeadBobProfile WalkProfile;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob|Profils")
|
||||
FHeadBobProfile SprintProfile;
|
||||
|
||||
/** Accroupi : plus lent et plus discret que la marche, le corps est ramasse. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob|Profils")
|
||||
FHeadBobProfile CrouchProfile;
|
||||
|
||||
/**
|
||||
* En l'air : tout a zero, y compris la frequence -- la phase se fige donc en vol
|
||||
* et repart d'ou elle en etait a la reception, ce qui evite que le premier pas
|
||||
* apres un saut tombe sur un pied arbitraire. Le profil reste editable malgre
|
||||
* tout, au cas ou l'on veuille un flottement pendant la chute.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Head Bob|Profils")
|
||||
FHeadBobProfile AirProfile;
|
||||
|
||||
private:
|
||||
/** Choisit le profil vise a partir de l'etat reel du CharacterMovement. */
|
||||
const FHeadBobProfile& SelectTargetProfile() const;
|
||||
|
||||
/** Rapproche BlendedProfile de Target, champ par champ. */
|
||||
void BlendTowards(const FHeadBobProfile& Target, float Step);
|
||||
|
||||
/**
|
||||
* Position dans le cycle de foulee, en radians, ramenee dans [0, 2*PI[.
|
||||
* Le repli n'est pas cosmetique : sans lui la valeur grossit indefiniment et la
|
||||
* precision du float se degrade, jusqu'a un balancement qui devient saccade au
|
||||
* bout d'une longue partie.
|
||||
*/
|
||||
float StridePhase = 0.f;
|
||||
|
||||
/** Profil courant, resultat du fondu entre les profils d'etat. */
|
||||
FHeadBobProfile BlendedProfile;
|
||||
|
||||
FVector LocationOffset = FVector::ZeroVector;
|
||||
|
||||
FRotator RotationOffset = FRotator::ZeroRotator;
|
||||
|
||||
/** Pousse par les reglages joueur, se multiplie a GlobalIntensity. */
|
||||
float IntensityScale = 1.f;
|
||||
|
||||
/** Caches : ces deux pointeurs sont lus a chaque frame, pas question d'y caster. */
|
||||
TObjectPtr<ACharacter> OwnerCharacter;
|
||||
|
||||
TObjectPtr<UCharacterMovementComponent> OwnerMovement;
|
||||
};
|
||||
Reference in New Issue
Block a user