Blaster davranışını uygulama, birinci şahıs nişancı deneyimlerinde bir patlama mekanizmasını programlama sürecidir. Oyuncular bir tıklama veya bir butonun basılmasıyla patlatma yapabilirken, tatmin edici ve doğru bir patlama davranışı oluşturmak önemlidir çünkü bu, oyuncuların genel oyun deneyiminden daha fazla zevk almasını sağlar.
örnek lazer tag deneyimi referans alındığında, bu öğretici bölümünde, blaster davranışını uygulamak için iki farklı tür blaster için arka plandaki scriptleri öğrenip aşağıdaki konularda rehberlik alacaksınız:
- Oyuncuların patlama butonuna bastıklarında bunu tespit etme.
- Oyuncunun, patlama butonuna yeni bastıysa blaster'ını kullanıp kullanamayacağını kontrol etme.
- Sunucuya kimin patlamayı başlattığını, patlamanın nereden geldiğini ve her bir lazer ışınının nihai varış noktasını bildiren patlama verisi oluşturma.
- Patlama verisini sunucuya bildirerek, patlama başka bir oyuncuyla çarpışmışsa uygun eylemleri gerçekleştirmesini sağlama.
- Her patlamadan sonra blaster'ı sıfırlayarak, blaster'ın yeniden patlamadan önce soğuması için yeterince zaman vermek.
Bu bölümü tamamladıktan sonra, blaster'ın patlamalarının diğer oyuncularla çarpıştığı zaman bunu tespit etmesine olanak sağlayan scriptleri öğrenecek ve ardından her blaster türüne göre uygun sağlık miktarını çıkaracaksınız.
Oyuncu girdisini denetleme
Blaster davranışını uygulamanın ilk adımı, bir oyuncunun patlama butonuna bastıklarında dinlemektir. Oyuncuların patlama butonuna basmak için kullandığı girdi türü, deneyime erişim sağladıkları cihaza bağlıdır. Örneğin, örnek lazer tag deneyimi fare ve klavye kontrollerini, oyun kumandalarını ve dokunmatik kontrolleri desteklemektedir. Bu girdi türlerinin her birini ReplicatedStorage ⟩ UserInputHandler içinde görebilirsiniz.
Bu istemci scripti, ContextActionService kullanarak MouseButton1 ve ButtonR2'yi patlama eylemine bağlar. Bu, her seferinde bir oyuncu ya sol fare düğmesine ya da bir oyun kumandasının R2 butonuna bastığında, blasterdan bir lazer ışınının patlamasını tetikler. Ayrıca, HUDGui'nin mobil cihazlarda patlama için bir butona sahip olduğunu ve bunu scriptte daha sonra bağlayacağını unutmayın.
UserInputHandlerContextActionService:BindAction("_", onBlasterActivated, false,Enum.UserInputType.MouseButton1,Enum.KeyCode.ButtonR2)
onBlasterActivated() tanımında Enum.UserInputState.Begin kullanımına da dikkat edilmelidir. Birçok kullanıcı arayüzü etkileşimi, bu örnekte olduğu gibi bir blaster seçerken, fare düğmesi açılana kadar (Enum.UserInputState.End) gerçekleşmez; bu da kullanıcılara etkileşimden kaçınma şansı verir. Ancak, bir patlama mekaniği, butonun aşağı indiği anda gerçekleşmezse duyarlı hissettirmiyor.
Bunu göstermek için, Enum.UserInputState.Begin'i Enum.UserInputState.End olarak değiştirip, oyun deneyiminin patlama yanıtının ne kadar etkilendiğini görmek için test edebilirsiniz. Örneğin, oyuncular butonu basılı tutabiliyorsa ancak patlamayı tetikleyemiyorlarsa, bu diğer oyuncuları etiketlerken deneyimlerini nasıl değiştirir?
UserInputHandler
local function onBlasterActivated(_actionName: string,
inputState: Enum.UserInputState, _inputObject: InputObject)
if inputState == Enum.UserInputState.End then -- güncellenmiş satır, geri değiştirmeyi unutmayın
attemptBlastClient()
end
end
Oyuncunun patlama yapıp yapamayacağını kontrol etme
UserInputHandler, bir buton basması veya ekran dokunması tespit ettikten sonra, ReplicatedStorage ⟩ Blaster ⟩ attemptBlastClient'ı çağırarak oyuncunun patlama yapıp yapamayacağını kontrol eder. Örnek lazer tag deneyimindeki çoğu kontrol gibi bu da iki kez gerçekleşir: önce istemciyle, sonra sunucuyla. attemptBlastClient, blasterStateClient oyuncu niteliğinin basit bir kontrolünü gerçekleştirmek için ReplicatedStorage ⟩ Blaster ⟩ canLocalPlayerBlast'ı çağırır:
canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return localPlayer:GetAttribute(PlayerAttribute.blasterStateClient) == BlasterState.Ready
end
ReplicatedStorage ⟩ Blaster ⟩ BlasterState'i incelediğinizde, deneyimin üç blaster durumu olduğunu görebilirsiniz: Ready, Blasting ve Disabled. Bu her bir durumun etkisini görmek için deneyimi test edebilir, Players hizmeti altında oyuncunuzu seçebilir ve ardından Properties penceresinde blasterStateClient niteliğini gözlemleyebilirsiniz. Patlama butonuna bastığınızda nasıl Disabled olduğuna, çoğu zaman Ready olduğuna ve patlama sırasında bir saniyeden kısa bir süre Blasting olduğuna dikkat edin.
Bu küçük duraklama, tıkladığınız kadar hızlı patlama yapmanızı engeller. Örneğin, fonksiyonu her zaman true döndürmeye değiştirirseniz, blaster'ınızı herhangi bir gecikme olmadan hızlıca patlatabilirsiniz ki bu da lazer tag oyunu için gerçekçi değildir.
canLocalPlayerBlast
local function canLocalPlayerBlast(): boolean
return true -- güncellenmiş satır, geri değiştirmeyi unutmayın
end
Patlama verisini oluşturma
Oyuncunun blaster'ının Ready durumunda olduğunu doğruladıktan sonra, attemptBlastClient, ReplicatedStorage ⟩ attemptBlastClient ⟩ blastClient'ı çağırır. blastClient'ın attığı ilk adım, blasterStateClient oyuncu niteliğini Blasting olarak ayarlamaktır; bu, daha önceki tam ateş durumunu engeller.
Sonraki adım, patlama verisini oluşturmaktır. Eğer ReplicatedStorage ⟩ Blaster ⟩ BlastData'yı inceleyerseniz, her patlamanın üç bilgi parçasından oluştuğunu görebilirsiniz:
- Patlamayı başlatan oyuncu.
- Patlamanın başlangıç noktasını temsil eden bir DataType.CFrame.
- Eğer başka bir oyuncuya çarpmışsa, her lazer ışınının nihai varışı ve vurulan oyuncuyu içeren bir RayResult tablosu.
Bu veriyi oluşturmak için, blastClient, ReplicatedStorage ⟩ attemptBlastClient ⟩ blastClient ⟩ generateBlastData'yı çağırır; bunu aşağıda inceleyebilirsiniz.
generateBlastData
local function generateBlastData(): BlastData.Type
local blasterConfig = getBlasterConfig()
local rayDirections = getDirectionsForBlast(
currentCamera.CFrame, blasterConfig)
local rayResults = castLaserRay(
localPlayer, currentCamera.CFrame.Position, rayDirections)
local blastData: BlastData.Type = {
player = localPlayer,
originCFrame = currentCamera.CFrame,
rayResults = rayResults,
}
return blastData
end
Bu fonksiyon, getBlasterConfig kullanarak oyuncunun blaster türünü alarak başlar. Örnek iki tür blaster sunar: bir tanesi geniş, yatay bir yayılma ile birkaç ışın üretir; diğeri ise tek bir ışın üretir. Bu yapılandırmaları ReplicatedStorage ⟩ Instances ⟩ LaserBlastersFolder içinde bulabilirsiniz.
Fonksiyon, patlama için başlangıç noktası olarak currentCamera.CFrame'i kullanır ve bunu getDirectionsForBlast'a aktarır. Bu noktada, kod blaster hakkında değildir, lazer ışını hakkında bir bilgidir; bununla daha fazla bilgi için öğreticinin vuruları tespit etme bölümünde daha fazla bilgi edineceksiniz. Son olarak, rayResults tablosunu oluşturduktan sonra, generateBlastData, blastClient'a patlama verisini döndürmek için ihtiyaç duyduğu tüm bilgiye sahiptir.
Sunucuya bildirme
blastClient patlama için eksiksiz veriye sahip olduğunda, iki olayı ateşler:
blastClientlocal laserBlastedBindableEvent = ReplicatedStorage.Instances.LaserBlastedBindableEventlocal laserBlastedEvent = ReplicatedStorage.Instances.LaserBlastedEventlaserBlastedBindableEvent:Fire(blastData)laserBlastedEvent:FireServer(blastData)
BindableEvent, patlamayı bildirmek için diğer istemci scriptlerini bilgilendirir. Örneğin, ReplicatedStorage ⟩ FirstPersonBlasterVisuals bu olayı patlama görsel efektlerini (patlama animasyonu ve soğuma çubuğu gibi) ne zaman görüntüleyeceğini bilmek için kullanır. Benzer şekilde, RemoteEvent, sunucu scriptlerini patlama hakkında bilgilendirir ve bu, patlamayı ServerScriptService ⟩ LaserBlastHandler içinde işlemeye başlar.
LaserBlastHandler
local function onLaserBlastedEvent(playerBlasted: Player, blastData: BlastData.Type)
local validatedBlastData = getValidatedBlastData(playerBlasted, blastData)
if not validatedBlastData then
return
end
if not canPlayerBlast(playerBlasted) then
return
end
blastServer(playerBlasted)
processTaggedPlayers(playerBlasted, blastData)
for _, replicateToPlayer in Players:GetPlayers() do
if playerBlasted == replicateToPlayer then
continue
end
replicateBlastEvent:FireClient(replicateToPlayer, playerBlasted, blastData)
end
end
Hileleri önlemek için sunucunun her istemciden gönderilen verileri doğrulaması gerekir. Bu kontroller şunları içerir:
- BlastData bir tablo mu? İçinde bir Class.CFrame ve başka bir rayResults adında bir tablo var mı?
- Oyuncuda bir blaster var mı?
- Oyuncunun bir karakteri ve dünyadaki bir yeri var mı?
- Patlama verisi gönderildikten sonra, oyuncu lazer ışınını patlattığı yerden aşırı bir mesafeye mi taşındı?
Bu son kontrol bir yargı meselesidir ve sunucu gecikmesi ile oyuncu hareket hızına bağlı olarak, kendi deneyiminiz için aşırı değerlerin ne olacağına karar verebilirsiniz. Bu yargının nasıl yapılacağına dair bir örnek vermek için, getValidatedBlastData içinde bir print ifadesi ekleyip deneyimi test edebilirsiniz.
getValidatedBlastDatalocal distanceFromCharacterToOrigin = blastData.originCFrame.Position - rootPartCFrame.Positionprint(distanceFromCharacterToOrigin.Magnitude) -- güncellenmiş satır, geri kaldırmayı unutmayınif distanceFromCharacterToOrigin.Magnitude > ToleranceValues.DISTANCE_SANITY_CHECK_TOLERANCE_STUDS thenwarn(`Player {player.Name} failed an origin sanity check while blasting`)returnend
Hareket ederken ve patlama yaparken, çıktıyı not edin. Çıktı şu şekilde görünebilir:
1.90196299552917483.15495586395263672.57428836822509774.80445861816406252.6434271335601807
Eğer ReplicatedStorage ⟩ PlayerStateHandler ⟩ togglePlayerMovement'taki hareket hızını artırırsanız, tekrar test ederken muhtemelen patlamalar arasındaki aşırı hareket nedeniyle birçok başarısız kontrol ile karşılaşacaksınız.
togglePlayerMovementlocal ENABLED_WALK_SPEED = 60 -- güncellenmiş satır, geri değiştirmeyi unutmayın
Sunucu daha sonra şunları yapar:
- rayResults'ı doğrular.
- Oyuncunun patlama yapıp yapamayacağını kontrol eder.
- Blaster durumunu sıfırlar.
- Etiketlenmiş oyuncular için sağlık seviyesini azaltır.
- Tüm diğer oyunculara patlamayı çoğaltarak, üçüncü şahıs görsellerini görmelerini sağlar.
Bu sunucu işlemleri hakkında daha fazla bilgi için öğreticinin vuruları tespit etme bölümüne bakabilirsiniz.
Blaster'ı sıfırlama
Örnek lazer tag deneyiminde, blaster'lar bir ısı mekaniği kullanıyor. Belirli bir sayıda patlamadan sonra yeniden doldurmak yerine, her patlamadan sonra "soğuması" için zamana ihtiyaç duyarlar. Bu soğuma süresi istemci (blastClient) ve sunucu (blastServer) üzerinde, sunucunun gerçekliğin kaynağı olmasıyla her iki yerde de gerçekleşmektedir.
blastServer
local blasterConfig = getBlasterConfig(player)
local secondsBetweenBlasts = blasterConfig:GetAttribute("secondsBetweenBlasts")
task.delay(secondsBetweenBlasts, function()
local currentState = player:GetAttribute(PlayerAttribute.blasterStateServer)
if currentState == BlasterState.Blasting then
player:SetAttribute(PlayerAttribute.blasterStateServer, BlasterState.Ready)
end
end)
secondsBetweenBlasts niteliği, ReplicatedStorage ⟩ Instances ⟩ LaserBlastersFolder içindeki blaster yapılandırmasının bir parçasıdır. secondsBetweenBlasts gecikmesi geçtikten sonra, oyuncu tekrar patlama yapabilir ve tüm süreç tekrar eder. Oyuncuya ne zaman tekrar patlama yapabileceğini anlatmak için, deneyimde bir soğuma çubuğu da bulunmaktadır.
Bu noktada, oyuncular doğabilir ve yeniden doğabilir, nişan alabilir ve patlayabilir, ancak deneyim hâlâ her bir patlamanın sonuçlarını belirlemek zorundadır. Öğreticinin bir sonraki bölümünde, patlamanın başka bir oyuncuya çarpıp çarpmadığını tespit etme yeteneğini programlamayı öğrenecek ve daha sonra blaster ayarlarına göre uygun sağlık miktarını azaltacaksınız.