(Feat) Add Animation Fps Charater

This commit is contained in:
2026-08-13 22:07:08 +02:00
parent 176beab9fc
commit cca54a5e0d
157 changed files with 850 additions and 148 deletions
@@ -0,0 +1,194 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "CharacterAppearanceTypes.h"
#include "CharacterPartsDataAsset.generated.h"
class UAnimInstance;
class UMaterialInterface;
class USkeletalMesh;
class UTexture2D;
/**
* Tout ce qui compose une silhouette : ses meshes de corps, son AnimBP, et les
* pieces disponibles pour chaque categorie.
*/
USTRUCT(BlueprintType)
struct FCharacterBodySet
{
GENERATED_BODY()
/** La vignette du bouton de silhouette, meme role que celle d'une piece. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Body")
TObjectPtr<UTexture2D> Icon;
/**
* Les morceaux du corps, dans l'ordre. Le PREMIER est le porteur : c'est lui
* qui va sur le composant Mesh du Character et qui joue l'animation, les
* suivants deviennent des composants enfants en leader pose.
*
* Une LISTE alors qu'il n'y a qu'une case aujourd'hui, et ce n'est pas de la
* sur-conception : le pack livre exprès `SKM_BodyA_torso`, `_arms`,
* `_legs_01/02/03`, `_hands`, `_feet`, precisement pour qu'une armure puisse
* eteindre les segments qu'elle recouvre. Le jour venu, la case 0 deviendra
* `SKM_BodyA_empty` -- invisible, porteur d'animation -- et les huit segments
* suivront derriere, SANS que ce code change. Un TObjectPtr unique, lui,
* imposerait de tout reprendre au premier plastron.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Body")
TArray<TObjectPtr<USkeletalMesh>> BodyMeshes;
/** L'AnimBP du porteur. Il change avec la silhouette, d'ou sa place ici. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Body")
TSubclassOf<UAnimInstance> AnimClass;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
TArray<FCharacterPartEntry> Heads;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
TArray<FCharacterPartEntry> Hairstyles;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
TArray<FCharacterPartEntry> Eyebrows;
/** Vide pour une silhouette qui n'en porte pas -- le pack n'en donne qu'a A. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
TArray<FCharacterPartEntry> Beards;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
TArray<FCharacterPartEntry> Mustaches;
/**
* Fragment cherche dans le NOM des slots de materiau du mesh de tete pour y
* trouver celui des yeux.
*
* Les yeux ne sont pas un mesh : le pack les livre comme un element du mesh
* de tete. Il ne suffit donc pas de poser un parametre de couleur, il faut
* REMPLACER le materiau de ce slot -- encore faut-il savoir lequel.
*
* Un fragment de nom et pas un index, parce qu'un index est faux deux fois :
* il oblige a le verifier a la main dans l'editeur, et il suppose surtout
* que les six tetes rangent leurs slots dans le MEME ordre. Les slots du
* pack s'appellent `M_Eye_A_01`, `M_Eye`, `M_Eyes_02`... tous contiennent
* « Eye », aucun slot de peau ne le contient.
*
* Si le fragment ne trouve rien, le materiau n'est PAS pose et un
* avertissement part dans le log. C'est volontaire : poser l'oeil sur un
* slot au hasard repeindrait le visage entier, un symptome qu'on met bien
* plus longtemps a diagnostiquer qu'une ligne de log.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
FName EyeMaterialSlotHint = TEXT("Eye");
};
/**
* Le catalogue : la table de correspondance entre les index d'une
* FCharacterAppearance et les assets reels.
*
* Un seul asset a remplir, et le SEUL endroit a toucher pour ajouter une
* coiffure. C'est aussi lui qui borne ce qu'un client peut demander : une
* apparence arrivee du reseau est passee a Sanitize(), qui ramene tout index
* hors bornes a une valeur sure.
*/
UCLASS(BlueprintType)
class EMBERWILD_API UCharacterPartsDataAsset : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
/**
* Une entree par valeur d'ECharacterBodyType, dans l'ordre de l'enum.
* L'ordre EST le contrat : c'est lui qui donne son sens a BodyType.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog")
TArray<FCharacterBodySet> BodySets;
// ------------------------------------------------------------------
// Palettes : une couleur = un bouton a l'ecran, sans reglage entre les
// deux. L'ordre EST l'ordre d'affichage, et l'index qui part sur le reseau.
//
// Partagees par les deux silhouettes : deux nuanciers de peau a tenir a
// jour divergeraient au premier ajout.
// ------------------------------------------------------------------
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
TArray<FLinearColor> SkinColors;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
TArray<FLinearColor> HairColors;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
TArray<FLinearColor> EyeColors;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
TArray<FLinearColor> UnderwearColors;
/** Les materiaux d'iris, un par forme d'oeil proposee. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
TArray<TObjectPtr<UMaterialInterface>> EyeMaterials;
// ------------------------------------------------------------------
// Noms des parametres des materiaux du pack.
//
// Ici et pas en dur dans le C++ : ils appartiennent aux assets, pas au
// code. Changer de pack de personnages ne doit demander qu'un nouveau
// catalogue -- et ces noms contiennent des ESPACES, ce qu'on n'invente
// pas de memoire.
// ------------------------------------------------------------------
/** `M_Body_Base`. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
FName SkinColorParameter = TEXT("Skin color");
/**
* `M_Head_Base` -- le meme role que ci-dessus, mais l'autre master, et
* surtout un NOM DIFFERENT : `Skin` cote tete, `Skin color` cote corps.
*
* Le master contient bien la chaine « Skin Base color », mais ce n'est pas
* le nom du parametre expose -- verifie dans `MI_HeadA_01_a`, ou le chercher
* ne rend aucun resultat alors que `Skin` apparait dans le groupe
* « Base colors ». Morale : un nom de parametre se lit dans l'editeur du
* Material Instance, jamais dans les chaines du binaire du master.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
FName HeadSkinColorParameter = TEXT("Skin");
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
FName UnderwearColorParameter = TEXT("Underware color");
/** `M_Hairstyle_Base`, parent des cheveux, barbes, moustaches ET sourcils. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
FName HairColorParameter = TEXT("Color");
/** `M_Eyes_Base`. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
FName EyeColorParameter = TEXT("Eye color");
// ------------------------------------------------------------------
// Lecture
// ------------------------------------------------------------------
/** Le jeu de pieces d'une silhouette, ou nullptr si l'index est hors bornes. */
const FCharacterBodySet* GetBodySet(ECharacterBodyType BodyType) const;
/** La liste d'une categorie pour une silhouette, vide si rien n'est defini. */
const TArray<FCharacterPartEntry>& GetParts(ECharacterBodyType BodyType, ECharacterPartCategory Category) const;
/** Nombre d'options d'une categorie. Sert a borner l'UI comme la console. */
UFUNCTION(BlueprintPure, Category = "Catalog")
int32 GetPartCount(ECharacterBodyType BodyType, ECharacterPartCategory Category) const;
/**
* Ramene une apparence dans les bornes du catalogue.
*
* Appelee sur le SERVEUR a la reception d'une apparence client, et au
* chargement des reglages -- un catalogue ampute entre deux versions du jeu
* laisserait sinon des index qui ne designent plus rien. Les pieces
* facultatives (barbe, moustache) retombent sur NoPart, les obligatoires
* sur 0 : mieux vaut la mauvaise tete que pas de tete.
*/
void Sanitize(FCharacterAppearance& InOut) const;
};