Làm cách nào tôi có thể nhận được tất cả các GameObjects của DontDestroyOnLoad?


7

Tôi cần phải tiêu diệt tất cả các DontDestroyOnLoadGameObject. Nhưng để làm được điều này, trước tiên tôi cần tìm ra tất cả. Tôi muốn tự động hóa điều này, trái ngược với việc phải tham khảo thủ công từng cái một.

DontDestroyOnLoadGameObjects dường như đều nằm trong cảnh được chia sẻ , "DontDestroyOnLoad". Vì vậy, tôi đã cố gắng thu thập tất cả các GameObject gốc từ Cảnh này, nhưng nó nói rằng đó là một cảnh không hợp lệ.

private void DestroyDontDestroyOnLoadGameObjects()
{
    var dontDestoyOnLoadScene = SceneManager.GetSceneByName("DontDestroyOnLoad");
    var dontDestroyOnLoadGameObjects = dontDestoyOnLoadScene.GetRootGameObjects();
    foreach (var dontdestroyGameObject in dontDestroyOnLoadGameObjects)
    {
        Destroy(gameObject);
    }
}

nhập mô tả hình ảnh ở đây

Làm cách nào tôi có thể Tiêu diệt tất cả các GameObject đã DontDestroyOnLoadkêu gọi họ?

Câu trả lời:


8

Đây là một phương pháp hackish táo tợn chỉ hoạt động trong Trình chỉnh sửa . Chúng tôi không thể tìm thấy cảnh DontDestroyOnLoad theo tên, nhưng mỗi GameObject của DontDestroyOnLoad'ed đều có tham chiếu đến nó. Vì vậy, nếu chúng ta có một tham chiếu đến chỉ một đối tượng như vậy (hoặc tạo một đối tượng như vậy) thì chúng ta có thể nhận được tất cả chúng:

public void DestroyAllDontDestroyOnLoadObjects() {

   var go = new GameObject("Sacrificial Lamb");
   DontDestroyOnLoad(go);

   foreach(var root in go.scene.GetRootGameObjects())
       Destroy(root);

}

Bạn có thể tránh việc tạo một đối tượng hy sinh mỗi khi bạn cần thao tác trên danh sách các đối tượng này bằng cách tham chiếu một đối tượng như vậy mà bạn biết bạn sẽ luôn tồn tại (giả sử, đối tượng người quản lý mà chính tập lệnh này cư trú) hoặc bằng cách thực hiện nghi thức hiến tế một lần đầu khi chạy và lưu trữ một tham chiếu đến cảnh để sử dụng từ đó trở đi (trong các thử nghiệm của tôi, nó vẫn còn hiệu lực ngay cả sau khi tất cả các đối tượng của nó đã bị phá hủy và các đối tượng mới được đánh dấu DDOL)

Lưu ý rằng theo các tài liệu, thủ thuật này sẽ không hoạt động trong một trò chơi được xây dựng :

Bạn không có quyền truy cập vào cảnh DontDestroyOnLoad và nó không có sẵn trong thời gian chạy.

Cố gắng truy cập cảnh này sẽ ném một ngoại lệ phàn nàn rằng cảnh đó không hợp lệ.


Nếu sự hy sinh theo nghi thức làm bạn đau bụng (với lý do chính đáng, tôi sẽ nói) hoặc nếu bạn cần điều này trong thời gian chạy trong một trò chơi được xây dựng , một cách tiếp cận thông thường hơn sẽ là giới thiệu một DontDestroyOnLoadManager như thế này:

public static class DontDestroyOnLoadManager
{
    static List<GameObject> _ddolObjects = new List<GameObject>();

    public static void DontDestroyOnLoad(this GameObject go) {
       UnityEngine.Object.DontDestroyOnLoad(go);
       _ddolObjects.Add(go);
    }

    public static void DestroyAll() {
        foreach(var go in _ddolObjects)
            if(go != null)
                UnityEngine.Object.Destroy(go);

        _ddolObjects.Clear();
    }
}

Sau đó, bạn có thể thay thế bất kỳ trường hợp DontDestroyOnLoad(someObject)nào khác trong cơ sở mã của bạn bằng someObject.DontDestroyOnLoad()(ở đây tôi đang sử dụng một phương thức mở rộng để giữ cho nó ngắn gọn, nhưng bạn cũng có thể gọi nó một cách rõ ràng thông qua lớp người quản lý của bạn). Việc này kết thúc DontDestroyOnLoad riêng và cũng thực hiện việc ghi sổ cần thiết để tìm tất cả các đối tượng đó sau này. Nhược điểm là nếu bạn có các tập lệnh & plugin bên thứ 3 bổ sung gọi DontDestroyOnLoad, bạn cần sửa đổi chúng để được hệ thống này theo dõi.


Tài giỏi! Cảm ơn! Không phải là người đầu tiên làm việc trong thời gian chạy?
Evorlor

Không, không phải trong trò chơi được xây dựng. Tôi đã thử nó và nó ném ngoại lệ, như đã lưu ý trong câu trả lời. Sẽ rất tuyệt nếu điều đó xảy ra, nhưng thành thật mà nói, nó không gây ngạc nhiên như thế nào. ;)
DMGregory

ah, tôi không thấy chỉnh sửa. cũng cảm ơn một lần nữa cho một câu trả lời tuyệt vời khác của bạn!
Evorlor

Tôi nghĩ rằng nó lạc hậu. Bạn chỉ có thể chỉnh sửa cảnh trong thời gian chạy. Từ URL của bạn: Cross-Scene references are not supported, and are prevented in Edit mode. In Play mode they are allowed, because Scenes cannot be saved.Tôi tin rằng phần bạn đã đề cập là dành cho Unity v5.3 trở về trước. Và nó hoạt động trong thời gian chạy cho tôi. Xem xét bạn không thể có GameObjects DontDestroyOnLoad trước khi nhấn play, điều này xảy ra trong trình chỉnh sửa sẽ không thành vấn đề.
Evorlor

1
Một ứng dụng có thể là đưa phiên bản hacky vào bên trong phiên bản trình quản lý, bên trong một lệnh #IF UNITY_EDITOR. Ở đó, nó có thể so sánh các đối tượng trong cảnh DontDestroyOnLoad với danh sách sổ sách của chúng tôi, cảnh báo bắn nếu bạn bỏ lỡ sử dụng trình bao bọc ở đâu đó và đối tượng DontDestroyOnLoad đi lạc đã được tạo bên ngoài danh sách của chúng tôi.
DMGregory
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.