Merhaba topluluk! Bu yazıda Blueprintler için belki aşina olduğunuz Event Dispatcher ile farklı olayları farklı yerlere yayabiliyorduk(Call) veya çağırabiliyorduk(Bind). Bu işlemi C++ üzerinde nasıl yapacağımız hakkında sizlere bilgi vereceğim. Lütfen alıntı yapacaksanız adımı ve soyadımı "Ali Kubur" belirtin.
Öncelikle Delege nedir ondan bahsetmek istiyorum. Basit olarak delegeler ile çalışma zamanı içerisinde farklı sınıflar arasında olan olayları birbirine yayabilirsiniz. Diyelim ki karakterinizde olan bir olayı (mesela zıplaması) olayını yayarak, karakter zıpladığı anda başka bir sınıfta olan üye fonksiyonunu çağırabiliriz. Aynı zaman bu olayları aynı event dispatcher üzerinden olduğu gibi C++ yazdığımız delegeleri blueprint üzerine UPROPERTY(BlueprintAssignable) makrosu ile Blueprintler üzerinden çağırabilirsiniz.
Basit olarak delegelerin ne olduğunu anladığımıza göre nasıl uygulayacağımıza bakalım.
Delegeleri tanımlamak için
DECLARE_DYNAMIC_MULTICAST_DELEGATE_XParam makrosunu kullanırsınız. Buradaki X delegenizin kaç tane parametre aldığını belirtiyor.
Örnek olarak
Mesela diyelim ki int, float ve double tipinde üç parametreleri FDelegeIsmi adında bir delege makrosu tanımlayacak olursak
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FDelegeIsmi, int, int_parametresi, float, float_parametresi, double, double parametresi); // Bu makroyu kullanırken, veri tipleri ve parametrelerden sonra , gelir.
Sadece ilkel veri tipi değil, kendi yarattığınız veri tiplerini de delegeden parametre olarak geçirebilirsiniz.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FQuestCompletedEvent, int32, QuestID); // Bir parametreli
Eğer hiç parametre vermek istemiyorsanız
[size=small]DECLARE_MULTICAST_DELEGATE(FDelegenizinIsmi);
Dikkat ederseniz bu makro ilk olarak yaratacağınız delegenin bir imzasını alıyor. İmza olarak istediğiniz ismi verebilirsiniz ben örnek olarak F[size=small]DelegenizinIsmi dedim.
Daha sonradan dikkat ettiyseniz tipleri yazıktan sonra parametre isimlerini yazdım. Virgüllere dikkat edin, bu makro bu şekilde çalışıyor.
Pekala, nasıl tanımlayacağımızı anladığımıza göre örnekler yapalım. Diyelim ki Karaker XP kazandığında delege olarak tanımlayalım ve bu olay olunca başka bir Aktörde bir üye fonksiyon çağıralım.
Öncelikle bu delege karakter sınıfımızda olacağı için karakter sınıfının UCLASS() makrosunun üzerinde delegeyi tanımlamak zorundayız.
[code-sh=cpp] // delegeler UCLASS üzerindeki yere, yani buraya beyan etmek zorundasınız.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLevelAtlandi, int32, XP); // Delegeyi tanımladım, bir parametre alıyor o da var olan yeni seviye...
UCLASS()
class PROJENIZ_API AProjeKarakter : public ACharacter
{
public:
UPROPERTY(BlueprintAssignable, Category="Level") // Blueprintler üzerinden bu delege çağrılabilinir
FLevelAtlandi XPKazanildi; // Delegemizin örneğini sınıf içerisinde yerleştirdik..
UFUNCTION()
void XPEkle(int32 XPMiktari); // Bir üye fonksiyon olsun..
// devam ediyor...
[/code-sh]
Diyelim ki XP arttıran bir üye fonksiyonumuz var. Adı XPEkle olsun parametre olarak int32 XP alsın. Bu üye fonksiyonu çağrıldığında bu olayın, bütün dinleyicilere yayıldığını belirtmek için Broadcast kullanılır.
Üye fonksiyonunun tanımlaması şu şekilde olsun.
[code-sh=cpp] // Üye fonksiyonu
void AProjeKarakter::XPEkle(int32 XP)
{
// Broadcast basitçe bu delegeyi bütün dinleyicilere yaymak demek. Parametre olarak yaymak zorundasınız. Yani XPKazanildi olayı gerçekleşince bunu dinleyen bütün hepsine yayıyorum. Bu olayın gerçekleştiğini anlatıyor.
XPKazanildi.Broadcast(XP);
}
// XPKazanildi olayının bütün dinleyicileri bu fonksiyon devreye girdiği zaman işlerini yapabilecektir.
[/code-sh]
Diyelim ki bir ABC adında aktörümüz olsun ve xp kazanıldığı zaman basitçe bir Log mesajı versin. Bunun için genellikle BeginPlay üzerinde XP eklendiği zaman olayı dinamik bir şekilde aktarabilmesi için şu şekilde tanımlanması gerekir
[code-sh=cpp] // Oyuna başladığında dinamik olarak delgeye fonksiyonu bildiriyoruz. Blueprint üzerindeki "Assign" olayı ile aynı.
void ABC::BeginPlay()
{
Super::BeginPlay();
// Karakterimin işaretçisini almak için cast ediyorum
AProjeKarakter* Karakter = Cast<AProjeKarakter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
Karakter->XPKazanildi.AddDynamic(this, &ABC::LogYazdir; // AddDynamic ile karakter XP kazandığı zaman LogYazdir adlı üye fonksiyonu çağrılacak.
}
// Diyelim ki log yazdirilacak üye fonksiyon bu şekilde tanımlanmış.
void ABC::LogYazdir(int32 XPMiktari)
{
UE_LOG(LogTemp, Warning, TEXT("Kazanilan XP: %d"), XPMiktari );
}
[/code-sh]
Çağıracağınız metodun argümanları delege ile aynı tip olmak zorundadır.
Dinamik delegeler ile karakter sınıfı üzerinden gerçekleşen bir olayı, başka bir aktörle birbirine bağladık. Aynı şekilde blueprint üzerinden geçerli karakter sınıfı referansınız ile bu delegeyi UMG Widget gibi olaylarda kullanabilirsiniz.
Öncelikle Delege nedir ondan bahsetmek istiyorum. Basit olarak delegeler ile çalışma zamanı içerisinde farklı sınıflar arasında olan olayları birbirine yayabilirsiniz. Diyelim ki karakterinizde olan bir olayı (mesela zıplaması) olayını yayarak, karakter zıpladığı anda başka bir sınıfta olan üye fonksiyonunu çağırabiliriz. Aynı zaman bu olayları aynı event dispatcher üzerinden olduğu gibi C++ yazdığımız delegeleri blueprint üzerine UPROPERTY(BlueprintAssignable) makrosu ile Blueprintler üzerinden çağırabilirsiniz.
Basit olarak delegelerin ne olduğunu anladığımıza göre nasıl uygulayacağımıza bakalım.
Delegeleri tanımlamak için
DECLARE_DYNAMIC_MULTICAST_DELEGATE_XParam makrosunu kullanırsınız. Buradaki X delegenizin kaç tane parametre aldığını belirtiyor.
Örnek olarak
Mesela diyelim ki int, float ve double tipinde üç parametreleri FDelegeIsmi adında bir delege makrosu tanımlayacak olursak
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FDelegeIsmi, int, int_parametresi, float, float_parametresi, double, double parametresi); // Bu makroyu kullanırken, veri tipleri ve parametrelerden sonra , gelir.
Sadece ilkel veri tipi değil, kendi yarattığınız veri tiplerini de delegeden parametre olarak geçirebilirsiniz.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FQuestCompletedEvent, int32, QuestID); // Bir parametreli
Eğer hiç parametre vermek istemiyorsanız
[size=small]DECLARE_MULTICAST_DELEGATE(FDelegenizinIsmi);
Dikkat ederseniz bu makro ilk olarak yaratacağınız delegenin bir imzasını alıyor. İmza olarak istediğiniz ismi verebilirsiniz ben örnek olarak F[size=small]DelegenizinIsmi dedim.
Daha sonradan dikkat ettiyseniz tipleri yazıktan sonra parametre isimlerini yazdım. Virgüllere dikkat edin, bu makro bu şekilde çalışıyor.
Pekala, nasıl tanımlayacağımızı anladığımıza göre örnekler yapalım. Diyelim ki Karaker XP kazandığında delege olarak tanımlayalım ve bu olay olunca başka bir Aktörde bir üye fonksiyon çağıralım.
Öncelikle bu delege karakter sınıfımızda olacağı için karakter sınıfının UCLASS() makrosunun üzerinde delegeyi tanımlamak zorundayız.
[code-sh=cpp] // delegeler UCLASS üzerindeki yere, yani buraya beyan etmek zorundasınız.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLevelAtlandi, int32, XP); // Delegeyi tanımladım, bir parametre alıyor o da var olan yeni seviye...
UCLASS()
class PROJENIZ_API AProjeKarakter : public ACharacter
{
public:
UPROPERTY(BlueprintAssignable, Category="Level") // Blueprintler üzerinden bu delege çağrılabilinir
FLevelAtlandi XPKazanildi; // Delegemizin örneğini sınıf içerisinde yerleştirdik..
UFUNCTION()
void XPEkle(int32 XPMiktari); // Bir üye fonksiyon olsun..
// devam ediyor...
[/code-sh]
Diyelim ki XP arttıran bir üye fonksiyonumuz var. Adı XPEkle olsun parametre olarak int32 XP alsın. Bu üye fonksiyonu çağrıldığında bu olayın, bütün dinleyicilere yayıldığını belirtmek için Broadcast kullanılır.
Üye fonksiyonunun tanımlaması şu şekilde olsun.
[code-sh=cpp] // Üye fonksiyonu
void AProjeKarakter::XPEkle(int32 XP)
{
// Broadcast basitçe bu delegeyi bütün dinleyicilere yaymak demek. Parametre olarak yaymak zorundasınız. Yani XPKazanildi olayı gerçekleşince bunu dinleyen bütün hepsine yayıyorum. Bu olayın gerçekleştiğini anlatıyor.
XPKazanildi.Broadcast(XP);
}
// XPKazanildi olayının bütün dinleyicileri bu fonksiyon devreye girdiği zaman işlerini yapabilecektir.
[/code-sh]
Diyelim ki bir ABC adında aktörümüz olsun ve xp kazanıldığı zaman basitçe bir Log mesajı versin. Bunun için genellikle BeginPlay üzerinde XP eklendiği zaman olayı dinamik bir şekilde aktarabilmesi için şu şekilde tanımlanması gerekir
[code-sh=cpp] // Oyuna başladığında dinamik olarak delgeye fonksiyonu bildiriyoruz. Blueprint üzerindeki "Assign" olayı ile aynı.
void ABC::BeginPlay()
{
Super::BeginPlay();
// Karakterimin işaretçisini almak için cast ediyorum
AProjeKarakter* Karakter = Cast<AProjeKarakter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
Karakter->XPKazanildi.AddDynamic(this, &ABC::LogYazdir; // AddDynamic ile karakter XP kazandığı zaman LogYazdir adlı üye fonksiyonu çağrılacak.
}
// Diyelim ki log yazdirilacak üye fonksiyon bu şekilde tanımlanmış.
void ABC::LogYazdir(int32 XPMiktari)
{
UE_LOG(LogTemp, Warning, TEXT("Kazanilan XP: %d"), XPMiktari );
}
[/code-sh]
Çağıracağınız metodun argümanları delege ile aynı tip olmak zorundadır.
Dinamik delegeler ile karakter sınıfı üzerinden gerçekleşen bir olayı, başka bir aktörle birbirine bağladık. Aynı şekilde blueprint üzerinden geçerli karakter sınıfı referansınız ile bu delegeyi UMG Widget gibi olaylarda kullanabilirsiniz.