Skip to content
Learni
View all tutorials
Unreal Engine

Comment créer un Character Controller en Unreal Engine 2026

Introduction

En 2026, Unreal Engine domine le développement de jeux AAA grâce à sa maturité en rendu Nanite/Lumen et son support C++ ultra-performant. Créer un Character Controller personnalisé en C++ est essentiel pour dépasser les limites des Blueprints en termes de performance et de contrôle fin. Contrairement aux templates basiques qui manquent de flexibilité, ce tutoriel vous guide pour implémenter un système complet : mouvement omnidirectionnel (WASD), saut avec gravité réaliste, et caméra follow avec SpringArm pour immersion.

Pourquoi ce choix ? Les Blueprints sont idéaux pour prototyping rapide, mais pour des jeux à 60+ FPS avec IA complexes ou multijoueur, le C++ réduit la latence CPU de 30-50%. Nous partons d'un projet vide pour un contrôle total, en générant les fichiers VS via command line – méthode pro utilisée en studio. À la fin, vous aurez un pawn jouable compilable en 5 minutes, prêt pour extensions comme animation Montage ou réplication réseau. Ce guide progresse des fondations (structure projet) aux features avancées (input binding), avec analogies comme un 'châssis de voiture' pour les composants physiques.

Prérequis

  • Unreal Engine 5.4+ (ou 6.0 en 2026) installé via Epic Games Launcher.
  • Visual Studio 2022 Community+ avec workloads 'Jeux C++' et 'Unreal Engine Installer' (inclut MSVC, Windows SDK).
  • 10 Go d'espace disque libre pour le projet.
  • Connaissances basiques en C++ (classes, pointeurs) et UE concepts (Actors, Components).

Étape 1 : Initialiser la structure du projet

Créez manuellement la hiérarchie de dossiers pour un contrôle absolu, comme un squelette prêt à recevoir les muscles C++. Cela évite les templates GUI pollués et permet des customs dès le départ. Ouvrez un terminal (PowerShell ou Git Bash) dans votre workspace dev.

Créer les dossiers et fichiers de base

terminal-init.sh
mkdir CharacterControllerProject
cd CharacterControllerProject
mkdir Source
mkdir Source/CharacterControllerProject
mkdir Config
mkdir Content
mkdir Plugins
echo 'Projet UE initialisé'

Ce script crée la structure standard UE : Source pour C++, Config pour .ini, Content pour assets. Lancez-le dans un dossier parent ; il prépare le terrain sans générer de code boilerplate inutile. Piège : oublier Source/CharacterControllerProject mène à des erreurs de module introuvable lors du build.

Étape 2 : Définir le fichier projet principal

Le fichier .uproject est le manifeste JSON qui lie votre code au moteur. Il déclare le module principal et active les plugins par défaut, comme un contrat entre votre code et UE.

Créer CharacterControllerProject.uproject

CharacterControllerProject.uproject
{
  "FileVersion": 3,
  "EngineAssociation": "5.4",
  "Category": "",
  "Description": "Projet Character Controller C++",
  "Modules": [
    {
      "Name": "CharacterControllerProject",
      "Type": "Runtime",
      "LoadingPhase": "Default"
    }
  ],
  "Plugins": [
    {
      "Name": "EnhancedInput",
      "Enabled": true
    }
  ]
}

Ce JSON associe le moteur 5.4+ et active EnhancedInput pour bindings modernes (supérieur aux legacy inputs). Copiez-collez dans le root. Version 3 est stable en 2026 ; ne touchez pas FileVersion sans raison pour éviter corruptions.

Étape 3 : Générer les fichiers Visual Studio

Utilisez le batch UE pour transformer votre squelette en SLN compilable. Analogie : comme compiler un Makefile en IDE full-featured.

Générer le projet VS

terminal-generate.bat
REM Remplacez par votre chemin UE
set UE_PATH="C:/Program Files/Epic Games/UE_5.4/Engine/Build/BatchFiles"
call %UE_PATH%/GenerateProjectFiles.bat -project="CharacterControllerProject.uproject" -game -makefileafter

REM Ouvrir VS (optionnel)
start CharacterControllerProject.sln

-game cible un executable standalone, -makefileafter pour Ninja builds rapides. Adaptez UE_PATH à votre install (vérifiez Epic Launcher). Piège majeur : VS sans workload UE échoue au link ; réinstallez si 'cl.exe not found'.

Étape 4 : Configurer les dépendances de build

Build.cs définit les libs UE nécessaires, comme un pom.xml pour C++. Ajoutez InputCore et EnhancedInput pour notre controller.

Source/CharacterControllerProject/CharacterControllerProject.Build.cs

Source/CharacterControllerProject/CharacterControllerProject.Build.cs
using UnrealBuildTool;

public class CharacterControllerProject : ModuleRules
{
    public CharacterControllerProject(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { 
            "Core", 
            "CoreUObject", 
            "Engine",
            "InputCore",
            "EnhancedInput",
            "HeadMountedDisplay",
            "AIModule"
        });

        PrivateDependencyModuleNames.AddRange(new string[] { });
    }
}

PublicDependency pour headers exposés, ajoute EnhancedInput pour actions modernes. AIModule optionnel pour futures IA. Erreur commune : oublier 'Engine' cause crashes au spawn ; rebuild full après edits.

Étape 5 : Implémenter l'header du Character

Définissez la classe comme extension de ACharacter : composants UPROPERTY pour Capsule (collision), SpringArm (caméra smooth), Camera (vue FPS). Bindings pour inputs.

Source/CharacterControllerProject/MyCharacter.h

Source/CharacterControllerProject/MyCharacter.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputActionValue.h"
#include "MyCharacter.generated.h"

UCLASS()
class CHARACTERCONTROLLERPROJECT_API AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    AMyCharacter();

protected:
    virtual void BeginPlay() override;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class USpringArmComponent* SpringArm;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class UCameraComponent* Camera;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
    class UInputMappingContext* DefaultMappingContext;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
    class UInputAction* MoveAction;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
    class UInputAction* LookAction;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input)
    class UInputAction* JumpAction;

public:
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
    
private:
    void Move(const FInputActionValue& Value);
    void Look(const FInputActionValue& Value);
};

Hérite ACharacter pour physique intégrée (gravité, collision). SpringArm évite clipping mur, Camera pour render. Inputs Enhanced pour multi-device (gamepad/clavier). GENERATED_BODY() auto-génère boilerplate UE.

Étape 6 : Implémenter la logique en CPP

Constructor attache composants, SetupPlayerInput bind actions à fonctions. Move/Look utilisent GetCharacterMovement()->AddInputVector pour direction world-space.

Source/CharacterControllerProject/MyCharacter.cpp

Source/CharacterControllerProject/MyCharacter.cpp
#include "MyCharacter.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "InputMappingContext.h"
#include "InputAction.h"

AMyCharacter::AMyCharacter()
{
    PrimaryActorTick.bCanEverTick = true;

    GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);

    SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    SpringArm->SetupAttachment(RootComponent);
    SpringArm->TargetArmLength = 300.0f;
    SpringArm->bUsePawnControlRotation = true;

    Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
    Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);

    GetCharacterMovement()->JumpZVelocity = 700.f;
    GetCharacterMovement()->AirControl = 0.35f;
    GetCharacterMovement()->MaxWalkSpeed = 500.f;
    GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
    GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;
}

void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
    {
        if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
        {
            Subsystem->AddMappingContext(DefaultMappingContext, 0);
        }
    }
}

void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
    {
        EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::Move);
        EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AMyCharacter::Look);
        EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ACharacter::Jump);
        EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
    }
}

void AMyCharacter::Move(const FInputActionValue& Value)
{
    FVector2D MovementVector = Value.Get<FVector2D>();

    if (Controller != nullptr)
    {
        AddMovementInput(GetActorForwardVector(), MovementVector.Y);
        AddMovementInput(GetActorRightVector(), MovementVector.X);
    }
}

void AMyCharacter::Look(const FInputActionValue& Value)
{
    FVector2D LookAxisVector = Value.Get<FVector2D>();

    if (Controller != nullptr)
    {
        AddControllerYawInput(LookAxisVector.X);
        AddControllerPitchInput(LookAxisVector.Y);
    }
}

Constructor scale Capsule (hauteur 96cm réaliste), tune MovementComponent pour vitesse 500u/s. BeginPlay ajoute MappingContext au subsystem. Move combine forward/right pour strafe fluide ; Look yaw/pitch caméra. Jump legacy pour compatibilité.

Étape 7 : Compiler et configurer les assets d'input

Compilez en VS (Development Editor), ouvrez Editor via .uproject. Créez Input Mapping Context et Actions dans Content/Input (EnhancedInput assets), assignez à MyCharacter BP subclass.

Compiler le projet

terminal-compile.bat
REM Depuis root projet
call Engine/Build/BatchFiles/Build.bat CharacterControllerProjectEditor Win64 Development -project="CharacterControllerProject.uproject" -WaitMutex

REM Ou via VS: Development Editor > Build Solution (F7)
start CharacterControllerProject.uproject

Batch build pour CI/CD friendly ; -WaitMutex évite locks parallèles. Temps ~2min première fois (PCH gen). Erreur : 'module not found' → vérifiez Build.cs et regén SLN.

Étape 8 : Configurer les inputs Enhanced

Dans Editor > Project Settings > Input > Add Mapping Context (DefaultMappingContext). Créez Actions: Move (2D Axis), Look (2D Axis), Jump (Digital). Scale 1.0-2.0.

Exemple Config/DefaultInput.ini (pour mappings avancés)

Config/DefaultInput.ini
[/Script/Engine.InputSettings]
NativeInputVisualization=Hidden

[+AxisMappings=(ActionName="MoveForward",Key=UpArrow,bAlt=false,Scale=1.0)]
[+AxisMappings=(ActionName="MoveForward",Key=W,bAlt=false,Scale=1.0)]
[+AxisMappings=(ActionName="MoveRight",Key=RightArrow,bAlt=false,Scale=1.0)]
[+AxisMappings=(ActionName="MoveRight",Key=D,bAlt=false,Scale=1.0)]

[+AxisMappings=(ActionName="Turn",Key=MouseX,bAlt=false,Scale=1.0)]
[+AxisMappings=(ActionName="LookUp",Key=MouseY,bAlt=false,Scale=-1.0)]

[+ActionMappings=(ActionName="Jump",Key=SpaceBar,bAlt=false,Shift=false,Control=false,Cmd=false)]

bUseNewInputStack=True

.ini backup pour versionning Git ; mappings legacy compat mais utilisez Enhanced en prioritaire. Scale=-1 pour invert mouse Y. Rechargez Editor après edits.

Test et intégration

Créez Blueprint subclass de MyCharacter (set comme Default Pawn dans World Settings). Play In Editor : WASD move, souris look, Espace jump. Vitesse air 0.35 pour contrôle précis.

Bonnes pratiques

  • Toujours utiliser EnhancedInput : scalable à gamepad/VR, legacy obsolète en 2026.
  • Tune MovementComponent tôt : MaxWalkSpeed=600 pour run, GroundFriction=8 pour adhérence réaliste.
  • UPROPERTY meta=(AllowPrivateAccess) pour accès Blueprint sans public getters verbeux.
  • Versionnez .uproject/Build.cs dans Git ; ignorez Binaries/Intermediate.
  • Profile CPU avec Stat Game pour optimiser Tick (désactivez si >16ms).

Erreurs courantes à éviter

  • 'Subsystem null' crash : Vérifiez Cast en BeginPlay ; testez non-local.
  • No movement : Oubli AddMappingContext ou bUsePawnControlRotation=false sur SpringArm.
  • Compile loop infinie : Supprimez DerivedDataCache avant rebuild.
  • Jump stuck : Bind Completed event pour StopJumping, pas que Triggered.

Pour aller plus loin

  • Intégrez Animation Blueprint avec State Machine pour idle/walk/jump.
  • Ajoutez réplication pour multijoueur : UPROPERTY(Replicated) sur vitesse.
  • Explorez Chaos Physics pour ragdoll.
Découvrez nos formations Unreal Engine avancées pour C++ networking et Niagara VFX. Docs officielles : UE Enhanced Input