U
18 / 22 · 9 phút
Hỏi đáp

Instantiate: sinh prefab, và tái sử dụng chúng

câu trả lời ngắn

Làm sao sinh object bằng code?

Biến thứ đó thành prefab, giữ tham chiếu tới nó trong một trường public, rồi gọi Instantiate(prefab, position, rotation). Kéo prefab từ bảng Project vào trường đó — kéo nhầm bản đang nằm trong Hierarchy là lỗi gây ra một nửa số bug của spawner.

Sinh vật thể chỉ gồm một hàm, Instantiate, cộng một thói quen quyết định nó chạy hay không: thứ bạn sinh ra phải là prefab lấy từ bảng Project, không phải bản đang nằm trong cảnh.

Tạo prefab trước đã

  1. 1

    Dựng vật thể trong cảnh cho tới khi nó đúng y thứ bạn muốn sinh ra — mesh, material, collider, script, đủ cả.

  2. 2

    Kéo nó từ Hierarchy vào Assets/Prefabs. Tên chuyển sang màu xanh: giờ nó là prefab, và nó nằm trên ổ cứng.

  3. 3

    Xoá bản còn lại trong cảnh đi. Prefab mới là bản gốc; bản trong cảnh chỉ là thêm một kẻ địch đứng sẵn lúc khởi động.

Instantiate

Spawner.cs — drag the PREFAB into the slot, not the scene object
using UnityEngine;

public class Spawner : MonoBehaviour
{
    public GameObject prefab;
    public Transform parent;        // tuỳ chọn, giữ Hierarchy gọn gàng
    public float interval = 1.5f;

    float next;

    void Update()
    {
        if (Time.time < next) return;
        next = Time.time + interval;

        Vector3 where = transform.position + Random.insideUnitSphere * 3f;
        where.y = transform.position.y;

        GameObject spawned = Instantiate(prefab, where, Quaternion.identity, parent);

        // Instantiate trả về bản sao mới. Hãy cấu hình bản đó, đừng đụng prefab —
        // ghi vào prefab.something là sửa thẳng vào file trên ổ cứng.
        spawned.name = "Enemy " + Time.frameCount;
    }
}

Ba thứ hay quên

  • Instantiate chép lại tất cả, kể cả scale của prefab và các object con. Nếu vật sinh ra sai kích thước thì chính prefab đang sai kích thước.

  • Truyền parent giúp Hierarchy dễ nhìn, nhưng vật sẽ thừa hưởng scale của cha. Hãy gắn vào thứ có scale 1, hoặc sinh ra không kèm cha rồi gọi SetParent(parent, true) sau đó.

  • Quaternion.identity nghĩa là không xoay. Viết transform.rotation vào đó thì mọi vật sinh ra quay cùng hướng với spawner, và thường đó mới là thứ bạn muốn.

Destroy, và vì sao spawner làm tụt khung hình

Mỗi lần Instantiate là một lần cấp phát, và mỗi lần Destroy là một mớ rác để lại cho bộ dọn rác. Spawner chạy mỗi khung hình sẽ làm điện thoại giật trong vòng một phút. Với đạn và hiệu ứng — thứ xuất hiện hàng trăm lần — hãy tái sử dụng thay vì tạo mới.

The smallest pool that is worth having
using System.Collections.Generic;
using UnityEngine;

public class SimplePool : MonoBehaviour
{
    public GameObject prefab;
    readonly Queue<GameObject> idle = new();

    public GameObject Get(Vector3 at)
    {
        GameObject go = idle.Count > 0 ? idle.Dequeue() : Instantiate(prefab);
        go.transform.position = at;
        go.SetActive(true);
        return go;
    }

    // Gọi hàm này thay cho Destroy.
    public void Release(GameObject go)
    {
        go.SetActive(false);
        idle.Enqueue(go);
    }
}

bài học làm ra thứ này

Sinh lưới khối bằng code

Bài này là một công thức đứng riêng. Trong khoá học, cùng thứ đó được dựng như một phần của dự án xuyên suốt năm tab — Căn bản, bài 08.