Kahraman
Coddy'nin Unity Journey'sinin Unity'de Oyun Mimarisi bölümünün bir parçası. Ders 50 / 64.
Bu bölümde kursun son oyunu olan Arena Survivor'ı geliştiriyoruz. Düşman dalgaları duvarlarla çevrili bir arenaya akın eder ve sen onlarla kılıçla savaşırsın: sana doğru yürüyen piyadeler ve bekleyip ardından atılan küreler. Yenilen bir dalga güçlendirme bırakır, bir HUD sağlığını ve dalgayı gösterir; sağlığın tükendiğinde koşu sona erer ve en iyi koşun kaydedilir. Oyun, bu bölümdeki araçları uygun oldukları yerlerde kullanır: 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 eşya toplamaları, yalnızca C# olaylarını dinleyen bir HUD ve bir JSON kaydı. On iki betiğin tümü en baştan projededir. Şimdilik yalnızca Hero çalışır; diğerleri daha sonraki bir dersin ihtiyaç duyacağı alanları içerir ve her ders bunlara yenilerini ekler.
Hero'nun kılıcı önündeki hedeflere vurur, bu yüzden kılıç darbesinin "önde olma" durumunu test etmesi 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. Uzunluğu 1 olan iki yön için bu değer, 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çılarda 0 ve zıt yönleri gösterdiklerinde -1 olur. Böylece "baktığım yönden en fazla 30 derece sapmış" ifadesi, açıyı hesaplamaya gerek kalmadan "noktasal çarpım en az 0.866" anlamına gelir. Bu nöbetçi robot, oyuncu 10 birim mesafede ve 30 derecelik görüş alanının içindeyken alarm verir:
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 uzunluğa sahiptir, ancak toPlayer vektörünün uzunluğu mesafe kadardır; bu yüzden önce normalize edilir. Aksi hâlde iki kat uzaktaki bir oyuncu noktasal çarpım sonucunu iki katına çıkarırdı. Oyuncu daha yüksek bir yürüyüş yolunda duruyorsa, konumu yüksekliğine göre değil haritadaki yerine göre hesaplansın diye y değeri bundan önce 0 yapılır. İşaret, ön tarafı arka taraftan ayırır: noktasal çarpım 0'dan büyükse ön yarım alanın herhangi bir yerindedir, 0'dan küçükse arka tarafta herhangi bir yerdedir.
Görev
OrtaKur kahramana bir kılıç ver.
Update()içinde, Space tuşuna basıldığında veya sol tıklama yapıldığında veTime.time >= nextSwingolduğunda,nextSwing = Time.time + swingCooldown;değerini ayarla veSwing()çağrısını yap.Swing()içinde,Physics.OverlapSphere(transform.position, reach)üzerinde döngü oluştur.Enemyetiketi taşıyan ve düz yönütoHit(y değeri 0'a ayarlanmış) içinVector3.Dot(transform.forward, toHit.normalized) >= 0.5fkoşulunu sağlayan her vuruşu yok et.
“Oyna” düğmesine bas ve kılıcı salla: öndeki mankenler kaybolur. Ardından “Kontrol et” düğmesine 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;
private float nextSwing;
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şuna basmak veya sol tıklamak, swingCooldown saniyede en fazla bir kez saldırı yapar
}
void Swing()
{
StartCoroutine(ShowSlash());
// kahramanın önünde, reach mesafesi içinde bulunan ve Enemy etiketi taşıyan her şeyi yok et
}
IEnumerator ShowSlash()
{
slash.SetActive(true);
yield return new WaitForSeconds(0.1f);
slash.SetActive(false);
}
}
Unity'de Oyun Mimarisi bölümündeki tüm dersler
1Kalıtım Değil, Bileşenler
Küçük BileşenlerTemel Düşman Script'iSoyut BileşenlerBirlikte Çalışan BileşenlerTekrar: Modüler TaretTekrar: Çift Namlulu Top4Serileştirilmiş Veriler
Serileştirilebilir SınıflarInspector'da ListelerInspector'da Enum'larTekrar: Ganimet TablosuTekrar: Ganimeti At2Unity'de Arayüzler
IDamageableArayüzler ve TryGetComponentGetComponentsÖzet: Etkileşim TuşuÖzet: Erişim Mesafesindeki En Yakın5ScriptableObjects
Veri VarlıklarıSilah İstatistikleriOrtak AyarlarRüzgârı KaydetVeri Olarak DalgalarTekrar: Eşya VeritabanıTekrar: Dükkândan Satın Al8Yeniden Kullanılabilir Kod
Genişletme MetotlarıGeneric SingletonGeneric YardımcılarTekrar: FindNearestKendi başına pratik yap: Unity playground