Menu
CoddyTech

Sang Pahlawan

Termasuk bagian Arsitektur Game di Unity dalam perjalanan Unity di Coddy. Pelajaran 50 dari 64.

Bab ini membangun Arena Survivor, game terakhir dalam kursus. Gelombang musuh menyerbu arena berdinding dan kamu melawan mereka dengan pedang: grunt yang berjalan ke arahmu, dan orb yang menunggu lalu menerjang. Gelombang yang dikalahkan meninggalkan power-up, HUD menampilkan kesehatanmu dan gelombang saat ini, lalu saat kesehatanmu habis, permainan berakhir dan permainan terbaikmu disimpan. Game ini menggunakan alat dari bagian ini saat sesuai: Enemy abstrak dengan dua jenis, IDamageable untuk segala sesuatu yang bisa terluka, gelombang sebagai aset ScriptableObject, pickup yang menggunakan interface, HUD yang hanya mendengarkan event C#, dan penyimpanan JSON. Semua dua belas skrip sudah ada di proyek sejak awal. Hanya Hero yang berfungsi saat ini; skrip lainnya memiliki field yang dibutuhkan pelajaran berikutnya, dan setiap pelajaran akan melengkapinya lebih lanjut.

Pedang hero mengenai apa pun yang ada di depannya, jadi ayunannya perlu menguji apakah sesuatu berada "di depan". Vector3.Dot(a, b) mengalikan bagian yang bersesuaian dari dua vektor lalu menjumlahkannya: a.x * b.x + a.y * b.y + a.z * b.z. Untuk dua arah dengan panjang 1, hasilnya adalah kosinus sudut di antara keduanya: 1 saat keduanya menunjuk ke arah yang sama, 0.866 pada 30 derajat, 0.707 pada 45 derajat, 0 pada sudut siku-siku, dan -1 saat keduanya menunjuk ke arah yang berlawanan. Jadi, "dalam jarak 30 derajat dari arah hadapku" berarti "hasil dot setidaknya 0.866", tanpa perlu menghitung sudut. Robot penjaga ini membunyikan alarm saat pemain berada dalam jarak 10 unit dan di dalam bidang pandang 30 derajatnya:

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!");
    }
}

Kedua arah harus memiliki panjang 1. transform.forward selalu memiliki panjang itu, tetapi toPlayer sepanjang jarak, jadi nilainya dinormalisasi terlebih dahulu; jika tidak, pemain yang jaraknya dua kali lebih jauh akan menghasilkan dot dua kali lipat. Nilai y-nya diatur menjadi 0 sebelum itu, jadi posisi pemain di jalur yang lebih tinggi dihitung berdasarkan letaknya di peta, bukan ketinggiannya. Tanda hasilnya membedakan depan dan belakang: dot di atas 0 berarti berada di bagian depan, sedangkan di bawah 0 berarti berada di bagian belakang.

challenge icon

Tantangan

Sedang

Beri hero sebuah pedang.

  1. Di dalam Update(), saat Space atau klik kiri ditekan dan Time.time >= nextSwing, atur nextSwing = Time.time + swingCooldown; lalu panggil Swing().
  2. Di dalam Swing(), lakukan perulangan pada Physics.OverlapSphere(transform.position, reach).
  3. Hancurkan setiap objek yang terkena dan memiliki tag Enemy, dengan arah datar toHit (y diatur ke 0) yang menghasilkan Vector3.Dot(transform.forward, toHit.normalized) >= 0.5f.

Tekan tombol “Main” lalu ayunkan pedang: boneka latihan di depan akan lenyap. Lalu tekan tombol “Periksa”.

Coba sendiri

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);
        }

        // Tekan Space atau klik kiri untuk mengayun, paling sering sekali setiap swingCooldown detik
    }

    void Swing()
    {
        StartCoroutine(ShowSlash());
        // Hancurkan semua yang bertag Enemy dalam jangkauan dan di depan hero
    }

    IEnumerator ShowSlash()
    {
        slash.SetActive(true);
        yield return new WaitForSeconds(0.1f);
        slash.SetActive(false);
    }
}

Semua pelajaran di Arsitektur Game di Unity

Latihan sendiri: Playground Unity