"bir yazılımcının not defteri.."

12 Haziran 2017 Pazartesi

dördüncü minik uygulama - FPS

Merhabalar,
bugün basit de olsa bir First Person Shooter (FPS) deneyimi yapacağız; ve yazının sonunda göreceğiniz görüntüyü oluşturacağız.


1- Proje başlatma ve Temel Ayarlar



önceki yazıdaki temel konuları bildiğinizi varsayıyorum, ve burada mümkün mertebede tekrarlamayacağım.

bu yazıda C++ kullanarak temel FPS yaratmayı anlayacağız, anlamaya çalışacağız; yazının sonunda bir de karakter kullanmayı, yani karakterler ile birlikte çalışmayı, ve biraz da bir karakteri animate etme üzerine konuşacağız.

e hadi başlayalım,

New Project > C++ tabına geçin ve Basic Code Project diyerek projemize "FPSProject" ismini verin; ve No Starter Content ayarlı olarak kalsın.



Create Project buttonuna bastığımızda editör içinde projemiz açılacaktır; eğer şimdi play buttonuna basarsak oyun PIE modda yani Play in Editor modunda editör içinde oynayacaktır, yani editör penceresinin içinde.



WASD tuşlarını kullnarak mini level içinde dönebilirsiniz; ayrıca mouse ile kamerayı da kontrol edebilirsiniz;

burada Escape tuşuna basarak oyunu durdurabilir ve PIE den çıkabilirsiniz.



şimdi Content Folder içinde Maps adında bir folder yaratalım:



ve File menüsünden Save As… diyerek levelimizi FPSMap adı ile Maps folderi nin içine kaydedelim.



şimdi Edit menüsü içinden Project Settings e girelim; Project ana başlığı altında Project Settings tabına geçin, ve on Maps & Modes kısmına bakın; dropdown menuyü kullanarak, FPSMap haritasını Editor Startup Map yani başlangıç haritası olarak seçin,



böylece editör, default map olarak otomatikman bu FPSMap i yükleyecek (load edecek).

Project Settings penceresini kapayın ve kaydedin.



2 - Visual Studio yu açma ve Game Mode:
projeyi açarken Basic Code projesi yarattığımızda Unreal Engine bizim için bir Game Mode otomatik olarak yarattı;

Game Mode lar oyunun kurallarını ve kazanma şartlarını tanımlar; Game modu temel gameplay framwork tipleri için kullanılacak olan class ları da ayarlar: Pawn, PlayerController, HUD.

Bu adımda projemizin Game Mode sınıfını Visual Studio içinden görmek istiyoruz; o yüzden şimdi editörde File menüsü içinden Open Visual Studio deyin ve C++ kodlarını açın.



Solution Explorer içinde cpp ve header h dosyaları göreceksiniz,



FPSProjectGameMode.cpp şu şekilde:
#include "FPSProject.h"
#include "FPSProjectGameMode.h"


FPSProjectGameMode.h dosysının içi de şuna benzemeli:
#pragma once

#include "GameFramework/GameModeBase.h"
#include "FPSProjectGameMode.generated.h"

/**
 * 
 */
UCLASS()
class FPSPROJECT_API AFPSProjectGameMode : public AGameModeBase
{
    GENERATED_BODY()
};



3- Ekrana Log Mesajı Ekleme:
Log lar programcıların dostudur;  Log mesajları olan biteni doğrulama; ve geliştirme esnasında hata ayıklama (debug) için gerçekten kullanışlıdır;  biz de şimdi FPSGameMode kullanımına istinaden log mesajları ekleyeceğiz;

bunun için Unreal Engine tarafında sağlanan klasik game moduna ilave yapıcaz; burada ilk olarak  FPSProjectGameMode.h  header dosyası hedefimizde olacak malum.

bunun için,
Solution Explorer, penceresinin içinde FPSProject > Source > FPSProject i genişletin ve game mode header ine ulaşın;



UCLASS()
class FPSPROJECT_API AFPSGameMode : public AGameModeBase
{
    GENERATED_BODY()
};

yapıcı AFPSProjectGameMode sınıf tanımının içine aşağıdaki kodu ekleyin:

virtual void StartPlay() override;

böylece AActor class dan miras alınmış olan StartPlay() functionunun override etmiş oluıyoruz, ezmiş oluyoruz,

şimdi artık gameplay esnasında oyun başladığında ekrana bi log mesajı basacak olan kodu ekleyebiliriz:

FPSProjectGameMode.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/GameModeBase.h"
#include "FPSProjectGameMode.generated.h"

/**
 * 
 */
UCLASS()
class FPSPROJECT_API AFPSProjectGameMode : public AGameModeBase
{
    GENERATED_BODY()

    virtual void StartPlay() override;
};

header i kaydedin; şimdi solution dan cpp yi bulalım





şimdi AFPSProjectGameMode yapıcısı içinde override ettiğimiz StartPlay() function u için aşağıdaki satırları ekleyelim:

void AFPSProjectGameMode::StartPlay()
{
    Super::StartPlay();

    if (GEngine)
    {
        // Display a debug message for five seconds. 
        // The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World, this is FPSGameMode!"));
    }
}

StartPlay() fonksyonu artık ekrana debug mesajı verecektir: "Hello World, this is FPSGameMode!", sarı bir text ile ve beş saniye kadar ekranda kalacaktır;


FPSProjectGameMode.cpp artık şöyle görünecektir:
// Fill out your copyright notice in the Description page of Project Settings.

#include "FPSProject.h"
#include "FPSProjectGameMode.h"

void AFPSProjectGameMode::StartPlay()
{
    Super::StartPlay();

    if (GEngine)
    {
        // Display a debug message for five seconds. 
        // The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World, this is FPSGameMode!"));
    }
}
Visual Studio da cpp dosyamızı da kaydedelim;


4 - projeyi derleyin:
şimdi sıra geldi projemizi derlemeye, editör içinden Compile buttonuna basın ve kodumuzu derleyin;



C++ projesine başladığımızdan beri, C++ kodunu doğrudan editör içinde Compile butttonu ile derleyebiliriz,

ve ardından Play buttonu ile olu PIE modda editör penceresinin içinde oynayın,



Log mesajının neden ekranda görünmediğini merak ediyor olabilirsiniz; bunun nedeni editörün bu etapta halen Default Game Modunu kullanıyor olmasıdır; birazdan  (6. aşamada) bunu ayarlayacağız..

escape e basarak editör PIE modundan çıkın;



5- C++ Game Mode Class ını Blueprint ortamında extent etme:
ilk olarak Content Browser penceresinde geçip  Content folder içinde Blueprints folder i yaratalım:



şimdi FPSProjectGameMode class a sağ tıklayın ve C++ Class Actions menüsünü açın:



şimdi Create Blueprint class based on FPSProjectGameMode a tıklayarak Add Blueprint Class dialog menüsünü açın,



şimdi de yeni Blueprint Class ımıza "BP_FPSProjectGameMode" ismini verin ve kaydedilecek yer olarak da Blueprints folderini seçin; son olarak Create Blueprint Class buttonuna basın.



şu ana kadar Blueprints folder i içinde yeni bir BP_FPSProjectGameMode Blueprint Class ı yaratmış olmalıyız:



editörü kapamadan önce BP_FPSProjectGameMode Blueprint ini kaydettiğinize emin olun.



6 - Setting the Default Game Mode
şimdi yeni değiştirilmiş olan Game Mode sınıfımızı BP de extend ettik, şimdi sıra geldi projemizin Default Mode unu bu BP_FPSProjectGameMode yapmaya.

Edit -> Project Settings
Project in altında sol tarataki Project Settings tabda, Maps & Modes a tıklayın;

Default GameMode dropdown menüsünden BP_FPSGameMode seçin



Project Settings menüsünü kapayın;

şimdi yine Play buttonuna basarak oynayın "Hello World, this is FPSGameMode!" yazısı artık görünmelidir, ve beş saniye ekranda sol üst köşede kalmalıdır;



ESC ile oyunu durdurun, ve PIE den çıkın.

kodun tamamı şöyle :


FPSProjectGameMode.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/GameModeBase.h"
#include "FPSProjectGameMode.generated.h"

/**
 * 
 */
UCLASS()
class FPSPROJECT_API AFPSProjectGameMode : public AGameModeBase
{
    GENERATED_BODY()

    virtual void StartPlay() override;
};


FPSProjectGameMode.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "FPSProject.h"
#include "FPSProjectGameMode.h"

void AFPSProjectGameMode::StartPlay()
{
    Super::StartPlay();

    if (GEngine)
    {
        // Display a debug message for five seconds. 
        // The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World, this is FPSGameMode!"));
    }
}



7 - Karakterimizi ayarlayalım:



resimdeki bu yazının sonunda göreceğimiz şey olacak inşallah :) bu yazının amacı bir FPS karakterini kullanmak (implement) idi; bunun için yeni bir karakter yapıcaz;

  • onun Axis Map ini tanımlayacağız; 
  • Character Movement Function larını kullanarak karaktere zıplama (jumping) niteliği vericez); 
  • kamera bakış açısını (view) değiştiricez 
  • karakterimize bu yazının konusu olan bir First Person Mesh ekleyeceğiz.


yeni bir karakter yapmak için motorun character base class ını kullanalım;

Character sınıfı Pawn sınıfından miras alınmıştır ve ona iki ayaklı hareket fonksyonaliteleri dahil edilmiştir; örneğin yürüme koşma ve zıplama gibi.

Visual Studio içinden manuel olarak *.h ve *.cpp dosyalarını solution a ekleyebilmemize rağmen onları sihirbaz ile eklemek iyi bir pratiktir; sihirbazı kullanarak motor bir header template ekler.



buradan parent class olarak Character seçin ve next deyin,



class ismine "FPSCharacter" girip create buttonuna basın.



artık visual studio ya geçtiğimizde sınıfımızı görebiliriz ve ona yeni kod eklemeye başlayabiliriz, yeni yaratılan sınıf Solution Explorer içinde , FPSProject > Source > FPSProject altındadır.




şimdi FPSCharacter class ın FPSCharacter.cpp dosyasını açarak içnie aşağıdaki satırı BeginPlay() functionuna kleyelim,

if (GEngine)
{
    // Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}


FPSCharacter.cpp artık böyle görünecek son hali:
// Fill out your copyright notice in the Description page of Project Settings.

#include "FPSProject.h"
#include "FPSCharacter.h"

// Sets default values
AFPSCharacter::AFPSCharacter()
{
    // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (GEngine)
    {
        // Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
    }
}

// Called every frame
void AFPSCharacter::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

}

// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

}


şimdi Solution Explorer içinden bizim yeni projeyi bulup derleyin, (tüm solution u değil)



Visual Studio derlemesi bittiğinde Unreal Editor ü açın ve yeni yarattığımız FPSCharacter class ının Content Browser içinde görünüp görünmediğini kontrol edin.





8 - C++ class ını Blueprint den miras alarak genişletme
şimdi artık yarattığımız sınıfı Bluprint ortamından miras alabiliriz; FPSCharacter e sağ tıklayın ve C++ Class Actions menüyü açın;



ve Add Blueprint Class dialog menüsünden Create Blueprint class based on FPSCharacter seçin



şimdi yni yaratacağımız Blueprint sınıfına "BP_FPSCharacter" adını verin ve yaratılacak folder olarak Blueprints folderini seçin, alttaki buttona basarak tamamlayın.



artık folder da yeni sınıfımız görünüyor olmalı,






9- Default Pawn Class ı ayarlama:
yeni değiştirilmiş Game Mode sınıfımızı Blueprint de başarı ile extend ettik; şimdi ihtiyacımız olan şey, BP_FPSCharacter i, default pawn sınıfı olarak projemizde ayarlamaktır,

Edit ->Project Settings  e girin ve resimde görüldüğü şekilde Default Pawn Class ı bizim az önce yarattığımız class olarak ayarlayın.



Project Settings menüsünü kapayın ve toolbar daki play buttonuna basarak editör içinde oynayın, "We are using FPSCharacter." yazısı "Hello World ün altında görünmelidir, yazı 5 saniye kadar viewport penceresinde kalacaktır.



şayet hareket edemiyorsanız (If you're unable to move) FPSCharacter ini doğru bir şekilde default Pawn olarak ayarlamışsınız demektir :) çünkü yeni karakterimiz henüz herhangi bir movement controlüne sahip değildir;

ESC ile PIE moddan çıkın.



10 - Axis Mapping i ayarlama
genellikle Axis Mapping ler bize daha sonra oyun davranışı (game behavior) olarak bağlanabilecek klavye, mouse, ve ila controller inpıt girdilerini map etmemize (giriş takımı ayarlamamıza) olanak sağlar; örneğin hareketler (movement) gibi. Axis Mappings ler kesintisiz hareketler ve akışkan oyun davranışları (game behavior) için sürekli olarak sorgulanır.

Joistik controller gibi eksenli donanımlar, basılıp basılmadığını (1/0 durumu) bildiren tuş takımı yerine açı girdileri (degrees of input) sağlayabilir;

joistik input metodları ölçeklenebilir (scalable) hareket girdileri (movement input) sağlamada etkili iken, Axis Mappings ler sürekli sorgulanan oyun davraşını yaratmak için genel hareket tuşlarını (common movement keys) map edebilir, WASD gibi..

şimdi karakterimize saha içinde gezinmesini sağlayacak bazı input Axis Mappings ler tanımlayalım.

Edit -> Project Settings e girin ve sol taraftaki Engine başlığına geçin ve Project Settings tabından da Input kısmına geçin; oran da  Bindings -> Axis Mappings e geçin,

isimlendirme kutusuna "MoveForward" yazın, ve  Dropdownlist ten W klavye tuşunu bu key map adına kaydedin; değer olarak +1 atayın;

aynı şekilde S harfini de tanımlayarak -1 scale değeri verin;

input setimiz aşağıdaki şekilde görünmeli:



şimdi sağa ve solu da tanımlayalım:

şimdi yeni bir tanımlama aşarak adını  "MoveRight"  olarak belirtin, options alanını genişletin ve  D ve A klavye input girişlerine de  +1 ve -1 değerleri ile kaydedin.



A harifini  "MoveLeft" olarak yeni bir girdi seti adında açın.



11 - Implementing Character Movement Functions
şimdi bu adımda Player Input Component imizi ayarlayacağız, ve FPSCharacter class ında
MoveForward ve MoveRight fonksyonlarıı tanımlayacağız.


şimdi visual studio ya geri dönelim:

FPSCharacter.h içine aşağıdaki fonksyon deklarasyonunlarını yapalım:
// Handles input for moving forward and backward.
UFUNCTION()
void MoveForward(float Value);

// Handles input for moving right and left.
UFUNCTION()
void MoveRight(float Value);

UFUNCTION makrosu her fonksyonun aşında bulunur, ve engine in bu fonskyonların farkında olmasını sağlar, böylece onlar serileştirme (serialization) ve diğer engine fonksyonelleiklerine katılabilirler.


FPSCharacter.h şimdi aşağıdaki gibi görünüyor:
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"

UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    AFPSCharacter();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:
    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    // Handles input for moving forward and backward.
    UFUNCTION()
    void MoveForward(float Value);

    // Handles input for moving right and left.
    UFUNCTION()
    void MoveRight(float Value);

};



Movement Function işlemleri (Implementations):
tipik bir FPS control sisteminde karakter hareket axes leri kamera ile ilişkilidir; mesela ileri hareket ("Forward" movement ) in anlamı kameranın ileri yönüdür; sağ hareket ise kemeranın baktığı noktanın sağa kaymasıdır;

karakterin roration (dönüş) kontrolünü elde etmek için PlayerController kullanacağız; ayrıca, MoveForward functionumuz rotation controlü sağlayan pitch component ini de görmezden gelecektir (ignore) ve input girişlerini de XY düzleminde kısıtlayacaktır (restrict), böylece yukarı veya aşağı doğru bakıyorken dahi karakterimizin yer boyunca hareket etmesini garantiye alacaktır.


FPSCharacter.cpp dosyasının içinde SetupPlayerInputComponent fonksyonuna aşağıdaki kod satırlarını ekleyin,
// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up "movement" bindings.
    PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
}


InputComponent input datanın nasıl handle edileceğini tanımlayan bir componenttir; bir InputComponent bir Actor e attachlanabilir; böylece o Actor Input girdileri alabilmeye başlar.


FPSCharacter.cpp dosyasının içine de MoveForward function tanımının içine aşağıdaki satırları ekleyin;
void AFPSCharacter::MoveForward(float Value)
{
    // Find out which way is "forward" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
    AddMovementInput(Direction, Value);
}

FPSCharacter.cpp şimdi böyle görünmeli:
// Fill out your copyright notice in the Description page of Project Settings.

#include "FPSProject.h"
#include "FPSCharacter.h"

// Sets default values
AFPSCharacter::AFPSCharacter()
{
    // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (GEngine)
    {
        // Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
    }
}

// Called every frame
void AFPSCharacter::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

}

// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up "movement" bindings.
    PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
}

void AFPSCharacter::MoveForward(float Value)
{
    // Find out which way is "forward" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
    AddMovementInput(Direction, Value);
}

void AFPSCharacter::MoveRight(float Value)
{
    // Find out which way is "right" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
    AddMovementInput(Direction, Value);
}

şimdi olanı derleme ve yeni karakter movement fonksyonaliyemizi test etme zamanı,
tümünü kaydedin; Solution Explorer dan FPSProject i bulun ve projeyi derleyin; derleme sonrası editöre geçerek, play buttonu ile PIE de oynayın; artık ileri ve geri sağa ve sola yürüyebildiğinizi görün. Escape ile PIE den çıkın.




12 - bu adımda karakterimize mouse ile etrafa bakabilme yetisi vereceğiz,
Edit -> Project Settings ->Input 
oradan Bindings altında, Axis Mappings e girin;
kutuya "Turn" yazın ve Mouse dropundan Mouse X i seçin

settings ayarı böyle görünmeli:


bir tane de "LookUp" adında tanımlayın, onu da ayn Mouse dropundan Mouse Y seçerek yapın;
Type "-1.0" Scale değeri olarak girin.

input ayarlarınızın son halie aşağıdaki gibi görünmelidir:


Project Settings ekranını kapayın.



şimdi input girdilerini handle edelim:
şimdi character base sınıfına bu iki fonksyonu ekleyeceğiz:
  • AddControllerYawInput
  • AddControllerPitchInput

eğer ek süreçleri eklemek istersek örneğin hassasiyet desteği veya eksen çevirme vs.. input girdilerini fonksyonlara girmeden (pass etmeden) önce çeşitli ayarlamaları (adjust) yapacak kendi fonksyonlarımızı da sağlayabiliriz; fakat, bu durumda input larımızı doğrudan AddControllerYawInputand ve AddControllerPitchInput fonksyonlarına bağlayacağız,


FPSCharacter.cpp ye aşağıdaki satırları ekleyin:
// Set up "look" bindings.
PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);


SetupPlayerInputComponent fonksyonu aşağıdaki gibi görünmeli:
// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up "movement" bindings.
    PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);

    // Set up "look" bindings.
    PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
    PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
}

Mouse Camera Controlünü test edelim hemencik:
Visual Studio içinde projenizi derleyin; sonra yine editöre geçip play buttonu ile deneyin.




13 - Character zıpamasını (Jumping) ayarlayalım:
Action Mappings ler pawn ı kontrol etmekten ziyade genellikle biraz daha farklı işlerle, olay temelli (event-driven) bağlanabilen yordamlar ile ilgilenirler;

bir tuşa basma (pressing) veya serbest bırakma (releasing), veya mouse button, veya key pad button ile tetiklenen ve doğrudan oyun davranışını tetikleyen bir etkiye neden olurlar.

bu aşamada, Action Mapping inputu ayarlayarak karaktere zıplama (jump) yeteneği kazandıracağız.

Edit -> Project Settings
Engine -> Project Settings ->Input
Bindings -> Action Mappings.

kutuya "Jump" yazın, action binding options i genişletin (expand)
dropdown menu içinde, Keyboard dropdown list içinden Space Bar seçin.

input ayarları böyle görünmeli:




Project Settings penceresini kapayın; kaydedin.

şimdi bu Input u Handle edelim:
Character base class ın .h deader dosyasının içine bakaranız, karkater zıpklaması (jumping) için zaten desteğinin olduğunu göreceksiniz; zıplama işlevi header içinde bPressedJump değişkenine (variable) bağlanmıştır, dolayısı ile tüm yapmamız gereken jump action u preslendiğinde bu bool değişkeni true olarak set etmektir; ve aynı şekilde action release olduğunda false set etmektir. bu yüzden aşağıdaki iki fonksyonu FPSCharacter class ımıza ekleylim:
  • StartJump
  • StopJump

Visual Studio ya dönelim ve FPSCharacter.h dosyasına public fonksyon olarak bu iki fonksyonu declare edelim:
// Sets jump flag when key is pressed.
UFUNCTION()
void StartJump();

// Clears jump flag when key is released.
UFUNCTION()
void StopJump();


FPSCharacter.h dosyası şimdi aşağıdaki şekilde görülmeli:
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"

UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    AFPSCharacter();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:
    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    // Handles input for moving forward and backward.
    UFUNCTION()
    void MoveForward(float Value);

    // Handles input for moving right and left.
    UFUNCTION()
    void MoveRight(float Value);

    // Sets jump flag when key is pressed.
    UFUNCTION()
    void StartJump();

    // Clears jump flag when key is released.
    UFUNCTION()
    void StopJump();
};



FPSCharacter.cpp içine de fonksyonların gerçek tanımlarını koyalım:
void AFPSCharacter::StartJump()
{
    bPressedJump = true;
}

void AFPSCharacter::StopJump()
{
    bPressedJump = false;
}


aşağıdaki kodu Jump işlevini handle etmek yani bağlamak için yeni yazılan fonksyonlara ekliyoruz;

// Set up "action" bindings.
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);


FPSCharacter.cpp artık böyle görünmeli:
// Fill out your copyright notice in the Description page of Project Settings.

#include "FPSProject.h"
#include "FPSCharacter.h"

// Sets default values
AFPSCharacter::AFPSCharacter()
{
    // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (GEngine)
    {
        // Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
    }
}

// Called every frame
void AFPSCharacter::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

}

// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up "movement" bindings.
    PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);

    // Set up "look" bindings.
    PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
    PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);

    // Set up "action" bindings.
    PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
    PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
}

void AFPSCharacter::MoveForward(float Value)
{
    // Find out which way is "forward" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
    AddMovementInput(Direction, Value);
}

void AFPSCharacter::MoveRight(float Value)
{
    // Find out which way is "right" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
    AddMovementInput(Direction, Value);
}

void AFPSCharacter::StartJump()
{
    bPressedJump = true;
}

void AFPSCharacter::StopJump()
{
    bPressedJump = false;
}

şimdi karakter zıplamasını test edelim; projeyi derleyin, ve editörden PIE modda oynayın.




14 - Adding a Mesh to your Character
Download linkinden Epic Games in örnek olarak verdiği mesh i bilgisayarınıza indirin; bu adımda karakterimize bir skeletal mesh vereceğiz; character class default olarak bizim için bir SkeletalMeshComponent objesi yaratır, ve tüm ihtiyacı olan hangi SkeletalMesh asseti kullanacağını bilmesidir.

Skeletal Mesh Import etme:
Content Browser a sağ tıklayın ve Import Asset deyin;
'Import to /Game...' tıklayın;




indirdiğiniz dosyadaki GenericMale.fbx mesh dosyasını bulun; ardından
"Click Open to begin importing the mesh to your project" deyin

Content Browser içinde, "FBX Import Options" dialog penceresi görünecektir;  Import a tıklayın ve mesh i projenize ekleyin; son olarak Save buttonu ile eklediğiniz mesh i Third Person Mesh e kaydedin.

şimdi  BP_FPSCharacter ikonuna çift tıklayarak onu Blueprint Editor içinde açın;
Components tabı içinde Mesh component e tıklayın;



Details Tabı içinde içinde None yazan  MEsh kısmı (section) ı açın ve GenericMale skeletal mesh i seçin.



Z lokasyonunu -88.0 yaparak SkeletalMeshComponent i CapsuleComponent e hizalayın.



SkeletalMeshComponent şimdi aşağıdakine benzer olmalı:



ArrowComponent in işaret ettiği aynı yönde, karakterin dünya içinde doğru yönde hareket edeceği, SkeletalMeshComponent inizi CapsuleComponent in içinde bulmak iyi bir pratiktir,

Blueprint editöründen çıkmadan önce BP_FPSCharacter Blueprint inizi derleyin (compile) ve kaydedin; yeni mesh i PIE modda tekrar deneyelim:


ekranda karakterimizin şimdi görünmesi gerek:


karakterin mesh ini editör ün viewport u içinde görmek istersek F8 e basmalıyız ki pawn ımızın içinden çıkabilelim. F8 sonrası camera level içinde özgürce hareket edecektir. kamerayı hareket ettirmek için mouse in sol tuluna basılı tutarken bir andan hareket ettirin.



herşey ok ise escape ile PIE den çıkabilirsiniz.



15 - Camera View ini değiştirme:
bir önceki adımın sonunda, default camera mesh in boynuna konumlanmıştı (was positioned) , bu adımda, FPS camera yı detalı ayarlayacağız, özelliklerine ince ayar çekicez, örneğin lokation, field of view gibi...

bir Camera Component attach etme:

Visual Studio ya dönün ve FPSCharacter.h dosyasını açın ve aşağıdaki kodu ekleyin:
// FPS camera.
UPROPERTY(VisibleAnywhere)
UCameraComponent* FPSCameraComponent;


FPSCharacter.h artık böyle görünmeli:
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"

UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    AFPSCharacter();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:     
    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    // Handles input for moving forward and backward.
    UFUNCTION()
    void MoveForward(float Value);

    // Handles input for moving right and left.
    UFUNCTION()
    void MoveRight(float Value);

    // Sets jump flag when key is pressed.
    UFUNCTION()
    void StartJump();

    // Clears jump flag when key is released.
    UFUNCTION()
    void StopJump();

    // FPS camera.
    UPROPERTY(VisibleAnywhere)
    UCameraComponent* FPSCameraComponent;
};

şimdi FPSCharacter.cpp yi açın ve, aşağıdaki kodu yapıcı fonksyona ekleyin:
// Create a first person camera component.
FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
// Attach the camera component to our capsule component.
FPSCameraComponent->SetupAttachment(GetCapsuleComponent());

bu kod bir UCameraComponent yaratır ve ona karaktein CapsuleComponent ini attach eder.

yapıcı nın içine yazdığımız kod bloğunun altıuna aşağıdaki kodu ekleyin:
// Position the camera slightly above the eyes.
FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
// Allow the pawn to control camera rotation.
FPSCameraComponent->bUsePawnControlRotation = true;

bu kod, pawn a kamera rotatioın unu control etmesine izin veriyor iken kamera pozisyonunu karakterin hafif göz hizasının üzerine ayarlar.

FPSCharacter.cpp dosyası artık şöyle görünmeli:
// Fill out your copyright notice in the Description page of Project Settings.

#include "FPSProject.h"
#include "FPSCharacter.h"

// Sets default values
AFPSCharacter::AFPSCharacter()
{
    // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    // Create a first person camera component.
    FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
    // Attach the camera component to our capsule component.
    FPSCameraComponent->SetupAttachment(GetCapsuleComponent());
    // Position the camera slightly above the eyes.
    FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
    // Allow the pawn to control camera rotation.
    FPSCameraComponent->bUsePawnControlRotation = true;
}

// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (GEngine)
    {
        // Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
    }
}

// Called every frame
void AFPSCharacter::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

}

// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up "movement" bindings.
    PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);

    // Set up "look" bindings.
    PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
    PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);

    // Set up "action" bindings.
    PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
    PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
}

void AFPSCharacter::MoveForward(float Value)
{
    // Find out which way is "forward" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
    AddMovementInput(Direction, Value);
}

void AFPSCharacter::MoveRight(float Value)
{
    // Find out which way is "right" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
    AddMovementInput(Direction, Value);
}

void AFPSCharacter::StartJump()
{
    bPressedJump = true;
}

void AFPSCharacter::StopJump()
{
    bPressedJump = false;
}

şimdi yeni Camera yı test edelim; yeni camera kodlarımızı derleyin,

FPSCharacter header (*.h) ve CPP (*.cpp) dosyakarını Visual Studio içinde kaydedin ve projeyi derleyin; PIE de oynatın; şimdi artık camera karakterin kafasının hemen üzerinde olmalı. escape ile çıkın PIE den.



16 - Character e first person mesh ekleme:
genel FPS oyun yapma yaklaşımı iki ayrık character mesh i kullanmaktır, birincisi full-body mesh, ve ikincisi de silah ve eller mesh i şeklindedir. Full-Body mesh karakterin thirt person perspective den görmek için kullanılır, fakat, first-person perspective görünümünde iken bu mesh gizlenir; "weapon and hands" mesh tipik olarak camera ya attachlanmış durumdadır ve sadece oyuncuya ve de o oyuncu FPS den bakıyor iken görünebilirdir; bu adımda karkaterimize bir First person mesh ekleyeceğiz.


şimdi Visual Studio ya dönün ve FPSCharacter.h dosyasını açıp aşağıdaki kodu ekleyin :
// First-person mesh (arms), visible only to the owning player.
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
USkeletalMeshComponent* FPSMesh;

şimdi FPSCharacter.cpp yi açınve yapıcı fonksyonu bulun FPS meh i yaratmak ve configure etmek için aşğıdaki kodu ekleyin:
// Create a first person mesh component for the owning player.
FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
// Only the owning player sees this mesh.
FPSMesh->SetOnlyOwnerSee(true);
// Attach the FPS mesh to the FPS camera.
FPSMesh->SetupAttachment(FPSCameraComponent);
// Disable some environmental shadowing to preserve the illusion of having a single mesh.
FPSMesh->bCastDynamicShadow = false;
FPSMesh->CastShadow = false;

SetOnlyOwnerSee mesh sadece bu karakter tarafından yönetilen PlayerController tarafından görüleceğini belirtir. Bu kod aynı zamanda mesh i camera ya attach ediyor ve bazı ortamsal yansımaları disable ediyor.  Camera-Attahed Arm lara gölgeler vermek yarattığımız FPS karakter tekil mesh ilüzyonunu yokederdi.

Nihayetinde, varolan third-person mesh i sahip olduğu karakterden gizlemek için FPSCharacter.cpp dosyasındaki yapıcı fonksyona aşağıdaki kodu ekleyin:
// The owning player doesn't see the regular (third-person) body mesh.
GetMesh()->SetOwnerNoSee(true);


FPSCharacter header (*.h) dosyasını kaydedin ve (*.cpp) dosyası üzerinde de gerekli değişikliği yaptıktan sonra projemizi Visual Studio ortamından derleyelim; ve PIE modda oynayalım;

bu noktada, karakterimizin mesh i editör içinde görünmüyor olmalı.




Mesh Blueprint ini yapalım:
First Person Skeletal Mesh önce buradaki dosyayı bilgisayarınıza indirin;


Content Browser a sağ tıklayın, Import Asset dialog box ını açın, oradan 'Import to /Game...'  diyaloğunu açın:


HeroFPP.fbx mesh dosyasını bulun ve projenize Open diyerek ekleyin.

aşağıdaki gibi bir uyarı penceresi gelirse önemsemeyin:

bu mesh first person mesh i sembolize (illustrate) eder, ve bir sonraki kısımda yapacağımız animasyonlar ile birlikte çalışır. Save buttonuna tıklayıp mesh i import edin.

Content Browser içinde Blueprints folder i içinde ki BP_FPSCharacter ikonuna çif tıklayıp onu editörde açın;  ve Components tabı içindeki FPSMesh component i bulun:


FirstPersonMesh component,  FirstPersonCameraComponent in child componentidir. Bu da onun her zaman camera ya attach lanacağı anlamına gelir.

şimdi Components menüsünden  FirstPersonMesh e tıklayın, ve None u seçin; şimdi HeroFPP skeletal mesh i Viewport a eklemek için seçin.



yeni eklenen HeroFPP skeletal mesh viewport ta aşağıdaki şekilde görünmelidir.



yeni eklenen mesh in transform değerlerini kameranın önünde kalması için transform: 240, 0 , 35  ve rotasyon: -180, 50 , -180 değerlerine ayarlayın.



kaydedin ve derleyin, ve oyunda çıktıyı deneyin.



kodun son hali aşağıdaki gibi olmalıdır:

FPSCharacter.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"

UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    // Sets default values for this character's properties
    AFPSCharacter();

protected:          
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    // Handles input for moving forward and backward.
    UFUNCTION()
    void MoveForward(float Value);

    // Handles input for moving right and left.
    UFUNCTION()
    void MoveRight(float Value);

    // Sets jump flag when key is pressed.
    UFUNCTION()
    void StartJump();

    // Clears jump flag when key is released.
    UFUNCTION()
    void StopJump();

    // FPS camera.
    UPROPERTY(VisibleAnywhere)
    UCameraComponent* FPSCameraComponent;

    // First-person mesh (arms), visible only to the owning player.
    UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
    USkeletalMeshComponent* FPSMesh;
};


FPSCharacter.cpp
// Fill out your copyright notice in the Description page of Project Settings.

#include "FPSProject.h"
#include "FPSCharacter.h"

// Sets default values
AFPSCharacter::AFPSCharacter()
{
    // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    // Create a first person camera component.
    FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
    // Attach the camera component to our capsule component.
    FPSCameraComponent->SetupAttachment(GetCapsuleComponent());
    // Position the camera slightly above the eyes.
    FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
    // Allow the pawn to control camera rotation.
    FPSCameraComponent->bUsePawnControlRotation = true;

    // Create a first person mesh component for the owning player.
    FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
    // Only the owning player sees this mesh.
    FPSMesh->SetOnlyOwnerSee(true);
    // Attach the FPS mesh to the FPS camera.
    FPSMesh->SetupAttachment(FPSCameraComponent);
    // Disable some environmental shadowing to preserve the illusion of having a single mesh.
    FPSMesh->bCastDynamicShadow = false;
    FPSMesh->CastShadow = false;

    // The owning player doesn't see the regular (third-person) body mesh.
    GetMesh()->SetOwnerNoSee(true);
}

// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
    Super::BeginPlay();

    if (GEngine)
    {
        // Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
    }
}

// Called every frame
void AFPSCharacter::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

}

// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

    // Set up "movement" bindings.
    PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
    PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);

    // Set up "look" bindings.
    PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
    PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);

    // Set up "action" bindings.
    PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
    PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
}

void AFPSCharacter::MoveForward(float Value)
{
    // Find out which way is "forward" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
    AddMovementInput(Direction, Value);
}

void AFPSCharacter::MoveRight(float Value)
{
    // Find out which way is "right" and record that the player wants to move that way.
    FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
    AddMovementInput(Direction, Value);
}

void AFPSCharacter::StartJump()
{
    bPressedJump = true;
}

void AFPSCharacter::StopJump()
{
    bPressedJump = false;
}

bu örnekte karaktere bir mesh eklemeyi ve kamera bakışımı değiştirmeyi de örneklemiş olduk.

şimdi buraya kadar olanları bir sindirelim; biraz zaman alacak..

şimdilik bir sonraki yazıda görüşmek üzere hoşça kalın.

Hiç yorum yok: