Menu
CoddyTech

Sang Pahlawan

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

Bab ini membangun Arena Survivor, game terakhir dalam perjalanan ini. Gelombang musuh menyerbu arena berpagar dan kamu melawan mereka dengan pedang: grunts yang berjalan ke arahmu, serta orb yang menunggu lalu menerjang. Gelombang yang dikalahkan meninggalkan power-up, HUD menampilkan kesehatanmu dan gelombang saat ini, dan saat kesehatanmu habis, sesi permainan berakhir dan sesi terbaikmu disimpan. Game ini menggunakan alat dari bagian ini saat sesuai: Enemy abstrak dengan dua jenis, IDamageable untuk segala sesuatu yang bisa terkena serangan, gelombang sebagai aset ScriptableObject, pickup di balik interface, HUD yang hanya mendengarkan event C#, dan penyimpanan JSON. Semua dua belas skrip sudah ada di proyek sejak awal. Baru Hero yang memiliki kode, dan setiap pelajaran menambahkan lebih banyak kode.

Pedang hero mengenai sasaran yang ada di depannya, jadi ayunannya perlu memeriksa apakah sasaran berada "di depan". Vector3.Dot(a, b) mengalikan bagian-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" menjadi "hasil dot minimal 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 tersebut, tetapi toPlayer sepanjang jaraknya, jadi nilainya dinormalisasi terlebih dahulu; jika tidak, pemain yang jaraknya dua kali lebih jauh akan menghasilkan nilai dot dua kali lebih besar. Nilai y-nya diatur ke 0 sebelum itu, jadi posisi pemain di jalur yang lebih tinggi dihitung berdasarkan letaknya di peta, bukan ketinggiannya. Tandanya membedakan arah depan dan belakang: nilai dot di atas 0 berarti berada di bagian depan, sedangkan nilai di bawah 0 berarti berada di belakang.

challenge icon

Tantangan

Sedang

Mulai Arena Survivor dengan pedang hero. Cara berjalan ditulis seperti ini: action Move menggerakkan hero dengan SimpleMove dan memutarnya agar menghadap ke arah ia berjalan. Lima boneka latihan dengan tag Enemy berdiri di sekelilingnya. Inspector memberi Hero nilai reach (2) dan swingCooldown (0.5), serta tebasan yang ditampilkan saat hero mengayunkan pedang.

  • Menekan Space atau mengeklik kiri akan mengayunkan pedang, paling banyak sekali setiap swingCooldown detik: menekan tombol sebelum cooldown selesai tidak akan melakukan apa pun. Baca tombol dengan Keyboard.current dan Mouse.current, lalu panggil Swing().
  • Di dalam Swing(), setelah tebasan ditampilkan, hancurkan setiap object bertag Enemy yang berada dalam jangkauan reach dan di depan hero. Dalam jangkauan berarti collider apa pun yang ditemukan Physics.OverlapSphere di sekitar hero dengan radius reach. Di depan berarti nilai dot antara arah depan hero dan arah menuju object di sepanjang permukaan tanah minimal 0.5: hingga 60 derajat ke kedua sisi.

Biarkan script lainnya seperti semula. Tekan Play, berjalanlah mendekati boneka latihan lalu ayunkan pedang, kemudian tekan 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;

    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 bertanda Enemy dalam jangkauan reach dan di depan pahlawan
    }

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

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Arsitektur Game di Unity