(Feat) Add Animation
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "FpsPlayer.h"
|
||||
|
||||
#include "Animation/AnimInstance.h"
|
||||
#include "Animation/AnimMontage.h"
|
||||
#include "Camera/CameraComponent.h"
|
||||
#include "Camera/CameraTypes.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
@@ -14,11 +16,13 @@
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "InputActionValue.h"
|
||||
#include "CraftingComponent.h"
|
||||
#include "HeadBobComponent.h"
|
||||
#include "InteractionComponent.h"
|
||||
#include "InventoryComponent.h"
|
||||
#include "ItemDataAsset.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "PickupItem.h"
|
||||
#include "SurvivalGameInstance.h"
|
||||
#include "SurvivalStatsComponent.h"
|
||||
#include "SurvivalUserSettings.h"
|
||||
|
||||
@@ -74,6 +78,31 @@ AFpsPlayer::AFpsPlayer()
|
||||
// ecraserait la rotation chaque frame et tous les effets de tilt seraient invisibles.
|
||||
FirstPersonCamera->bUsePawnControlRotation = false;
|
||||
|
||||
// Bras vue premiere personne, accroches a la camera pour suivre le regard.
|
||||
FirstPersonArms = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonArms"));
|
||||
FirstPersonArms->SetupAttachment(FirstPersonCamera);
|
||||
// Symetrique exact du mesh 3e personne ci-dessous : chacun ne voit que ses
|
||||
// propres bras. Sans ca, les bras d'un ami flotteraient devant notre objectif.
|
||||
FirstPersonArms->SetOnlyOwnerSee(true);
|
||||
// Un mesh colle a l'objectif projetterait une ombre enorme en travers du
|
||||
// decor. L'ombre du joueur, elle, vient du mesh 3e personne.
|
||||
FirstPersonArms->SetCastShadow(false);
|
||||
FirstPersonArms->bCastDynamicShadow = false;
|
||||
// Les bras ne sont pas dans le monde, ils sont devant l'objectif : une
|
||||
// collision les ferait pousser des objets et surtout bloquer le trace
|
||||
// d'interaction, qui part exactement d'entre eux.
|
||||
FirstPersonArms->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
// Chez l'hote, le pawn de chaque ami porte AUSSI ce composant, invisible pour
|
||||
// tout le monde. Sans cette option le serveur evaluerait quatre AnimBlueprints
|
||||
// pour quatre meshes que personne ne rend.
|
||||
FirstPersonArms->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
|
||||
// Point de depart a affiner dans BP_FpsPlayer : la bonne valeur depend de
|
||||
// l'origine du FBX (racine aux pieds ? au bassin ?) et de l'orientation
|
||||
// d'export. Le yaw de -90 est le decalage habituel d'un FBX Blender/Maya.
|
||||
FirstPersonArms->SetRelativeLocationAndRotation(FVector(0.f, 0.f, -160.f), FRotator(0.f, -90.f, 0.f));
|
||||
|
||||
HeadBob = CreateDefaultSubobject<UHeadBobComponent>(TEXT("HeadBob"));
|
||||
|
||||
InteractionComponent = CreateDefaultSubobject<UInteractionComponent>(TEXT("InteractionComponent"));
|
||||
InventoryComponent = CreateDefaultSubobject<UInventoryComponent>(TEXT("InventoryComponent"));
|
||||
CraftingComponent = CreateDefaultSubobject<UCraftingComponent>(TEXT("CraftingComponent"));
|
||||
@@ -131,10 +160,18 @@ void AFpsPlayer::BeginPlay()
|
||||
{
|
||||
if (DefaultMappingContext)
|
||||
{
|
||||
// On ACTIVE le contexte ici, mais on ne le DECLARE pas comme
|
||||
// remappable : c'est USurvivalGameInstance qui s'en charge, parce
|
||||
// que le menu principal n'a pas de pawn et doit quand meme
|
||||
// afficher les touches.
|
||||
// La DECLARATION des contextes remappables appartient au
|
||||
// GameInstance -- le menu principal n'a pas de pawn et doit
|
||||
// pourtant afficher les touches. On la demande quand meme ici, et
|
||||
// AVANT d'activer le contexte : c'est elle qui traduit les touches
|
||||
// vers la disposition clavier du joueur, et un AZERTY doit trouver
|
||||
// ses touches des la premiere image, pas au premier passage dans
|
||||
// l'ecran de reglages. L'appel est idempotent.
|
||||
if (USurvivalGameInstance* GameInstance = GetGameInstance<USurvivalGameInstance>())
|
||||
{
|
||||
GameInstance->RegisterMappableContexts();
|
||||
}
|
||||
|
||||
Subsystem->AddMappingContext(DefaultMappingContext, 0);
|
||||
}
|
||||
else
|
||||
@@ -176,6 +213,10 @@ void AFpsPlayer::ApplyUserSettings()
|
||||
bSprintToggleMode = Settings->GetSprintToggle();
|
||||
bCrouchToggleMode = Settings->GetCrouchToggle();
|
||||
|
||||
// Le curseur "secousses de camera" vaut aussi pour le balancement : un joueur
|
||||
// qui le met a zero demande une camera fixe, pas une camera fixe qui respire.
|
||||
HeadBob->SetIntensityScale(CameraShakeMultiplier);
|
||||
|
||||
// Repasser en maintien alors que la touche n'est plus enfoncee laisserait le
|
||||
// personnage bloque en sprint : on repart d'un etat propre.
|
||||
if (!bSprintToggleMode && bIsSprinting)
|
||||
@@ -228,7 +269,15 @@ void AFpsPlayer::UpdateCameraEffects(float DeltaTime)
|
||||
CrouchTiltSpring.Update(Step, CrouchTiltFrequency, CrouchTiltDamping, CrouchTiltRampTime, 1.5f);
|
||||
|
||||
// ==================================================================
|
||||
// 3. FOV de sprint
|
||||
// 3. Balancement de tete
|
||||
// ==================================================================
|
||||
// Integre ici et applique dans ApplyCameraTransform, exactement comme les
|
||||
// ressorts ci-dessus : c'est ce qui permet a CalcCamera de recomposer la
|
||||
// transform sans faire avancer le temps deux fois.
|
||||
HeadBob->UpdateBob(Step);
|
||||
|
||||
// ==================================================================
|
||||
// 4. FOV de sprint
|
||||
// ==================================================================
|
||||
// On exige un vrai deplacement : sinon le FOV s'ouvrirait juste en
|
||||
// maintenant Shift a l'arret, ce qui donne un effet de pompage bizarre.
|
||||
@@ -257,7 +306,18 @@ void AFpsPlayer::ApplyCameraTransform()
|
||||
// demi-hauteur courante de la capsule, ce saut est annule exactement --
|
||||
// a condition de lire les deux au meme instant, d'ou l'appel depuis CalcCamera.
|
||||
const float CapsuleHalfHeight = GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
|
||||
FirstPersonCamera->SetRelativeLocation(FVector(0.f, 0.f, EyeHeightAboveFeet - CapsuleHalfHeight + PunchSpring.Offset));
|
||||
|
||||
// Le balancement s'AJOUTE au reste. Son Y est un decalage lateral dans le
|
||||
// repere de la capsule, dont le yaw suit deja le regard (bUseControllerRotationYaw) :
|
||||
// la tete se porte donc bien a droite de ce qu'on regarde, sans conversion.
|
||||
// Le tangage, lui, n'est pas dans la capsule -- c'est voulu, le balancement
|
||||
// reste horizontal meme quand on regarde ses pieds.
|
||||
const FVector BobOffset = HeadBob->GetLocationOffset();
|
||||
|
||||
FirstPersonCamera->SetRelativeLocation(FVector(
|
||||
BobOffset.X,
|
||||
BobOffset.Y,
|
||||
EyeHeightAboveFeet - CapsuleHalfHeight + PunchSpring.Offset + BobOffset.Z));
|
||||
|
||||
// ==================================================================
|
||||
// Rotation
|
||||
@@ -274,6 +334,9 @@ void AFpsPlayer::ApplyCameraTransform()
|
||||
// regarde vers le bas. C'est ce qui vend l'impact a l'atterrissage.
|
||||
ViewOffset.Pitch += PunchSpring.Offset * PunchPitchPerCm;
|
||||
|
||||
// Roulis et tangage du balancement, dans le meme sac que le reste.
|
||||
ViewOffset += HeadBob->GetRotationOffset();
|
||||
|
||||
if (const AController* OwningController = GetController())
|
||||
{
|
||||
FirstPersonCamera->SetWorldRotation(OwningController->GetControlRotation() + ViewOffset);
|
||||
@@ -812,9 +875,35 @@ void AFpsPlayer::StopCrouch()
|
||||
|
||||
void AFpsPlayer::Interact()
|
||||
{
|
||||
// Le geste part AVANT la RPC, pas apres sa reponse : un montage declenche a
|
||||
// l'aller-retour serveur donnerait des bras qui repondent 60 ms apres le clic,
|
||||
// et le joueur lirait ca comme un jeu qui rame. Le prix a payer est un geste
|
||||
// dans le vide si le serveur refuse l'interaction -- infiniment moins genant.
|
||||
//
|
||||
// Le test de type est ici et pas dans le composant d'interaction : celui-ci ne
|
||||
// connait que l'interface IInteractable et n'a pas a apprendre ce qu'est un
|
||||
// pickup. Un coffre ou un etabli n'ont pas a declencher un geste de ramassage.
|
||||
if (Cast<APickupItem>(InteractionComponent->GetFocusedActor()))
|
||||
{
|
||||
PlayArmsMontage(GrabMontage);
|
||||
}
|
||||
|
||||
InteractionComponent->TryInteract();
|
||||
}
|
||||
|
||||
float AFpsPlayer::PlayArmsMontage(UAnimMontage* Montage, float PlayRate)
|
||||
{
|
||||
// IsLocallyControlled : chez l'hote, le pawn de chaque ami passerait aussi par
|
||||
// ici a chaque ramassage et animerait un mesh que personne ne rend.
|
||||
if (!Montage || !IsLocallyControlled())
|
||||
{
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
UAnimInstance* ArmsAnim = FirstPersonArms->GetAnimInstance();
|
||||
return ArmsAnim ? ArmsAnim->Montage_Play(Montage, PlayRate) : 0.f;
|
||||
}
|
||||
|
||||
void AFpsPlayer::OnStartCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust)
|
||||
{
|
||||
Super::OnStartCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust);
|
||||
|
||||
Reference in New Issue
Block a user