// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "CharacterAppearanceTypes.h" #include "CharacterPreviewActor.generated.h" class UCameraComponent; class UCharacterAppearanceComponent; class USkeletalMeshComponent; /** * Les deux cadrages de l'ecran de customisation. * * Deux et pas un par categorie : ce qu'on veut, c'est voir le visage quand on * choisit une barbe et la silhouette entiere quand on choisit un corps. Un * cadrage par categorie donnerait onze reglages a poser a la main pour onze * fois le meme resultat. */ UENUM(BlueprintType) enum class ECharacterPreviewFraming : uint8 { FullBody, Face, Count UMETA(Hidden) }; /** * Le mannequin de l'ecran de customisation : un personnage pose dans la map de * menu, qu'on fait tourner a la souris et que la camera cadre selon ce que le * joueur est en train de regler. * * Il porte le MEME UCharacterAppearanceComponent que le pawn de jeu, et c'est * tout l'interet : le personnage qu'on regarde ici est monte par exactement le * code qui montera celui que les autres joueurs verront. Deux chemins de * montage finiraient par diverger, et le joueur s'en apercevrait au pire * moment -- une fois en partie. */ UCLASS() class EMBERWILD_API ACharacterPreviewActor : public AActor { GENERATED_BODY() public: ACharacterPreviewActor(); virtual void Tick(float DeltaSeconds) override; /** Monte l'apparence sur le mannequin. */ UFUNCTION(BlueprintCallable, Category = "Preview") void ApplyAppearance(const FCharacterAppearance& InAppearance); /** La camera glisse vers le cadrage demande. Sans effet s'il y est deja. */ UFUNCTION(BlueprintCallable, Category = "Preview") void SetFraming(ECharacterPreviewFraming NewFraming); /** Fait pivoter le personnage. Appelee pendant un clic-glisser. */ UFUNCTION(BlueprintCallable, Category = "Preview") void AddPreviewYaw(float DeltaDegrees); /** Remet le personnage face a la camera. */ UFUNCTION(BlueprintCallable, Category = "Preview") void ResetPreviewYaw(); UFUNCTION(BlueprintPure, Category = "Preview") UCameraComponent* GetPreviewCamera() const { return PreviewCamera; } UFUNCTION(BlueprintPure, Category = "Preview") UCharacterAppearanceComponent* GetAppearanceComponent() const { return AppearanceComponent; } /** Le reglage vit ici et pas sur le widget : c'est une sensibilite de camera. */ UFUNCTION(BlueprintPure, Category = "Preview") float GetYawPerPixel() const { return YawPerPixel; } protected: virtual void BeginPlay() override; /** Le porteur d'animation et de pose ; les pieces s'y accrochent. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Preview") TObjectPtr BodyMesh; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Preview") TObjectPtr AppearanceComponent; /** * Pivot de rotation, entre la racine et le mesh. * * Le personnage tourne en faisant pivoter CE composant et jamais l'acteur : * la camera est fille de l'acteur, la faire tourner avec lui donnerait un * decor qui defile pendant qu'on regarde un personnage immobile. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Preview") TObjectPtr TurntablePivot; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Preview") TObjectPtr PreviewCamera; /** * Les deux positions de camera, a placer A LA SOURIS dans le viewport du * Blueprint plutot qu'a taper en coordonnees. * * Ce sont des reperes vides : la camera n'y est pas accrochee, elle glisse * vers eux. Sans quoi changer de categorie la ferait sauter d'un cadrage a * l'autre, ce qui se lit comme une coupure de montage. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Preview|Framing") TObjectPtr FullBodyViewSpot; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Preview|Framing") TObjectPtr FaceViewSpot; /** * Vitesse de glissement de la camera entre deux cadrages. * * Une vitesse d'interpolation et pas une duree : le mouvement freine en * arrivant au lieu de s'arreter net, et deux changements de categorie * coup sur coup s'enchainent sans a-coup -- la camera repart d'ou elle est. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Preview|Framing", meta = (ClampMin = "0.5")) float FramingInterpSpeed = 6.f; /** Degres de rotation par pixel de deplacement horizontal de la souris. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Preview|Turntable") float YawPerPixel = 0.35f; private: /** Le repere vise par la camera, selon le cadrage courant. */ USceneComponent* GetSpotForFraming(ECharacterPreviewFraming InFraming) const; /** * Coupe le Tick quand la camera est arrivee. * * Meme principe que le couvercle d'AStorageContainer : cet acteur ne tick * que pendant qu'il bouge. Un mannequin immobile dans un menu n'a aucune * raison de couter une frame. */ void UpdateFramingInterpolation(float DeltaSeconds); ECharacterPreviewFraming CurrentFraming = ECharacterPreviewFraming::FullBody; /** Rotation accumulee par le clic-glisser, en degres. */ float TurntableYaw = 0.f; };