Bu bölümde, proje için yeni bir PlayerController sınıfı tanımlayacağız.
1. Unreal Engine Editor'da, ana menüden "Tools - New C++ Class" seçeneği ile açılan "Add C++ Class" penceresinde "Player Controller" seçeneği seçili iken, "Next" butonuna tıklayalım.
2. Açılan pencerede "Name" satırına "MyGamePlayerController" değerini girdikten sonra "Create Class" butonuna tıklayarak PlayerController sınıfını oluşturalım.
3. Dosyaların içerikleri aşağıdaki şekilde olacaktır:
// MyGamePlayerController.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MyGamePlayerController.generated.h"
/**
*
*/
UCLASS()
class MYGAME_API AMyGamePlayerController : public APlayerController
{
GENERATED_BODY()
};
// MyGamePlayerController.cpp
#include "MyGamePlayerController.h"
4. Kodlar derlendikten sonra "C++ Classes/MyGame" dizini altında "MyGamePlayerController" adlı bir dosya otomatik olarak oluşturulacaktır.
PlayerController sınıfı kod dosyalarının içeriğini aşağıdaki şekilde düzenleyelim:
// MyGamePlayerController.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "InputAction.h" // UInputAction için
#include "InputMappingContext.h" // UInputMappingContext için
#include "MyGamePlayerController.generated.h"
// Artık forward declaration'a ihtiyacımız yok çünkü header'ları include ettik
/**
* MyGame projesi için özel PlayerController sınıfı
* Girdi işleme, UI yönetimi ve oyuncu kontrol mantığını yönetir
*/
UCLASS()
class MYGAME_API AMyGamePlayerController : public APlayerController
{
GENERATED_BODY()
public:
// Constructor
AMyGamePlayerController();
protected:
//////////////////////////////////////////////////////////////////////////
// Temel Yaşam Döngüsü Fonksiyonları
/**
* Oyuncu controller'ı başlatıldığında çağrılır
*/
virtual void BeginPlay() override;
/**
* Her frame'de çağrılır
* @param DeltaTime - Geçen süre
*/
virtual void Tick(float DeltaTime) override;
/**
* Oyuncu pawn'ını kontrol etmeye başladığında çağrılır
* @param InPawn - Kontrol edilecek pawn
*/
virtual void OnPossess(APawn* InPawn) override;
/**
* Oyuncu pawn'ını kontrol etmeyi bıraktığında çağrılır
* @param InPawn - Kontrolü bırakılan pawn
*/
virtual void OnUnPossess() override;
//////////////////////////////////////////////////////////////////////////
// Girdi (Input) Sistemi
/**
* Enhanced Input sistemini kur
*/
virtual void SetupInputComponent() override;
/**
* Input mapping context'leri ekle
*/
void SetupInputMapping();
/**
* Input action'ları bağla
*/
void BindInputActions();
/**
* Mouse cursor ayarlarını yap
*/
void SetMouseCursorSettings();
public:
//////////////////////////////////////////////////////////////////////////
// Girdi İşleme Fonksiyonları
/**
* Hareket girdisini işle
* @param InputActionValue - Girdi değeri
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Input")
void HandleMoveInput(const FInputActionValue& InputActionValue);
/**
* Bakış girdisini işle
* @param InputActionValue - Girdi değeri
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Input")
void HandleLookInput(const FInputActionValue& InputActionValue);
/**
* Zıplama girdisini işle
* @param InputActionValue - Girdi değeri
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Input")
void HandleJumpInput(const FInputActionValue& InputActionValue);
/**
* Koşma girdisini işle
* @param InputActionValue - Girdi değeri
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Input")
void HandleSprintInput(const FInputActionValue& InputActionValue);
/**
* Etkileşim girdisini işle
* @param InputActionValue - Girdi değeri
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Input")
void HandleInteractInput(const FInputActionValue& InputActionValue);
/**
* Pause/Menü girdisini işle
* @param InputActionValue - Girdi değeri
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Input")
void HandlePauseInput(const FInputActionValue& InputActionValue);
//////////////////////////////////////////////////////////////////////////
// UI Yönetimi Fonksiyonları
/**
* HUD'u oluştur ve göster
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|UI")
void CreateHUD();
/**
* HUD'u kaldır
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|UI")
void RemoveHUD();
/**
* Pause menüsünü göster/gizle
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|UI")
void TogglePauseMenu();
/**
* Skor UI'ını güncelle
* @param NewScore - Yeni skor değeri
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|UI")
void UpdateScoreUI(float NewScore);
/**
* Sağlık UI'ını güncelle
* @param HealthPercentage - Sağlık yüzdesi (0-1)
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|UI")
void UpdateHealthUI(float HealthPercentage);
/**
* Mesaj UI'ını göster
* @param Message - Gösterilecek mesaj
* @param DisplayTime - Görüntülenme süresi (saniye)
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|UI")
void ShowMessage(const FString& Message, float DisplayTime = 3.0f);
//////////////////////////////////////////////////////////////////////////
// Oyun Mantığı Fonksiyonları
/**
* Oyuncu öldüğünde çağrılır
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Gameplay")
void OnPlayerDied();
/**
* Oyuncu respawn olduğunda çağrılır
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Gameplay")
void OnPlayerRespawned();
/**
* Oyuncu skorunu artır
* @param ScoreAmount - Eklenecek skor miktarı
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Gameplay")
void AddScore(float ScoreAmount);
/**
* Oyuncu hasar aldığında çağrılır
* @param DamageAmount - Hasar miktarı
* @param DamageCauser - Hasarı veren aktör
*/
UFUNCTION(BlueprintCallable, Category = "MyGame|Gameplay")
void OnPlayerDamaged(float DamageAmount, AActor* DamageCauser);
//////////////////////////////////////////////////////////////////////////
// Ağ (Multiplayer) Fonksiyonları
/**
* Sunucuda skor güncelle (RPC)
* @param ScoreAmount - Eklenecek skor
*/
UFUNCTION(Server, Reliable, WithValidation, Category = "MyGame|Network")
void Server_AddScore(float ScoreAmount);
/**
* Client'ta UI güncelle (RPC)
* @param NewScore - Yeni skor
*/
UFUNCTION(Client, Reliable, Category = "MyGame|Network")
void Client_UpdateScore(float NewScore);
/**
* Tüm client'lara mesaj gönder (Multicast RPC)
* @param Message - Gönderilecek mesaj
*/
UFUNCTION(NetMulticast, Reliable, Category = "MyGame|Network")
void Multicast_ShowMessage(const FString& Message);
//////////////////////////////////////////////////////////////////////////
// Blueprint Implementable Events
/**
* HUD oluşturulduğunda çağrılır (Blueprint'te implemente edilecek)
*/
UFUNCTION(BlueprintImplementableEvent, Category = "MyGame|Events")
void OnHUDCreated();
/**
* Pause menüsü değiştiğinde çağrılır (Blueprint'te implemente edilecek)
* @param bIsPausedParam - Oyun durduruldu mu?
*/
UFUNCTION(BlueprintImplementableEvent, Category = "MyGame|Events")
void OnPauseChanged(bool bIsPausedParam);
/**
* Skor güncellendiğinde çağrılır (Blueprint'te implemente edilecek)
* @param NewScore - Yeni skor
*/
UFUNCTION(BlueprintImplementableEvent, Category = "MyGame|Events")
void OnScoreUpdated(float NewScore);
/**
* Sağlık güncellendiğinde çağrılır (Blueprint'te implemente edilecek)
* @param HealthPercentage - Sağlık yüzdesi (0-1)
*/
UFUNCTION(BlueprintImplementableEvent, Category = "MyGame|Events")
void OnHealthUpdated(float HealthPercentage);
//////////////////////////////////////////////////////////////////////////
// Blueprint Ayarlanabilir Özellikler
/**
* Varsayılan Input Mapping Context
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|Input")
TSoftObjectPtr<UInputMappingContext> DefaultInputMappingContext;
/**
* Hareket Input Action
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|Input")
TSoftObjectPtr<UInputAction> MoveInputAction;
/**
* Bakış Input Action
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|Input")
TSoftObjectPtr<UInputAction> LookInputAction;
/**
* Zıplama Input Action
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|Input")
TSoftObjectPtr<UInputAction> JumpInputAction;
/**
* Koşma Input Action
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|Input")
TSoftObjectPtr<UInputAction> SprintInputAction;
/**
* Etkileşim Input Action
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|Input")
TSoftObjectPtr<UInputAction> InteractInputAction;
/**
* Pause Input Action
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|Input")
TSoftObjectPtr<UInputAction> PauseInputAction;
/**
* HUD widget sınıfı
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|UI")
TSubclassOf<class UUserWidget> HUDWidgetClass;
/**
* Pause menü widget sınıfı
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MyGame|UI")
TSubclassOf<class UUserWidget> PauseMenuWidgetClass;
/**
* Mouse hassasiyeti
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyGame|Input", meta = (ClampMin = "0.1", ClampMax = "10.0"))
float MouseSensitivity = 1.0f;
/**
* Gamepad hassasiyeti
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyGame|Input", meta = (ClampMin = "0.1", ClampMax = "10.0"))
float GamepadSensitivity = 1.0f;
/**
* Fareyi UI üzerinde kilitle
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyGame|Input")
bool bLockMouseCursor = false;
/**
* Oyun şu anda durdurulmuş mu?
*/
UPROPERTY(BlueprintReadOnly, Category = "MyGame|State")
bool bIsGamePaused = false;
protected:
//////////////////////////////////////////////////////////////////////////
// İç Değişkenler
/**
* Aktif HUD widget
*/
UPROPERTY()
class UUserWidget* CurrentHUDWidget = nullptr;
/**
* Aktif pause menü widget
*/
UPROPERTY()
class UUserWidget* CurrentPauseMenuWidget = nullptr;
/**
* Enhanced input local player subsystem
*/
UPROPERTY()
class UEnhancedInputLocalPlayerSubsystem* InputSubsystem = nullptr;
/**
* Mevcut skor
*/
float CurrentScore = 0.0f;
/**
* Mevcut sağlık yüzdesi
*/
float CurrentHealthPercentage = 1.0f;
/**
* Oyun durduruldu mu?
*/
bool bIsPaused = false;
};
// MyGamePlayerController.cpp
#include "MyGamePlayerController.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Blueprint/UserWidget.h"
#include "Engine/LocalPlayer.h"
#include "Kismet/GameplayStatics.h"
#include "MyGameGameMode.h"
// Log kategorisi tanımlama
DEFINE_LOG_CATEGORY_STATIC(LogMyGamePlayerController, Log, All);
AMyGamePlayerController::AMyGamePlayerController()
{
// Mouse ve input ayarları
bShowMouseCursor = false;
bEnableClickEvents = false;
bEnableTouchEvents = false;
bEnableMouseOverEvents = false;
// Asset path'leri yorum satırı yapıldı
// Bunları Unreal Editor'de asset'leri oluşturduktan sonra aktifleştirin
DefaultInputMappingContext = TSoftObjectPtr<UInputMappingContext>(
FSoftObjectPath(TEXT("/Game/_Game/Input/IMC_Default.IMC_Default"))
);
MoveInputAction = TSoftObjectPtr<UInputAction>(
FSoftObjectPath(TEXT("/Game/_Game/Input/Actions/IA_Move.IA_Move"))
);
LookInputAction = TSoftObjectPtr<UInputAction>(
FSoftObjectPath(TEXT("/Game/_Game/Input/Actions/IA_Look.IA_Look"))
);
JumpInputAction = TSoftObjectPtr<UInputAction>(
FSoftObjectPath(TEXT("/Game/_Game/Input/Actions/IA_Jump.IA_Jump"))
);
SprintInputAction = TSoftObjectPtr<UInputAction>(
FSoftObjectPath(TEXT("/Game/_Game/Input/Actions/IA_Sprint.IA_Sprint"))
);
InteractInputAction = TSoftObjectPtr<UInputAction>(
FSoftObjectPath(TEXT("/Game/_Game/Input/Actions/IA_Interact.IA_Interact"))
);
PauseInputAction = TSoftObjectPtr<UInputAction>(
FSoftObjectPath(TEXT("/Game/_Game/Input/Actions/IA_Pause.IA_Pause"))
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("MyGamePlayerController initialized"));
}
void AMyGamePlayerController::BeginPlay()
{
Super::BeginPlay();
UE_LOG(LogMyGamePlayerController, Log, TEXT("PlayerController BeginPlay"));
// Enhanced Input subsystem'ini al
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
InputSubsystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>();
if (InputSubsystem)
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Enhanced Input subsystem found"));
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("Enhanced Input subsystem NOT found"));
}
}
// HUD'u oluştur
CreateHUD();
// Mouse cursor ayarı
SetMouseCursorSettings();
// Input mapping context'ini ekle (BeginPlay'den sonra)
// Eğer pawn zaten sahipsek, input'u ayarla
if (GetPawn())
{
SetupInputMapping();
}
}
void AMyGamePlayerController::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Debug için: Input sisteminin durumunu kontrol et
static bool bHasLoggedInputStatus = false;
if (!bHasLoggedInputStatus && GetWorld()->GetTimeSeconds() > 2.0f)
{
FString InputStatus = FString::Printf(TEXT(
"Input Status: Subsystem=%s, Pawn=%s, IMC=%s, MoveAction=%s"
),
InputSubsystem ? TEXT("Valid") : TEXT("Null"),
GetPawn() ? *GetPawn()->GetName() : TEXT("Null"),
DefaultInputMappingContext.IsNull() ? TEXT("Null") : TEXT("Set"),
MoveInputAction.IsNull() ? TEXT("Null") : TEXT("Set")
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("%s"), *InputStatus);
ShowMessage(InputStatus, 5.0f);
bHasLoggedInputStatus = true;
}
}
void AMyGamePlayerController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
UE_LOG(LogMyGamePlayerController, Log, TEXT("PlayerController possessing pawn: %s"),
*GetNameSafe(InPawn));
// Eğer bir karaktere sahipsek, bazı ayarları yap
if (ACharacter* ControlledCharacter = Cast<ACharacter>(InPawn))
{
// Character'in input yönünü controller'a göre ayarla
ControlledCharacter->bUseControllerRotationYaw = false;
ControlledCharacter->bUseControllerRotationPitch = false;
ControlledCharacter->bUseControllerRotationRoll = false;
if (UCharacterMovementComponent* MovementComp = ControlledCharacter->GetCharacterMovement())
{
MovementComp->bOrientRotationToMovement = true;
MovementComp->RotationRate = FRotator(0.0f, 540.0f, 0.0f);
}
}
}
void AMyGamePlayerController::OnUnPossess()
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("PlayerController unpossessing pawn"));
// Input mapping context'ini kaldır
if (InputSubsystem)
{
// Null check yapmadan önce asset'in yüklü olup olmadığını kontrol et
if (DefaultInputMappingContext.IsNull())
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("DefaultInputMappingContext is null"));
}
else if (UInputMappingContext* IMC = DefaultInputMappingContext.LoadSynchronous())
{
InputSubsystem->RemoveMappingContext(IMC);
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load DefaultInputMappingContext"));
}
}
Super::OnUnPossess();
}
void AMyGamePlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
UE_LOG(LogMyGamePlayerController, Log, TEXT("Setting up input component"));
// Enhanced Input Component oluştur
UEnhancedInputComponent* EnhancedInputComp = Cast<UEnhancedInputComponent>(InputComponent);
if (EnhancedInputComp)
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Enhanced Input Component found"));
// Input subsystem'i al
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
InputSubsystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>();
if (InputSubsystem)
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Enhanced Input subsystem found in SetupInputComponent"));
// Input mapping context'ini ekle
SetupInputMapping();
// Input action'ları bağla
BindInputActions();
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Enhanced Input subsystem NOT found"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("LocalPlayer is null"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("Enhanced Input Component NOT found"));
}
}
void AMyGamePlayerController::SetupInputMapping()
{
// InputSubsystem null mu kontrol et
if (!InputSubsystem)
{
// Henüz başlatılmamışsa, başlatmaya çalış
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
InputSubsystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>();
if (InputSubsystem)
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("InputSubsystem initialized in SetupInputMapping"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to initialize InputSubsystem"));
return;
}
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("LocalPlayer is null"));
return;
}
}
// Default input mapping context'i yükle ve ekle
if (DefaultInputMappingContext.IsNull())
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("DefaultInputMappingContext is not set"));
return;
}
if (UInputMappingContext* IMC = DefaultInputMappingContext.LoadSynchronous())
{
// Önce aynı context'i kaldır (tekrar eklememek için)
InputSubsystem->RemoveMappingContext(IMC);
// Sonra yeni olarak ekle
InputSubsystem->AddMappingContext(IMC, 0);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Default Input Mapping Context added"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load Default Input Mapping Context"));
}
}
void AMyGamePlayerController::BindInputActions()
{
UEnhancedInputComponent* EnhancedInputComp = Cast<UEnhancedInputComponent>(InputComponent);
if (!EnhancedInputComp)
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("EnhancedInputComponent is null"));
return;
}
// Move input binding
if (!MoveInputAction.IsNull())
{
if (UInputAction* MoveAction = MoveInputAction.LoadSynchronous())
{
EnhancedInputComp->BindAction(
MoveAction,
ETriggerEvent::Triggered,
this,
&AMyGamePlayerController::HandleMoveInput
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Move input action bound"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load MoveInputAction"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("MoveInputAction is not set"));
}
// Look input binding
if (!LookInputAction.IsNull())
{
if (UInputAction* LookAction = LookInputAction.LoadSynchronous())
{
EnhancedInputComp->BindAction(
LookAction,
ETriggerEvent::Triggered,
this,
&AMyGamePlayerController::HandleLookInput
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Look input action bound"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load LookInputAction"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("LookInputAction is not set"));
}
// Jump input binding
if (!JumpInputAction.IsNull())
{
if (UInputAction* JumpAction = JumpInputAction.LoadSynchronous())
{
EnhancedInputComp->BindAction(
JumpAction,
ETriggerEvent::Started,
this,
&AMyGamePlayerController::HandleJumpInput
);
EnhancedInputComp->BindAction(
JumpAction,
ETriggerEvent::Completed,
this,
&AMyGamePlayerController::HandleJumpInput
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Jump input action bound"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load JumpInputAction"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("JumpInputAction is not set"));
}
// Sprint input binding
if (!SprintInputAction.IsNull())
{
if (UInputAction* SprintAction = SprintInputAction.LoadSynchronous())
{
EnhancedInputComp->BindAction(
SprintAction,
ETriggerEvent::Triggered,
this,
&AMyGamePlayerController::HandleSprintInput
);
EnhancedInputComp->BindAction(
SprintAction,
ETriggerEvent::Canceled,
this,
&AMyGamePlayerController::HandleSprintInput
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Sprint input action bound"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load SprintInputAction"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("SprintInputAction is not set"));
}
// Interact input binding
if (!InteractInputAction.IsNull())
{
if (UInputAction* InteractAction = InteractInputAction.LoadSynchronous())
{
EnhancedInputComp->BindAction(
InteractAction,
ETriggerEvent::Started,
this,
&AMyGamePlayerController::HandleInteractInput
);
EnhancedInputComp->BindAction(
InteractAction,
ETriggerEvent::Completed,
this,
&AMyGamePlayerController::HandleInteractInput
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Interact input action bound"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load InteractInputAction"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("InteractInputAction is not set"));
}
// Pause input binding
if (!PauseInputAction.IsNull())
{
if (UInputAction* PauseAction = PauseInputAction.LoadSynchronous())
{
EnhancedInputComp->BindAction(
PauseAction,
ETriggerEvent::Started,
this,
&AMyGamePlayerController::HandlePauseInput
);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Pause input action bound"));
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to load PauseInputAction"));
}
}
else
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("PauseInputAction is not set"));
}
}
void AMyGamePlayerController::HandleMoveInput(const FInputActionValue& InputActionValue)
{
if (!GetPawn() || bIsPaused)
return;
FVector2D MovementVector = InputActionValue.Get<FVector2D>();
// X ekseni: Sağ/Sol (Yaw)
// Y ekseni: İleri/Geri (Pitch)
if (MovementVector.SizeSquared() > 0.0f)
{
// Controller'ın rotasyonuna göre hareket vektörünü dönüştür
const FRotator Rotation = GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// İleri vektör
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
// Sağ vektör
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// Son hareket vektörü
FVector FinalMovement = (ForwardDirection * MovementVector.Y) + (RightDirection * MovementVector.X);
FinalMovement.Normalize();
// Pawn'a hareket emri ver
GetPawn()->AddMovementInput(FinalMovement, 1.0f);
UE_LOG(LogMyGamePlayerController, Verbose, TEXT("Move Input: X=%.2f, Y=%.2f"),
MovementVector.X, MovementVector.Y);
}
}
void AMyGamePlayerController::HandleLookInput(const FInputActionValue& InputActionValue)
{
if (bIsPaused)
return;
FVector2D LookAxisVector = InputActionValue.Get<FVector2D>();
// Mouse/Gamepad hassasiyeti ile çarp
LookAxisVector.X *= MouseSensitivity;
LookAxisVector.Y *= MouseSensitivity;
// Yatay bakış (sağ/sol)
if (LookAxisVector.X != 0.0f)
{
AddYawInput(LookAxisVector.X);
}
// Dikey bakış (yukarı/aşağı)
if (LookAxisVector.Y != 0.0f)
{
AddPitchInput(LookAxisVector.Y);
}
UE_LOG(LogMyGamePlayerController, Verbose, TEXT("Look Input: X=%.2f, Y=%.2f"),
LookAxisVector.X, LookAxisVector.Y);
}
void AMyGamePlayerController::HandleJumpInput(const FInputActionValue& InputActionValue)
{
if (!GetPawn() || bIsPaused)
return;
bool bIsPressed = InputActionValue.Get<bool>();
if (ACharacter* ControlledCharacter = Cast<ACharacter>(GetPawn())) // Değişken adını ControlledCharacter yaptık
{
if (bIsPressed)
{
ControlledCharacter->Jump();
UE_LOG(LogMyGamePlayerController, Log, TEXT("Jump started"));
}
else
{
ControlledCharacter->StopJumping();
UE_LOG(LogMyGamePlayerController, Log, TEXT("Jump stopped"));
}
}
}
void AMyGamePlayerController::HandleSprintInput(const FInputActionValue& InputActionValue)
{
if (!GetPawn() || bIsPaused)
return;
bool bIsSprinting = InputActionValue.Get<bool>();
if (ACharacter* ControlledCharacter = Cast<ACharacter>(GetPawn()))
{
if (UCharacterMovementComponent* MovementComp = ControlledCharacter->GetCharacterMovement())
{
if (bIsSprinting)
{
// Sprint hızını ayarla (normal hızın 1.5 katı)
MovementComp->MaxWalkSpeed = 600.0f; // Varsayılan 400-500'dür
UE_LOG(LogMyGamePlayerController, Log, TEXT("Sprinting started"));
}
else
{
// Normal hıza dön
MovementComp->MaxWalkSpeed = 450.0f; // Varsayılan yürüme hızı
UE_LOG(LogMyGamePlayerController, Log, TEXT("Sprinting stopped"));
}
}
}
}
void AMyGamePlayerController::HandleInteractInput(const FInputActionValue& InputActionValue)
{
if (!GetPawn() || bIsPaused)
return;
bool bIsPressed = InputActionValue.Get<bool>();
if (bIsPressed)
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Interact input pressed"));
// Raycast ile etkileşim
FVector StartLocation;
FRotator StartRotation;
GetPlayerViewPoint(StartLocation, StartRotation);
FVector EndLocation = StartLocation + (StartRotation.Vector() * 500.0f); // 5 metre ileri
FHitResult HitResult;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(GetPawn());
bool bHit = GetWorld()->LineTraceSingleByChannel(
HitResult,
StartLocation,
EndLocation,
ECC_Visibility,
CollisionParams
);
if (bHit && HitResult.GetActor())
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Interacted with: %s"),
*HitResult.GetActor()->GetName());
// Burada etkileşim mantığınızı ekleyin
// Örneğin: kapı açma, item toplama, düğmeye basma
ShowMessage(FString::Printf(TEXT("Interacted with: %s"),
*HitResult.GetActor()->GetName()), 2.0f);
}
else
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("No interactable object found"));
}
}
}
void AMyGamePlayerController::HandlePauseInput(const FInputActionValue& InputActionValue)
{
bool bIsPressed = InputActionValue.Get<bool>();
if (bIsPressed)
{
TogglePauseMenu();
}
}
void AMyGamePlayerController::CreateHUD()
{
if (HUDWidgetClass && !CurrentHUDWidget)
{
CurrentHUDWidget = CreateWidget<UUserWidget>(this, HUDWidgetClass);
if (CurrentHUDWidget)
{
CurrentHUDWidget->AddToViewport();
// Mouse cursor ayarlarını güncelle
SetMouseCursorSettings();
UE_LOG(LogMyGamePlayerController, Log, TEXT("HUD created and added to viewport"));
// Blueprint event'ini tetikle
OnHUDCreated();
}
else
{
UE_LOG(LogMyGamePlayerController, Error, TEXT("Failed to create HUD widget"));
}
}
else if (!HUDWidgetClass)
{
UE_LOG(LogMyGamePlayerController, Warning, TEXT("HUDWidgetClass is not set"));
}
}
void AMyGamePlayerController::RemoveHUD()
{
if (CurrentHUDWidget)
{
CurrentHUDWidget->RemoveFromParent();
CurrentHUDWidget = nullptr;
UE_LOG(LogMyGamePlayerController, Log, TEXT("HUD removed"));
}
}
void AMyGamePlayerController::TogglePauseMenu()
{
bIsPaused = !bIsPaused;
if (bIsPaused)
{
// Pause menüsünü göster
if (PauseMenuWidgetClass && !CurrentPauseMenuWidget)
{
CurrentPauseMenuWidget = CreateWidget<UUserWidget>(this, PauseMenuWidgetClass);
if (CurrentPauseMenuWidget)
{
CurrentPauseMenuWidget->AddToViewport(100); // Yüksek Z-order
// Oyunu duraklat
SetPause(true);
// Mouse'u göster ve kilitle
bShowMouseCursor = true;
SetInputMode(FInputModeUIOnly());
UE_LOG(LogMyGamePlayerController, Log, TEXT("Pause menu shown"));
}
}
}
else
{
// Pause menüsünü kaldır
if (CurrentPauseMenuWidget)
{
CurrentPauseMenuWidget->RemoveFromParent();
CurrentPauseMenuWidget = nullptr;
// Oyunu devam ettir
SetPause(false);
// Mouse'u gizle
bShowMouseCursor = false;
SetInputMode(FInputModeGameOnly());
UE_LOG(LogMyGamePlayerController, Log, TEXT("Pause menu hidden"));
}
}
// Oyunun durumunu güncelle
bIsGamePaused = bIsPaused;
// Blueprint event'ini tetikle (parametre ismini değiştirdik)
OnPauseChanged(bIsPaused);
}
void AMyGamePlayerController::UpdateScoreUI(float NewScore)
{
CurrentScore = NewScore;
UE_LOG(LogMyGamePlayerController, Log, TEXT("Score updated: %.0f"), CurrentScore);
// Blueprint event'ini tetikle
OnScoreUpdated(CurrentScore);
}
void AMyGamePlayerController::UpdateHealthUI(float HealthPercentage)
{
CurrentHealthPercentage = FMath::Clamp(HealthPercentage, 0.0f, 1.0f);
UE_LOG(LogMyGamePlayerController, Log, TEXT("Health updated: %.1f%%"), CurrentHealthPercentage * 100.0f);
// Blueprint event'ini tetikle
OnHealthUpdated(CurrentHealthPercentage);
}
void AMyGamePlayerController::ShowMessage(const FString& Message, float DisplayTime)
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Showing message: %s"), *Message);
// Ekran mesajı (debug için)
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(
-1,
DisplayTime,
FColor::Yellow,
Message
);
}
// Multiplayer için multicast RPC
if (GetNetMode() != NM_Standalone)
{
Multicast_ShowMessage(Message);
}
}
void AMyGamePlayerController::OnPlayerDied()
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Player died"));
// Input'u devre dışı bırak
SetIgnoreMoveInput(true);
SetIgnoreLookInput(true);
// Ölüm ekranı göster
ShowMessage(TEXT("YOU DIED"), 5.0f);
// 3 saniye sonra respawn
FTimerHandle RespawnTimer;
GetWorld()->GetTimerManager().SetTimer(
RespawnTimer,
[this]()
{
OnPlayerRespawned();
},
3.0f,
false
);
}
void AMyGamePlayerController::OnPlayerRespawned()
{
UE_LOG(LogMyGamePlayerController, Log, TEXT("Player respawned"));
// Input'u tekrar aktif et
SetIgnoreMoveInput(false);
SetIgnoreLookInput(false);
// Sağlığı resetle
UpdateHealthUI(1.0f);
ShowMessage(TEXT("RESPAWNED"), 2.0f);
}
void AMyGamePlayerController::AddScore(float ScoreAmount)
{
if (ScoreAmount <= 0.0f)
return;
// Multiplayer için sunucuya RPC gönder
if (GetLocalRole() == ROLE_Authority)
{
// Sunucudaysak direkt güncelle
CurrentScore += ScoreAmount;
UpdateScoreUI(CurrentScore);
// GameMode'a bildir
if (AMyGameGameMode* GameMode = Cast<AMyGameGameMode>(GetWorld()->GetAuthGameMode()))
{
GameMode->AddPlayerScore(this, ScoreAmount);
}
}
else
{
// Client'taysak sunucuya istek gönder
Server_AddScore(ScoreAmount);
}
}
void AMyGamePlayerController::OnPlayerDamaged(float DamageAmount, AActor* DamageCauser)
{
if (DamageAmount <= 0.0f)
return;
// Sağlık hesaplaması (basit örnek)
// Gerçek implementasyonda sağlık değişkeni Pawn veya PlayerState'te olmalı
CurrentHealthPercentage = FMath::Max(0.0f, CurrentHealthPercentage - (DamageAmount * 0.1f));
UpdateHealthUI(CurrentHealthPercentage);
// Hasar feedback'i
ShowMessage(FString::Printf(TEXT("Damage Taken: %.0f"), DamageAmount), 1.5f);
// Eğer sağlık sıfıra ulaştıysa
if (CurrentHealthPercentage <= 0.0f)
{
OnPlayerDied();
}
}
//////////////////////////////////////////////////////////////////////////
// Ağ (Multiplayer) Fonksiyonları
void AMyGamePlayerController::Server_AddScore_Implementation(float ScoreAmount)
{
if (ScoreAmount <= 0.0f)
return;
CurrentScore += ScoreAmount;
// Client'a skor güncellemesini gönder
Client_UpdateScore(CurrentScore);
// GameMode'a bildir
if (AMyGameGameMode* GameMode = Cast<AMyGameGameMode>(GetWorld()->GetAuthGameMode()))
{
GameMode->AddPlayerScore(this, ScoreAmount);
}
}
// Validate fonksiyonunu header'da tanımlamamız gerekiyor
bool AMyGamePlayerController::Server_AddScore_Validate(float ScoreAmount)
{
// Anti-cheat validation
// Maksimum skor artışını kontrol et
return ScoreAmount > 0.0f && ScoreAmount <= 1000.0f;
}
void AMyGamePlayerController::Client_UpdateScore_Implementation(float NewScore)
{
CurrentScore = NewScore;
UpdateScoreUI(CurrentScore);
}
void AMyGamePlayerController::Multicast_ShowMessage_Implementation(const FString& Message)
{
// Tüm client'larda mesajı göster
if (GEngine && GetNetMode() != NM_DedicatedServer)
{
GEngine->AddOnScreenDebugMessage(-1, 3.0f, FColor::Yellow, Message);
}
}
//////////////////////////////////////////////////////////////////////////
// Yardımcı Fonksiyonlar
void AMyGamePlayerController::SetMouseCursorSettings()
{
if (bLockMouseCursor)
{
bShowMouseCursor = false;
SetInputMode(FInputModeGameOnly());
}
else
{
bShowMouseCursor = true;
FInputModeGameAndUI InputMode;
InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
InputMode.SetHideCursorDuringCapture(false);
SetInputMode(InputMode);
}
}
1. "MyGamePlayerController" sınıfına sağ tıkladığımızda açılan menüden, "Create Blueprint class based on MyGamePlayerController" seçeneğine tıklayarak "Add Blueprint Class" penceresini açalım.
2. "Name" satırına "BP_MyGamePlayerController" değerini girdikten ve "Path" bölümünde "Content\_Game\Blueprints\PlayerControllers" dizinini seçtikten sonra "Create My Game Player Controller Class" butonuna tıklayarak Blueprint sınıfını oluşturalım.
3. İşlem tamamlandığında, "Content\_Game\Blueprints\PlayerControllers" dizininde "BP_MyGamePlayerController" sınıfı oluşturulur.
4. "BP_MyGamePlayerController" penceresini açtığımızda, "Details" sekmesinin "Input" satırında aşağıda gösterilen değerlerin otomatik olarak atandığı görülür:
Unreal Engine Editor'ün "Project Settings" penceresinin "Maps & Modes" sekmesinde, "Player Controller Class" değerini "BP_MyGamePlayerController" olarak değiştirelim. "Default Pawn Class" değeri şimdilik aynı kalacaktır.
⚠️ Yukarıdaki işlemi yaptığımızda, "BP_MyGameGameMode" sınıfının Details sekmesindeki "Player Controller Class" değeri otomatik olarak "BP_MyGamePlayerController" olarak değişir. Aynı şekilde, "BP_MyGameGameMode" sınıfının Details sekmesindeki "Player Controller Class" değerini değiştirdiğimizde, "Project Settings" penceresinin "Maps & Modes" sekmesindeki "Player Controller Class" değeri de otomatik olarak değişir.
Projeyi çalıştırdığımızda,
1. "BP_MyGamePlayerController" sınıfı aktif PlayerController olarak devreye girer ve Outliner'a görünür.
⚠️ AMyGameGameMode::AMyGameGameMode() Constructor fonksiyonu içinde tanımlanan BP_MyGameCharacter değerleri henüz oluşturulmadığından, "Project Settings" içindeki "Default Pawn Class" değeri şimdilik aynı kalacaktır.
2. Aşağıdaki ifadeler sahne ekranında görünür ve bir süre sonra kaybolur.
Welcome .... to My Game! GAME STARTED
3. Aşağıdaki ifadeler Output Log ekranına yazılır:
LogLoad: Game class is 'BP_MyGameGameMode_C' LogMyGame: MyGameGameMode initialized LogMyGamePlayerController: MyGamePlayerController initialized LogMyGamePlayerController: Setting up input component LogMyGamePlayerController: Enhanced Input Component found LogMyGamePlayerController: Move input action bound LogMyGamePlayerController: Look input action bound LogMyGamePlayerController: Jump input action bound LogMyGamePlayerController: Sprint input action bound LogMyGamePlayerController: Interact input action bound LogMyGamePlayerController: Pause input action bound LogMyGame: Pawn spawned for player: DefaultPawn_0 LogMyGamePlayerController: PlayerController possessing pawn: DefaultPawn_0 LogMyGamePlayerController: Warning: InputSubsystem is null, cannot setup input mapping LogMyGame: Handling new player: BP_MyGamePlayerController_C_0 LogMyGame: Player ... joined the game. Total players: 1 LogMyGame: GameMode BeginPlay - Current State: Waiting LogMyGamePlayerController: PlayerController BeginPlay LogMyGamePlayerController: Enhanced Input subsystem found LogMyGamePlayerController: Warning: HUDWidgetClass is not set LogMyGame: Game State Changed: Waiting -> Playing LogMyGame: Game Started! Duration: 300 seconds LogMyGamePlayerController: PlayerController unpossessing pawn LogMyGame: Player ... left the game LogMyGame: Game State Changed: Playing -> Finished LogMyGame: Game Ended: Player Lost