Cette page présente certains concepts de programmation avancés de l'Unreal Engine. Dans les explications ci-dessous, nous supposons que vous connaissez le C# de Unity et que vous souhaitez apprendre à utiliser le C++ de l'Unreal Engine. Cela dit, dans la plupart des cas, vous pouvez également utiliser Blueprint et obtenir les mêmes résultats. C'est la raison pour laquelle nous avons ajouté des exemples relatifs aux langages de programmation C++ et Blueprint chaque fois que nous l'avons pu.
Arrêtons-nous sur les modèles de programmation de jeu les plus fréquemment utilisés et sur la manière de les aborder dans l'Unreal Engine. Dans les exemples ci-dessous, nous vous décrivons certaines fonctions courantes de Unity et vous expliquons comment mettre en œuvre la même fonctionnalité dans l'Unreal Engine.
Instancier un GameObject/générer des acteurs
Dans Unity, vous utilisez la fonction Instantiate
pour créer de nouvelles instances d'objets. Cette fonction prend n'importe quel type d'objet UnityEngine.Object
(GameObject, MonoBehaviour, etc.) et en fait une copie.
public GameObject EnemyPrefab;
public Vector3 SpawnPosition;
public Quaternion SpawnRotation;
void Start()
{
GameObject NewGO = (GameObject)Instantiate(EnemyPrefab, SpawnPosition, SpawnRotation);
NewGO.name = "MyNewGameObject";
}
L'Unreal Engine propose deux fonctions pour instancier des objets :
NewObject
crée de nouveaux typesUObject
.SpawnActor
génère les typesAActor
.
UObjects et NewObject
Le processus de création de sous-classes UObject
dans l'Unreal Engine est similaire au processus de création de sous-classes ScriptableObject
dans Unity. Ces sous-classes sont utiles pour les classes de gameplay qui n'ont pas besoin d'apparaître dans le monde ou d'être rattachées à des composants, comme c'est le cas des acteurs.
Dans Unity, si vous créez votre propre sous-classe de ScriptableObject
, vous devez l'instancier comme suit :
MyScriptableObject NewSO = ScriptableObject.CreateInstance<MyScriptableObject>();
Dans l'Unreal Engine, si vous créez votre propre type dérivé UObject
, vous pouvez l'instancier de la façon suivante :
UMyObject* NewObj = NewObject<UMyObject>();
AActors et SpawnActor
Les acteurs sont générés en utilisant la méthode SpawnActor
sur un objet World (UWorld
en langage C++). Certains UObjects vous offrent une méthode GetWorld
(à l'instar de tous les acteurs). Cette méthode vous permet d'obtenir un objet World.
Notez qu'au lieu de faire passer un autre acteur, l'exemple ci-dessous fait passer la classe de l'acteur qui doit apparaître. Dans notre exemple, la classe peut être n'importe quelle sous-classe de AMyEnemy.
Comment effectuer la copie d'un autre objet (à la manière d'Instantiate dans Unity) ?
Les fonctions NewObject
et SpawnActor
peuvent également disposer d'un objet modèle avec lequel travailler. L'Unreal Engine effectue une copie de cet objet au lieu de créer un nouvel objet en partant de zéro. Cette opération permet de copier l'ensemble des UPROPERTY et des composants.
AMyActor* CreateCloneOfMyActor(AMyActor* ExistingActor, FVector SpawnLocation, FRotator SpawnRotation)
{
UWorld* World = ExistingActor->GetWorld();
FActorSpawnParameters SpawnParams;
SpawnParams.Template = ExistingActor;
World->SpawnActor<AMyActor>(ExistingActor->GetClass(), SpawnLocation, SpawnRotation, SpawnParams);
}
Vous vous demandez sans doute ce que signifie l'expression en partant de zéro dans ce contexte. Chaque classe d'objet que vous créez possède un modèle par défaut qui définit les valeurs par défaut de ses propriétés et de ses composants. Si vous ne remplacez pas ces propriétés et ne fournissez pas votre propre modèle, l'Unreal Engine utilise ces valeurs par défaut pour créer votre objet. Pour illustrer cette procédure, arrêtons-nous d'abord sur MonoBehaviour :
public class MyComponent : MonoBehaviour
{
public int MyIntProp = 42;
public SphereCollider MyCollisionComp = null;
void Start()
{
// Créer le composant de collision s'il n'en existe pas déjà un
if (MyCollisionComp == null)
{
MyCollisionComp = gameObject.AddComponent<SphereCollider>();
MyCollisionComp.center = Vector3.zero;
MyCollisionComp.radius = 20.0f;
}
}
}
Dans l'exemple ci-dessus, la valeur par défaut de la propriété int
est définie sur 42 et celle du rayon du composant SphereCollider
sur 20.
Le constructeur d'objets permet d'obtenir le même résultat dans l'Unreal Engine :
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
UPROPERTY()
int32 MyIntProp;
UPROPERTY()
USphereComponent* MyCollisionComp;
AMyActor()
{
MyIntProp = 42;
MyCollisionComp = CreateDefaultSubobject<USphereComponent>(FName(TEXT("CollisionComponent"));
MyCollisionComp->RelativeLocation = FVector::ZeroVector;
MyCollisionComp->SphereRadius = 20.0f;
}
};
Nous définissons les valeurs de propriété par défaut sur la classe dans le constructeur de AMyActor
. Notez l'utilisation de la fonction CreateDefaultSubobject
. Nous pouvons utiliser cette fonction pour créer des composants et leur attribuer des propriétés par défaut. Tous les sous-objets créés avec cette fonction font office de modèle par défaut, de sorte que nous pouvons les modifier dans une sous-classe ou dans Blueprint.
Convertir un type en un autre
Dans cet exemple, nous obtenons un composant connu, puis nous le projetons vers un type spécifique et effectuons une action conditionnelle.
Unity C#
Collider collider = gameObject.GetComponent<Collider>;
SphereCollider sphereCollider = collider as SphereCollider;
if (sphereCollider != null)
{
// ...
}
Unreal Engine C++
UPrimitiveComponent* Primitive = MyActor->GetComponentByClass(UPrimitiveComponent::StaticClass());
USphereComponent* SphereCollider = Cast<USphereComponent>(Primitive);
if (SphereCollider != nullptr)
{
// ...
}
Détruire le GameObject/l'acteur
Unity
|
C++
|
Blueprint ![]() |
Détruire le GameObject/l'acteur (avec un délai d'une seconde)
Unity
|
C++
|
Blueprint ![]() |
Désactiver les GameObjects/acteurs
Unity
|
C++
|
Blueprint ![]() |
Accéder au GameObject/à l'acteur à partir d'un composant
Unity
|
C++
|
Blueprint ![]() |
Accéder à un composant à partir du GameObject/de l'acteur
Unity C#
MyComponent MyComp = gameObject.GetComponent<MyComponent>();
Unreal Engine C++
UMyComponent* MyComp = MyActor->FindComponentByClass<UMyComponent>();
Blueprint

Rechercher des GameObjects/acteurs
Unity C#
// Cherche le nom d'un GameObject.
GameObject MyGO = GameObject.Find("MyNamedGameObject");
// Rechercher des objets par type
MyComponent[] Components = Object.FindObjectsOfType(typeof(MyComponent)) as MyComponent[];
foreach (MyComponent Component in Components)
{
// ...
}
// Rechercher des GameObjects par balise
GameObject[] GameObjects = GameObject.FindGameObjectsWithTag("MyTag");
foreach (GameObject GO in GameObjects)
{
// ...
}
Unreal Engine C++
// Rechercher un acteur par nom (fonctionne également sur les UObjects)
AActor* MyActor = FindObject<AActor>(nullptr, TEXT("MyNamedActor"));
// Rechercher des acteurs par type (objet UWorld nécessaire)
for (TActorIterator<AMyActor> It(GetWorld()); It; ++It)
{
AMyActor* MyActor = *It;
// ...
}
Blueprint

Unreal Engine C++
// Rechercher des UObjects par type
for (TObjectIterator<UMyObject> It; It; ++it)
{
UMyObject* MyObject = *It;
// ...
}
// Rechercher des acteurs par balise (fonctionne également sur les ActorComponents, utiliser plutôt TObjectIterator)
for (TActorIterator<AActor> It(GetWorld()); It; ++It)
{
AActor* Actor = *It;
if (Actor->ActorHasTag(FName(TEXT("Mytag"))))
{
// ...
}
}
Blueprint

Ajouter des balises aux GameObjects/acteurs
Unity C#
MyGameObject.tag = "MyTag";
Unreal Engine C++
// Les acteurs peuvent disposer de plusieurs balises
MyActor.Tags.AddUnique(TEXT("MyTag"));
Blueprint

Ajouter des balises aux MonoBehaviours/ActorComponents
Unity C#
// Cela modifie la balise sur le GameObject auquel elle est rattachée
MyComponent.tag = "MyTag";
Unreal Engine C++
// Les composants possèdent leur propre matrice de balises
MyComponent.ComponentTags.AddUnique(TEXT("MyTag"));
Comparer les balises sur les GameObjects/acteurs et sur les MonoBehaviours/ActorComponents
Unity C#
if (MyGameObject.CompareTag("MyTag"))
{
// ...
}
// Vérifie la balise sur le GameObject auquel elle est rattachée
if (MyComponent.CompareTag("MyTag"))
{
// ...
}
Unreal Engine C++
// Vérifie si un acteur possède cette balise
if (MyActor->ActorHasTag(FName(TEXT("MyTag"))))
{
// ...
}
Blueprint

Unreal Engine C++
// Vérifie si un ActorComponent possède cette balise
if (MyComponent->ComponentHasTag(FName(TEXT("MyTag"))))
{
// ...
}
Blueprint

Physique : Corps rigide et composant de primitive
Dans Unity, pour donner à un GameObject des caractéristiques physiques, vous deviez au préalable lui attribuer un composant Rigidbody.
Dans l'Unreal Engine, tout composant de primitive (UPrimitiveComponent
dans C++) peut être un objet physique. Parmi les composants de primitive les plus courants figurent :
- les composants de forme (capsule, sphère et boîte)
- les composants de maillage statique
- les composants de maillage squelettique
Contrairement à Unity, qui sépare les responsabilités de collision et les visualisations en composants distincts, l'Unreal Engine combine les concepts de "potentiellement physique" et "potentiellement visible" dans un composant de primitive unique. Tout composant ayant une géométrie dans le monde (dont le rendu est possible ou avec lequel il est possible d'interagir physiquement) est une sous-classe de PrimitiveComponent
.
Couches et canaux
Les canaux de collision dans l'Unreal Engine sont l'équivalent des couches dans Unity. Pour en savoir plus, consultez l'article Collision Filtering (Filtrage des collisions).
Ray-casting et ray-tracing
Unity C#
GameObject FindGOCameraIsLookingAt()
{
Vector3 Start = Camera.main.transform.position;
Vector3 Direction = Camera.main.transform.forward;
float Distance = 100.0f;
int LayerBitMask = 1 << LayerMask.NameToLayer("Pawn");
RaycastHit Hit;
bool bHit = Physics.Raycast(Start, Direction, out Hit, Distance, LayerBitMask);
if (bHit)
{
return Hit.collider.gameObject;
}
return null;
}
Unreal Engine C++
APawn* AMyPlayerController::FindPawnCameraIsLookingAt()
{
// Utilisez ceci pour personnaliser diverses propriétés du tracé
FCollisionQueryParams Params;
// Ignorer le pion du joueur
Params.AddIgnoredActor(GetPawn());
// Le résultat de l'impact dépend du tracé de ligne
FHitResult Hit;
// Projection de rayons à partir de la caméra, n'entrant en collision qu'avec les pions (qui se trouvent sur le canal de collision ECC_Pawn)
FVector Start = PlayerCameraManager->GetCameraLocation();
FVector End = Start + (PlayerCameraManager->GetCameraRotation().Vector() * 1000.0f);
bool bHit = GetWorld()->LineTraceSingle(Hit, Start, End, ECC_Pawn, Params);
if (bHit)
{
// Hit.Actor contient un pointeur faible vers l'acteur que le tracé a touché
return Cast<APawn>(Hit.Actor.Get());
}
return nullptr;
}
Blueprint
Cliquez sur l'image pour l'afficher à taille réelle.
Volumes de déclenchement
Unity C#
public class MyComponent : MonoBehaviour
{
void Start()
{
collider.isTrigger = true;
}
void OnTriggerEnter(Collider Other)
{
// ...
}
void OnTriggerExit(Collider Other)
{
// ...
}
}
Unreal Engine C++
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
// Mon composant de déclenchement
UPROPERTY()
UPrimitiveComponent* Trigger;
AMyActor()
{
Trigger = CreateDefaultSubobject<USphereComponent>(TEXT("TriggerCollider"));
// Cette fonction doit être activée (True) sur les deux collisionneurs pour que les événements se déclenchent
Trigger.bGenerateOverlapEvents = true;
// Définir le mode de collision du collisionneur
// Ce mode n'active le collisionneur que pour les projections de rayons (ray-casting), les balayages et les chevauchements
Trigger.SetCollisionEnabled(ECollisionEnabled::QueryOnly);
}
virtual void NotifyActorBeginOverlap(AActor* Other) override;
virtual void NotifyActorEndOverlap(AActor* Other) override;
};
Blueprint Unreal Engine

Pour en savoir plus sur la configuration des réponses aux collisions, consultez la page Collision.
Corps rigides cinématiques
Unity C#
public class MyComponent : MonoBehaviour
{
void Start()
{
rigidbody.isKinematic = true;
rigidbody.velocity = transform.forward * 10.0f;
}
}
Dans l'Unreal Engine, le composant de collision et le composant de corps rigide ne font qu'un. La classe de base correspondante est UPrimitiveComponent
. Elle possède de nombreuses sous-classes (USphereComponent
, UCapsuleComponent
, etc.) pour répondre à vos besoins.
Unreal Engine C++
UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
UPROPERTY()
UPrimitiveComponent* PhysicalComp;
AMyActor()
{
PhysicalComp = CreateDefaultSubobject<USphereComponent>(TEXT("CollisionAndPhysics"));
PhysicalComp->SetSimulatePhysics(false);
PhysicalComp->SetPhysicsLinearVelocity(GetActorRotation().Vector() * 100.0f);
}
};
Événements de commande
Unity C#
public class MyPlayerController : MonoBehaviour
{
void Update()
{
if (Input.GetButtonDown("Fire"))
{
// ...
}
float Horiz = Input.GetAxis("Horizontal");
float Vert = Input.GetAxis("Vertical");
// ...
}
}
Unreal Engine C++ :
UCLASS()
class AMyPlayerController : public APlayerController
{
GENERATED_BODY()
void SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAction("Fire", IE_Pressed, this, &AMyPlayerController::HandleFireInputEvent);
InputComponent->BindAxis("Horizontal", this, &AMyPlayerController::HandleHorizontalAxisInputEvent);
InputComponent->BindAxis("Vertical", this, &AMyPlayerController::HandleVerticalAxisInputEvent);
}
void HandleFireInputEvent();
void HandleHorizontalAxisInputEvent(float Value);
void HandleVerticalAxisInputEvent(float Value);
};
Blueprint

Voici un exemple de propriétés de commandes dans les paramètres d'un projet :

Pour en savoir plus sur la configuration des commandes de votre projet Unreal Engine, consultez la page Input.