【问题标题】:Attempting to add objects to active scene in Unity, but objects load in parent scene尝试将对象添加到 Unity 中的活动场景,但对象加载到父场景中
【发布时间】:2018-03-18 04:34:53
【问题描述】:

我正在尝试构建一个简单的飞行游戏。我有两个场景——一个用于生成 GameManager 和 SceneController 实例的管理场景,以及一个加载的游戏场景,玩家可以在其中飞过一些红色的大门。

游戏场景加载完毕后,我会添加一些门。然而,门并没有出现在层次结构中的这个场景下——它们出现在管理场景下。预制件确实出现在游戏场景中。我希望所有这些都会出现在游戏场景中。

两个问题:

  1. 我是否不正确地加载游戏场景?是否需要发生其他事情才能使其完全激活?
  2. 我是否不了解场景的工作原理,如果是,我应该采取哪些不同的做法?

场景控制器代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneController : MonoBehaviour {

    // This is a singleton
    private static SceneController _instance;

    public static SceneController Instance { get { return _instance; } }

    private void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(this.gameObject);
        } else {
            _instance = this;
        }
    }

    // Scene names
    private string sceneNameGameScene = "GameScene";

    // Use this for initialization
    void Start () {
        SceneManager.sceneLoaded += OnSceneLoaded;
        StartCoroutine(LoadSceneAdditive(sceneNameGameScene, LoadSceneMode.Additive));
    }

    void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
        if (scene.name == sceneNameGameScene) {
            SceneManager.SetActiveScene(scene);
            Debug.Log("OnSceneLoaded Active Scene : " + SceneManager.GetActiveScene().name);
            SetupGameScene();
        }
    }

    IEnumerator LoadSceneAdditive(string sceneName, LoadSceneMode loadSceneMode){
        AsyncOperation _async = new AsyncOperation();
        _async = SceneManager.LoadSceneAsync(sceneName, loadSceneMode);

        while (!_async.isDone) {
            yield return null;
        }

        Scene nextScene = SceneManager.GetSceneByName( name );
        if (nextScene.IsValid ()) {
            SceneManager.SetActiveScene (nextScene);
        }
    }


    private void SetupGameScene() {

        // Create a game map
        GameMap gameMap = new GameMap();
        gameMap.Setup(this.transform);
    }
}

游戏地图代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameMap {
    private GameObject gatePrefab = GameObject.Instantiate(Resources.Load("GatePrefab")) as GameObject;
    private Transform transform;

    public GameMap() {}

    public void Setup (Transform parentTransform) {
        transform = parentTransform;
        Vector3 position;
        Quaternion rotation;

        position = new Vector3(0, 0, 0);
        rotation = Quaternion.identity;
        CreateGate(position, rotation, 10.0f, 2.0f, "Gate 1");

        position = new Vector3(0, 0, 20);
        rotation =  Quaternion.identity * Quaternion.Euler(0, 45, 0);
        CreateGate(position, rotation, 10.0f, 1.0f, "Gate 2");

        position = new Vector3(20, 0, 20);
        rotation =  Quaternion.identity * Quaternion.Euler(0, 90, 0);
        CreateGate(position, rotation, 8.0f, 1.0f, "Gate 3");

        CreateGround();
    }

    private void CreateGate(Vector3 position, Quaternion rotation, float lengthOfSide, float thickness, string name) {
        // Create the gates, and call the "Initialize" method to populate properties as Unity doesn't have constructors.
        GameObject clone = GameObject.Instantiate(gatePrefab, position, rotation, transform) as GameObject;
        clone.name = name;
        clone.GetComponent<Gate>().Initialize(lengthOfSide, thickness);
    }

    private void CreateGround() {
        Debug.Log("OnSceneLoaded Active Scene : " + SceneManager.GetActiveScene().name);
        GameObject ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
        ground.name = "Ground";
        ground.transform.parent = transform;
        ground.transform.localPosition = new Vector3(0, -10, 0);
        ground.transform.localRotation = Quaternion.identity;
        ground.transform.localScale = new Vector3(50, 1, 50);

        ground.GetComponent<Renderer>().material.color = Color.grey;
    }
}

门牌代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Gate : MonoBehaviour {
    float lengthOfSide;
    float thickness;

    public void Initialize (float lengthOfSide, float thickness) {
        this.lengthOfSide = lengthOfSide;
        this.thickness = thickness;
    }

    // Use this for initialization
    void Start () {
        SetupRigidBody();
        Setup3dEntities();
    }

    void SetupRigidBody() {
        Rigidbody rb = this.gameObject.AddComponent<Rigidbody>();
        rb.detectCollisions = true;
        rb.mass = 1000;
        rb.useGravity = false;
    }

    // Create the physical gate
    void Setup3dEntities() {
        Vector3 position;
        Vector3 scale;
        float lengthOfVeritcalSegment = lengthOfSide - (2 * thickness);
        float yPosHorizontalSegment = (lengthOfSide - thickness) / 2;
        float xPosVerticalSegment = lengthOfSide - thickness;

        // Bottom
        position = new Vector3(0, -yPosHorizontalSegment, 0);
        scale = new Vector3(lengthOfSide, thickness, thickness);
        CreatePrimitiveCube(position, scale);

        // Top
        position = new Vector3(0, yPosHorizontalSegment, 0);
        scale = new Vector3(lengthOfSide, thickness, thickness);
        CreatePrimitiveCube(position, scale);

        // Left
        position = new Vector3(xPosVerticalSegment/2, 0, 0);
        scale = new Vector3(thickness, lengthOfVeritcalSegment, thickness);
        CreatePrimitiveCube(position, scale);

        // Right
        position = new Vector3(-xPosVerticalSegment/2, 0, 0);
        scale = new Vector3(thickness, lengthOfVeritcalSegment, thickness);
        CreatePrimitiveCube(position, scale);
    }

    void CreatePrimitiveCube(Vector3 position, Vector3 scale) {
        // Create a primitive cube. Note that we want to set the position and rotation to match the parent!
        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.transform.parent = gameObject.transform;
        cube.transform.localPosition = position;
        cube.transform.localRotation = Quaternion.identity;
        cube.transform.localScale = scale;

        // TODO: Make a better color/material mechanism!
        cube.GetComponent<Renderer>().material.color = Color.red;

//      Debug.Log("Cube.parent: " + cube.transform.parent.gameObject.name);
//      Debug.Log("Cube.localScale: " + cube.transform.localScale);
    }
}

屏幕截图 - 注释层次结构很奇怪:

【问题讨论】:

    标签: unity3d


    【解决方案1】:

    您的 SceneController 将其转换传递给 GameMap Setup 方法。 (我假设 SceneController 转换是“app”对象?)

    GameMap Setup 方法然后创建门并使用给定的 parentTransform 作为每个门的父级(因为它是 GameObject.Instantiate 方法中的 passend)

    所以我想 Gate 对象是管理场景中“app”对象的子对象是有道理的?

    如果您想让它们出现在另一个场景中,那么您必须传递不同的父级或不传递父级。

    【讨论】:

    • 不传入父母似乎可以解决问题。我最初以不同的方式组织我的场景,并且在父级中传递是我的新手解决方案。
    【解决方案2】:

    所以,据我了解,您希望有一个管理场景,您可以在其中使用脚本管理游戏。

    我的想法是你不要使用LoadSceneAdditive,而是使用DontDestroyOnLoad。即使您加载另一个场景,这也会使您的脚本仍然被加载。这也将使游戏对象在当前加载的场景中生成。

    因此,您只需使用LoadSceneMode.Single 而不是LoadSceneMode.Additive

    另一种选择是使用SceneManager.SetActiveScene 更改您想要设置为“父场景”的场景或您想要生成游戏对象的场景。

    【讨论】:

    • 过去,这是正确的做法。 Unity 现在建议“建议避免使用 DontDestroyOnLoad 来持久化您希望在场景加载中存活的管理器游戏对象。相反,创建一个包含所有管理器的管理器场景并使用 SceneManager.LoadScene(, LoadSceneMode.Additive) 和SceneManager.UnloadScene 来管理你的游戏进度。”:docs.unity3d.com/Manual/MultiSceneEditing.html
    猜你喜欢
    • 2021-08-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2015-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多