Kahraman
Coddy'nin Unity Journey'sinin Unity'de Oyun Mimarisi bölümünün bir parçası. Ders 41 / 50.
Bu bölüm, yolculuğun son oyunu olan Arena Survivor'ı geliştiriyor. Düşman dalgaları duvarlarla çevrili bir arenaya akın ediyor ve sen kılıçla onları püskürtüyorsun: sana doğru yürüyen piyadeler ve bekleyip sonra atılan küreler. Yenilen bir dalga bir güçlendirme bırakıyor, HUD sağlığını ve dalgayı gösteriyor; sağlığın tükendiğinde oyun sona eriyor ve en iyi oyun kaydediliyor. Oyun, bu bölümdeki araçları uygun oldukları yerlerde kullanıyor: iki türü olan soyut bir Enemy, zarar görebilecek her şey için IDamageable, ScriptableObject varlığı olarak dalgalar, bir arayüzün arkasındaki toplanabilir güçlendirmeler, yalnızca C# olaylarını dinleyen bir HUD ve JSON kaydı. On iki betiğin tümü en baştan projede yer alıyor. Şimdilik yalnızca Hero kod içeriyor ve her ders daha fazlasını ekliyor.
Kahramanın kılıcı önündeki şeylere isabet eder, bu yüzden kılıç savuruşunun "önde" olup olmadığını sınaması gerekir. Vector3.Dot(a, b) iki vektörün karşılık gelen bileşenlerini çarpar ve sonuçları toplar: a.x * b.x + a.y * b.y + a.z * b.z. Uzunlukları 1 olan iki yön için bu, aralarındaki açının kosinüsüdür: aynı yönü gösterdiklerinde 1, 30 derecede 0.866, 45 derecede 0.707, dik açıda 0 ve zıt yönü gösterdiklerinde -1. Böylece "baktığım yönden en fazla 30 derece uzakta" ifadesi, hesaplanacak bir açı olmadan "noktasal çarpım en az 0.866" hâline gelir. Bu nöbetçi robot, oyuncu 10 birim yakınında ve 30 derecelik görüş alanının içindeyken alarmı çalıştırır:
public Transform player;
public float range = 10f;
void Update()
{
Vector3 toPlayer = player.position - transform.position;
toPlayer.y = 0f;
bool near = toPlayer.magnitude <= range;
bool inView = Vector3.Dot(transform.forward, toPlayer.normalized) >= 0.866f;
if (near && inView)
{
Debug.Log("Alarm!");
}
}Her iki yönün de uzunluğu 1 olmalıdır. transform.forward her zaman bu uzunluktadır, ancak toPlayer uzaklık kadar uzundur; bu yüzden önce normalize edilir. Aksi hâlde iki kat uzaktaki bir oyuncu, noktasal çarpımın iki kat olmasına neden olurdu. Bundan önce y değeri 0 olarak ayarlanır; böylece daha yüksek bir yürüyüş yolundaki oyuncu, ne kadar yüksekte olduğuna göre değil, haritada durduğu konuma göre hesaba katılır. İşaret, önü arkadan ayırır: 0'dan büyük noktasal çarpım ön yarım dairenin herhangi bir yerini, 0'dan küçük olan ise arka tarafın herhangi bir yerini gösterir.
Görev
OrtaArena Survivor'a kahramanın kılıcıyla başla. Yürüme şöyle yazılır: Move eylemi, SimpleMove ile kahramanı yürütür ve yürüdüğü yöne bakmasını sağlar. Etrafında Enemy etiketi taşıyan beş eğitim mankeni durur. Inspector, Hero için reach (2) ve swingCooldown (0.5) değerlerini ve savuruş sırasında gösterdiği kılıç darbesi efektini ayarlar.
- Space tuşuna basmak veya sol tıklamak savuruş yapar; bu,
swingCooldownsaniyede en fazla bir kez gerçekleşir: bekleme süresi bitmeden yapılan bir basış hiçbir şey yapmaz. TuşlarıKeyboard.currentveMouse.currentile oku veSwing()çağrısını yap. Swing()içinde, kılıç darbesi gösterildikten sonrareachmesafesinde ve kahramanın önünde bulunanEnemyetiketli her nesneyi yok et. Erişme mesafesi içinde olmak,Physics.OverlapSphere'ın kahramanın etrafındareachyarıçapıyla bulduğu herhangi bir çarpıştırıcı demektir. Önde olmak, kahramanın ileri yönü ile nesneye doğru, zemin boyunca olan yön arasındaki nokta çarpımının en az 0.5 olması demektir: her iki yana doğru en fazla 60 derece.
Diğer betikleri olduğu gibi bırak. Play'e bas, mankenlere doğru yürü ve savuruş yap, ardından Kontrol Et'e bas.
Kendin dene
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
public class Hero : MonoBehaviour
{
[SerializeField] private float speed = 5f;
[SerializeField] private float reach = 2f;
[SerializeField] private float swingCooldown = 0.5f;
[SerializeField] private GameObject slash;
private CharacterController controller;
private InputAction moveAction;
void Start()
{
controller = GetComponent<CharacterController>();
moveAction = InputSystem.actions.FindAction("Move");
}
void Update()
{
Vector2 input = moveAction.ReadValue<Vector2>();
Vector3 move = new Vector3(input.x, 0f, input.y);
controller.SimpleMove(move * speed);
if (move != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(move);
}
// Space tuşu veya sol tıklama saldırı yapar; en fazla swingCooldown saniyede bir kez
}
void Swing()
{
StartCoroutine(ShowSlash());
// kahramanın önünde ve reach mesafesinde bulunan, Enemy etiketi taşıyan her şeyi yok et
}
IEnumerator ShowSlash()
{
slash.SetActive(true);
yield return new WaitForSeconds(0.1f);
slash.SetActive(false);
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Unity'de Oyun Mimarisi bölümündeki tüm dersler
1Hiyerarşiler Değil, Bileşenler
Küçük BileşenlerTemel Bir Düşman BetiğiSoyut BileşenlerBirlikte Çalışan BileşenlerÖzet: Modüler Taret4Serileştirilmiş Veriler
Serileştirilebilir SınıflarInspector'da ListelerInspector'da Enum'larÖzet: Ganimet Tablosu7Durum Makineleri
Sınıflar Olarak DurumlarBir Durum MakinesiGeçişlerDüşmanların Yapay ZekâsıTekrar: Kapı Durumları10Proje: Arena Hayatta Kalma
KahramanDüşman Türleri5ScriptableObjects
Veri VarlıklarıSilah İstatistikleriPaylaşılan AyarlarVeri Olarak DalgalarTekrar: Eşya Veritabanı8Yeniden Kullanılabilir Kod
Genişletme MetotlarıGeneric SingletonGeneric YardımcılarTekrar: FindNearest