Casuslara titreşimli bir görsel efekt eklemek için oyuncu karakterini art arda gösterip gizleyeceksin. Bir Casusun hasar aldığı her durumda bu efekt oluşmalıdır ancak aynı zamanda bu fonksiyon çağrıldığında kodunun geri kalanının çalışmaya devam ettiğinden emin olman gerekir. Birden fazla Casusunun olduğu zamanlarda bu durum çok daha karmaşık hale gelir. Bir oyun sırasında aynı anda hasar gören birden fazla Casus olabilir, bu yüzden her birini ayrı ayrı ele alabilen bir koda ihtiyacın olacak.
Bunu başarmak için spawn ifadesini yoğun bir şekilde kullanman gerekir. Bir fonksiyonu üretmek, kodunun geri kalanını beklemeye almadan fonksiyonu asenkron bir şekilde çalıştırmana olanak tanır. Her Casus için bir fonksiyon üreterek her Casusun diğerlerinden bağımsız şekilde titrediğinden emin olabilirsin.
Bir Casus hasar aldığında karakterini nasıl titreteceğini öğrenmek için bu adımları izle.
Titreme Döngüsünü Oluşturma
invisibility_managersınıf tanımınaFlickerCharacter()adlı yeni bir fonksiyon ekle. Bu fonksiyon birfort_characteralır ve karakterin görünüp kaybolarak titremesini sağlar. Bu fonksiyona<suspends>belirleyicisini ekleyerek asenkron şekilde çalışmasına izin ver.# Fort_character'ını yinelemeli şekilde gizleyip göstererek bir aracının (oyuncu veya AI) görünürlüğünü titretir FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() çağrıldı")FlickerCharacter()içinde,InCharacterüzerindeHide()döngüsü uygula, belirli bir süreSleep()çalıştır (daha önce tanımladığınFlickerRateSecondsboyunca), karaktereShow()uygula ve tekrar uyut. Bunu yaptığında; karakter üzerinde, düşman oyuncuların karakteri takip etmesine izin veren ancak kısa süreli görünmezlik nedeniyle zor nişan almalarına neden olan bir titreme efekti oluşturulur.# Fort_character'ını yinelemeli şekilde gizleyip göstererek bir aracının (oyuncu veya AI) görünürlüğünü titretir FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() çağrıldı") # Titreşim efekti oluşturmak için karakteri gizleme ve gösterme döngüsü. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds)Döngüyü Bozma
Karakterin titremesinin durması gerektiğinde bu döngü fonksiyonundan çıkmanın bir yolu gerekir. Daha önce oluşturduğun
PlayerVisibilitySecondseşleştirmesi bir oyuncunun daha ne kadar süre titreyeceğini takip eder. Her döngü sırasında bu süreyi azaltman gerekecektir. Kalan süre 0'a ulaştığında oyuncu titremeyi durdurur ve döngüden çıkabilirsin.InCharacter.GetAgent[]anahtarını kullanıpPlayerVisibilitySecondseşleştirmesine erişerek ve bu değeri birTimeRemainingdeğişkeninde depolayarak bir oyuncunun daha ne kadar süre titreyeceğini görebilirsin. DeğeriFlickerRateSeconds * 2kadar azaltarak aynı ifadede eşleştirmenin kalan süresini ayarlayabilirsin. BöyleceTimeRemaining,setifadesi çözümlendikten sonraPlayerVisibilitySecondsiçindeki değer olacaktır. Her döngüde iki kezSleep()çağrısı yaptığın içinFlickerRateSecondsdeğeri 2 ile çarpılmalıdır.# Fort_character'ını yinelemeli şekilde gizleyip göstererek bir aracının (oyuncu veya AI) görünürlüğünü titretir FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() çağrıldı") # Titreşim efekti oluşturmak için karakteri gizleme ve gösterme döngüsü. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds) # Her döngüde karakterin titreme miktarı FlickerRateSeconds kadar azalır. # Kalan süre 0'a ulaşırsa döngüden çık. if: TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2TimeRemainingdeğerinin 0’a eşit veya daha küçük olup olmadığını kontrol et. Bu değer, titremesini durdurmamız gereken karakteri gösterir. Bunu yapmak için karakter üzerindeHide()fonksiyonunu çağırarak karakteri tekrar görünmez yap vebreakfonksiyonuyla döngüden çık.FlickerCharacter()fonksiyonun şu şekilde görünmelidir:# Fort_character'ını yinelemeli şekilde gizleyip göstererek bir aracının (oyuncu veya AI) görünürlüğünü titretir FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() çağrıldı") # Titreşim efekti oluşturmak için karakteri gizleme ve gösterme döngüsü. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds) # Her döngüde karakterin titreme miktarı FlickerRateSeconds kadar azalır. # Kalan süre 0'a ulaşırsa döngüden çık. if: TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2 TimeRemaining <= 0.0 then: InCharacter.Hide() break
Titremeyi Başlatma ve Sıfırlama
Bir Casus zaten titriyorken hasar görürse ne olacağını düşün. Bu durumda sonraki her hasar örneği yeni bir fonksiyon üreteceğinden FlickerCharacter() fonksiyonları hızlıca kontrolden çıkabilir ve aynı karakter üzerinde düzinelerce fonksiyon çalışabilir. Bunun yerine, oyuncu her hasar aldığında oyuncunun PlayerVisibilitySeconds değeri sıfırlanmalıdır. Bunu yapmak için bir fonksiyon tanımlayarak oyuncunun titreyip titremediğini kontrol etmelisin. Titriyorsa oyuncunun titremesi gereken süreyi sıfırla. Titremiyorsa bu karakter için yeni bir titreme olayı üret.
invisibility_managersınıf tanımına, bir oyuncunun titreyip titremediğini belirlemek için kullanacağınIsFlickering()adlı yeni bir yardımcı fonksiyon ekle. Bu fonksiyon, bir aracıyı bağımsız değişken olarak alır vePlayerVisibilitySecondsdeğeri0.0sayısından daha büyüksetruedöndürür. Bu fonksiyonu hem başarısız olabilir hale getirmek hem de başarısızlık durumunda geri alınmasına izin vermek için fonksiyonadecidesvetransactsbelirleyicilerini ekle.# Oyuncunun titreme süresi kalıp kalmadığını döndürür IsFlickering(InAgent:agent)<decides><transacts>:void= PlayerVisibilitySeconds[InAgent] > 0.0invisibility_managersınıf tanımınaStartOrResetFlickering()adlı yeni bir fonksiyon ekle. Bu fonksiyon, bir aracıyı bağımsız değişken olarak alır ve bir oyuncunun titremeye başlaması veya titremeyi sıfırlaması gerektiğini belirler.# Aracı görünmezse yeni bir titreme olayı başlatır, görünmez değilse # aracının devam eden titremesini sıfırlar. StartOrResetFlickering(InAgent:agent):void=StartOrResetFlickering()dizisinde belirtilen aracının titremediğini kontrol et. Titremiyorsa bu aracı için yeni bir titreme olayı başlatman gerekir. Bu aracı içinfort_characterdeğerini al ve birFortCharacterdeğişkenine kaydet.# Aracı görünmezse yeni bir titreme olayı başlatır, görünmez değilse # aracının devam eden titremesini sıfırlar. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Bu karakter için YENİ FlickerEvent başlatmayı deniyor")PlayerVisibilitySecondsiçindeki aracının değeriniVulnerableSecondsolarak ayarla, sonra bu aracı içinFortCharacterdeğerini geçerek yeni birFlickerCharacter()fonksiyonunaspawnuygula.if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Bu karakter için YENİ FlickerEvent başlatmayı deniyor") # Yeni titreşim başlatıldı if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("Bu karakter için bir FlickerEvent üretildi")- Aracı zaten titriyorsa yalnızca
PlayerVisibilitySecondsiçindeki değeriniVulnerableSecondsolarak sıfırlaman gerekir. Daha öncekiFlickerCharacter()fonksiyonu, bu değeri asenkron bir şekilde okuduğu içinFlickerCharacter()döngüsü devam ederken değer sıfırlanırsabreakdevreye girmeden döngü devam eder.StartOrResetFlickering()fonksiyonun şu şekilde görünmelidir:# Aracı görünmezse yeni bir titreme olayı başlatır, görünmez değilse # aracının devam eden titremesini sıfırlar. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Bu karakter için YENİ FlickerEvent başlatmayı deniyor") # Yeni titreşim başlatıldı if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("Bu karakter için bir FlickerEvent üretildi") else: # Devam eden titreşimi sıfırla if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): Logger.Print("Karakterin FlickerTimer süresini VulnerableSeconds değerine sıfırla")
Hasar Gören Casusları Titretme
Bütün bu fonksiyonları birbirine bağlamak için bir Casus hasar gördüğünde ne olacağını belirleyen bir fonksiyon tanımlamalısın. FlickerCharacter() fonksiyonunda olduğu gibi, hasar alıp almadığını belirlemek için her bir Casusu ayrı ayrı takip etmen gerekir. Her Casus için bir fonksiyon üretebilmen amacıyla bu fonksiyonun asenkron olması gerekir.
invisibility_managersınıf tanımınaOnInfiltratorDamaged()adlı yeni bir fonksiyon ekle. Bu fonksiyon bir aracıyı alır ve bu aracı hasar gördüğündeStartOrResetFlickering()fonksiyonunu çağırır. Bu fonksiyona<suspends>belirleyicisini ekleyerek asenkron şekilde çalışmasına izin ver.# Bir aracı (oyuncu veya AI) hasar aldığında görünürlüğünü titretir OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Bu karakter için titretme başlatılmaya çalışıyor")- Geçerli oyun alanı için
fort_team_collectiondeğerini al ve birTeamCollectiondeğişkenine kaydet. Sonra aracının bu fonksiyona geçirilenfort_characterdeğerini al.# Bir aracı (oyuncu veya AI) hasar aldığında görünürlüğünü titretir OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Bu karakter için titretme başlatılmaya çalışıyor") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): - Bu fonksiyonun kendisine geçirilen aracıyı sürekli olarak izlemesi gerektiğinden döngüye girmesi şarttır. Bu döngü, belirtilen karakter her hasar aldığında çalışmalıdır ve fonksiyonun izlediği aracıda
StartOrResetFlickeringfonksiyonunu çağırır.OnInfiltratorDamagedfonksiyonuna bir döngü ekle.# Bir aracı (oyuncu veya AI) hasar aldığında görünürlüğünü titretir OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Bu karakter için titretme başlatılmaya çalışıyor") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop: - Döngünün içinde
IsVisibilityShareddeğerinin true olup olmadığını kontrol et. Değer true ise bu bir casus hasar gördüğünde takımdaki tüm casusların titremeye başlayacağı anlamına gelir. Bu ayar etkinse sırasıylaGetTeam[]veGetAgents[]fonksiyonlarını çağırarak hem bu aracının takımını hem de takımdaki oyuncuları al.if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): - Şimdi bir
fordöngüsünde her takım arkadaşı içinStartOrResetFlickeringçağrısı yap.if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Her bir takım arkadaşını PlayerVisibility saniye içinde ayarla ve bir FlickerEvent üret for(Teammate:TeamAgents): Logger.Print("Bir Takım Arkadaşı için StartOrResetFlickering çağrılıyor") StartOrResetFlickering(Teammate) - Görünürlük paylaşılmıyorsa bu fonksiyonun izlediği aracı için
StartOrResetFlickeringçağrısı yap.loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Her bir takım arkadaşını PlayerVisibility saniye içinde ayarla ve bir FlickerEvent üret for(Teammate:TeamAgents): Logger.Print("Bir Takım Arkadaşı için StartOrResetFlickering çağrılıyor") StartOrResetFlickering(Teammate) else: # Sadece hasar gören karakteri titret Logger.Print("InAgent için StartOrResetFlickering çağrılıyor") StartOrResetFlickering(InAgent) - Döngünün sonunda son olarak ilgili karakterin
DamagedEvent()değerineAwait()uygula. Bu şekilde döngü yalnızca bir karakter hasar gördüğünde yinelenir. Fonksiyon başladığında bu döngünün en az bir kez çalışacağını unutma. Yani en az birStartOrResetFlickering()çağrısı yapılacaktır. Bunun sonucunda casuslar oyuna titreyerek başlar, sonra görünmez olurlar. Bu durum, casuslara görünmez olduklarını ve aynı zamanda görünmezliğin kalıcı olmadığını hatırlatmaya yardımcı olur.OnInfiltratorDamaged()fonksiyonun şu şekilde görünmelidir:# Bir aracı (oyuncu veya AI) hasar aldığında görünürlüğünü titretir OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Bu karakter için titretme başlatılmaya çalışıyor") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Her bir takım arkadaşını PlayerVisibility saniye içinde ayarla ve bir FlickerEvent üret for(Teammate:TeamAgents): Logger.Print("Bir Takım Arkadaşı için StartOrResetFlickering çağrılıyor") StartOrResetFlickering(Teammate) else: # Sadece hasar gören karakteri titret Logger.Print("InAgent için StartOrResetFlickering çağrılıyor") StartOrResetFlickering(InAgent) FortCharacter.DamagedEvent().Await()
Oyun Başlangıcında Karakterler İçin Fonksiyonlar Üretme
StartInvisibilityManager() fonksiyonuna döndüğünde bir oyuncunun karakteri için Hide() çağrısı yapmadan önce o karakter için bir OnInfiltratorDamaged() fonksiyonu üret. Bu şekilde her casusun kendisini asenkron bir şekilde izleyen ve titremesiyle ilgili tüm mantığı işleyen bir fonksiyonu olur. StartInvisibilityManager() şu şekilde görünmelidir:
StartInvisibilityManager<public>(AllTeams:[]team, AllPlayers:[]player, Infiltrators:team):void=
Logger.Print("Görünmezlik kodu başlatıldı!")
set Teams = GetPlayspace().GetTeamCollection().GetTeams()
for(PlayerSpawner:PlayersSpawners):
PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
# Bir oyuncu casus takımında doğduysa o oyuncu için bir OnInfiltratorDamaged fonksiyonu
# oluştur. Ardından, karakterini görünmez yap.
for (TeamPlayer:AllPlayers):
if:
FortCharacter:fort_character = TeamPlayer.GetFortCharacter[]
CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]
Logger.Print("Bu oyuncunun geçerli takımı alındı")
Teams[0] = CurrentTeam
set PlayerVisibilitySeconds[TeamPlayer] = 0.0
Logger.Print("Oyuncu PlayerVisibilitySeconds değerine eklendi")
then:
spawn{OnInfiltratorDamaged(TeamPlayer)}
Logger.Print("Oyuncu bir casus olarak doğdu, bu da onu görünmez yapıyor")
FortCharacter.Hide()
else:
Logger.Print("Bu oyuncu bir casus değil")
Kodu kaydet, derle ve bölüme oynanış testi uygulamak için UEFN araç çubuğunda Oturumu Başlat düğmesine tıkla. Bölümüne oynanış testi yaptığında kodun başlatılmasıyla her Casus titremeli, sonra görünmez olmalıdır. Casus hasar aldıktan sonra, IsVisibilityShared fonksiyonunu ayarladığın değere bağlı olarak tek başına ya da takım halinde titremelidir.

Sonraki Adım
Bu eğitimin sonraki adımında sürmekte olan oyuna katılan oyuncuları nasıl işleyeceğini öğreneceksin.