【问题标题】:Prefab clone does not have script component attached预制克隆没有附加脚本组件
【发布时间】:2019-03-09 14:21:15
【问题描述】:

runtime Prefab with scriptruntime prefab with script

我的问题是我的Prefab 克隆没有脚本组件。原始预制件有一个脚本组件,因此生成的所有克隆都应该有一个吗?

背景:我使用大厅网络管理器创建了一个共享的增强现实体验。预制件放置在“Game Player Prefab”中,并在服务器内为每个用户生成。

在发布之前,我会尽可能详细地进行解释。下面是附加到预制件的脚本和从Lobby Manager Inspector 实现预制件的屏幕截图。由于某种原因,堆栈不允许我包含这部分代码,因此将其包含在此处: using System. Collections、System.Collections.Generic、UnityEngine、UnityEngine.Networking、UnityEngine.UI 和公共类玩家身份:NetworkBehaviour

using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using System.Collections.Generic;

public class PlayerIdentity : NetworkBehaviour, MonoBehaviour
{

    GameObject imageTracker_1, imageTracker_2, canvasUI;
    public GameObject[] user;
    public GameObject myTextObj, origin;
    public float distanceFromOrigin;
    int count = 0;
    //public Text myText;

    private void Awake()
    {
        transform.GetComponent<playerIdentity>().enabled = true;

        user[0] = GameObject.FindWithTag("Respawn");
        user[1] = GameObject.FindWithTag("Finish");

   
    }

    void Start()
    {
        if (!isLocalPlayer)
        {
            Destroy(this);
            return;
        }
        //code stop unity responding! 
        //while (count < user.Length)
        //{
        //    if (transform.name == "idle(Clone)")
        //    {
        //        transform.name = "player" + count;
        //        count++;
        //    }
        //}

        origin = GameObject.Find("PositionOrigin");
        //used for finding text, "GetComponent<Text>" needs to be attached or fails.
        // canvasUI = GameObject.Find("Canvas");
        // myText = canvasUI.GetComponentInChildren<Text>();
        //// myText.text = "Out of area";
        // myTextObj.SetActive(false);

for 循环使脚本文件夹成为用户的子文件夹(场景中的标记组件,用于在运行时生成预制件)。

        for (int i = 0; i < user.Length; i++) {
            transform.SetParent(user[i].transform, false); 
            if (user[i].GetComponentInChildren<playerIdentity>() == null){
                Debug.Log("no child");
            }
        }


        // we track the vuforia image within the scene and attach the avatar as a child                   
        //imageTracker_1 = GameObject.FindWithTag("Respawn");
        //GameObject imageTracker_2 = GameObject.FindWithTag("Finish");
        //transform.SetParent(imageTracker_1.transform, false);
        //transform.parent = imageTracker_1.transform;

    
        //imageTracker_2 = GameObject.Find("avatar_01");
        //GameObject.Find("Idle(Clone)").transform.parent = imageTracker_2.transform;
    }
}

使用 if 语句是因为 gameObject 返回 NUll,但是我引用了 gameObject 但它在运行时失败。因此 if 语句确保组件不会返回 Null。

private void Update()
{
    distanceFromOrigin = Vector3.Distance(origin.transform.position, transform.position);      

    //during start the gameObject will return NULL, this will make sure during every frame the gameObject does not equal null
    if ( origin || imageTracker_1 || myTextObj == null)
    {
        myTextObj = GameObject.Find("OutOfBound");
        origin = GameObject.Find("PositionOrigin");
        //imageTracker_1 = GameObject.FindWithTag("Player");
        //transform.SetParent(imageTracker_1.transform, false);
    }
}

}

这是用于生成预制件的大厅经理脚本:

使用 UnityEngine、UnityEngine.UI、UnityEngine.SceneManagement、UnityEngine.Networking、UnityEngine.Networking.Types、UnityEngine.Networking.Match、System.Collections。

命名空间原型.NetworkLobby

public class LobbyManager : NetworkLobbyManager 
{
    static short MsgKicked = MsgType.Highest + 1;

    static public LobbyManager s_Singleton;


    [Header("Unity UI Lobby")]
    [Tooltip("Time in second between all players ready & match start")]
    public float prematchCountdown = 5.0f;

    [Space]
    [Header("UI Reference")]
    public LobbyTopPanel topPanel;

    public RectTransform mainMenuPanel;
    public RectTransform lobbyPanel;

    public LobbyInfoPanel infoPanel;
    public LobbyCountdownPanel countdownPanel;
    public GameObject addPlayerButton;

    protected RectTransform currentPanel;

    public Button backButton;

    public Text statusInfo;
    public Text hostInfo;

    //Client numPlayers from NetworkManager is always 0, so we count (throught connect/destroy in LobbyPlayer) the number
    //of players, so that even client know how many player there is.
    [HideInInspector]
    public int _playerNumber = 0;

    //used to disconnect a client properly when exiting the matchmaker
    [HideInInspector]
    public bool _isMatchmaking = false;

    protected bool _disconnectServer = false;
    
    protected ulong _currentMatchID;

    protected LobbyHook _lobbyHooks;

    void Start()
    {
        s_Singleton = this;
        _lobbyHooks = GetComponent<Prototype.NetworkLobby.LobbyHook>();
        currentPanel = mainMenuPanel;

        backButton.gameObject.SetActive(false);
        GetComponent<Canvas>().enabled = true;

        DontDestroyOnLoad(gameObject);

        SetServerInfo("Offline", "None");
    }

    public override void OnLobbyClientSceneChanged(NetworkConnection conn)
    {
        if (SceneManager.GetSceneAt(0).name == lobbyScene)
        {
            if (topPanel.isInGame)
            {
                ChangeTo(lobbyPanel);
                if (_isMatchmaking)
                {
                    if (conn.playerControllers[0].unetView.isServer)
                    {
                        backDelegate = StopHostClbk;
                    }
                    else
                    {
                        backDelegate = StopClientClbk;
                    }
                }
                else
                {
                    if (conn.playerControllers[0].unetView.isClient)
                    {
                        backDelegate = StopHostClbk;
                    }
                    else
                    {
                        backDelegate = StopClientClbk;
                    }
                }
            }
            else
            {
                ChangeTo(mainMenuPanel);
            }

            topPanel.ToggleVisibility(true);
            topPanel.isInGame = false;
        }
        else
        {
            ChangeTo(null);

            Destroy(GameObject.Find("MainMenuUI(Clone)"));

            //backDelegate = StopGameClbk;
            topPanel.isInGame = true;
            topPanel.ToggleVisibility(false);
        }
    }

    public void ChangeTo(RectTransform newPanel)
    {
        if (currentPanel != null)
        {
            currentPanel.gameObject.SetActive(false);
        }

        if (newPanel != null)
        {
            newPanel.gameObject.SetActive(true);
        }

        currentPanel = newPanel;

        if (currentPanel != mainMenuPanel)
        {
            backButton.gameObject.SetActive(true);
        }
        else
        {
            backButton.gameObject.SetActive(false);
            SetServerInfo("Offline", "None");
            _isMatchmaking = false;
        }
    }

    public void DisplayIsConnecting()
    {
        var _this = this;
        infoPanel.Display("Connecting...", "Cancel", () => { _this.backDelegate(); });
    }

    public void SetServerInfo(string status, string host)
    {
        statusInfo.text = status;
        hostInfo.text = host;
    }


    public delegate void BackButtonDelegate();
    public BackButtonDelegate backDelegate;
    public void GoBackButton()
    {
        backDelegate();
        topPanel.isInGame = false;
    }

    // ----------------- Server management

    public void AddLocalPlayer()
    {
        TryToAddPlayer();
    }

    public void RemovePlayer(LobbyPlayer player)
    {
        player.RemovePlayer();
    }

    public void SimpleBackClbk()
    {
        ChangeTo(mainMenuPanel);
    }
             
    public void StopHostClbk()
    {
        if (_isMatchmaking)
        {
            matchMaker.DestroyMatch((NetworkID)_currentMatchID, 0, OnDestroyMatch);
            _disconnectServer = true;
        }
        else
        {
            StopHost();
        }

        
        ChangeTo(mainMenuPanel);
    }

    public void StopClientClbk()
    {
        StopClient();

        if (_isMatchmaking)
        {
            StopMatchMaker();
        }

        ChangeTo(mainMenuPanel);
    }

    public void StopServerClbk()
    {
        StopServer();
        ChangeTo(mainMenuPanel);
    }

    class KickMsg : MessageBase { }
    public void KickPlayer(NetworkConnection conn)
    {
        conn.Send(MsgKicked, new KickMsg());
    }




    public void KickedMessageHandler(NetworkMessage netMsg)
    {
        infoPanel.Display("Kicked by Server", "Close", null);
        netMsg.conn.Disconnect();
    }

    //===================

    public override void OnStartHost()
    {
        base.OnStartHost();

        ChangeTo(lobbyPanel);
        backDelegate = StopHostClbk;
        SetServerInfo("Hosting", networkAddress);
    }

    public override void OnMatchCreate(bool success, string extendedInfo, MatchInfo matchInfo)
    {
        base.OnMatchCreate(success, extendedInfo, matchInfo);
        _currentMatchID = (System.UInt64)matchInfo.networkId;
    }

    public override void OnDestroyMatch(bool success, string extendedInfo)
    {
        base.OnDestroyMatch(success, extendedInfo);
        if (_disconnectServer)
        {
            StopMatchMaker();
            StopHost();
        }
    }


    //allow to handle the (+) button to add/remove player
    public void OnPlayersNumberModified(int count)
    {
        _playerNumber += count;

        int localPlayerCount = 0;
        foreach (PlayerController p in ClientScene.localPlayers)
            localPlayerCount += (p == null || p.playerControllerId == -1) ? 0 : 1;

        addPlayerButton.SetActive(localPlayerCount < maxPlayersPerConnection && _playerNumber < maxPlayers);
    }

    // ----------------- Server callbacks ------------------

    //we want to disable the button JOIN if we don't have enough player
    //But OnLobbyClientConnect isn't called on hosting player. So we override the lobbyPlayer creation
    public override GameObject OnLobbyServerCreateLobbyPlayer(NetworkConnection conn, short playerControllerId)
    {
        
        GameObject obj = Instantiate(lobbyPlayerPrefab.gameObject) as GameObject;
       

        LobbyPlayer newPlayer = obj.GetComponent<LobbyPlayer>();
        newPlayer.ToggleJoinButton(numPlayers + 1 >= minPlayers);

        for (int i = 0; i < lobbySlots.Length; ++i)
        {
            LobbyPlayer p = lobbySlots[i] as LobbyPlayer;

           

            if (p != null)
            {
                p.RpcUpdateRemoveButton();
                p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
            }
        }

        return obj;
    }

    public override void OnLobbyServerPlayerRemoved(NetworkConnection conn, short playerControllerId)
    {
        for (int i = 0; i < lobbySlots.Length; ++i)
       {
            LobbyPlayer p = lobbySlots[i] as LobbyPlayer;

            if (p != null)
            {
                p.RpcUpdateRemoveButton();
                p.ToggleJoinButton(numPlayers + 1 >= minPlayers);
            }
        }
    }

    public override void OnLobbyServerDisconnect(NetworkConnection conn)
    {
        for (int i = 0; i < lobbySlots.Length; ++i)
        {
            LobbyPlayer p = lobbySlots[i] as LobbyPlayer;

            if (p != null)
            {
                p.RpcUpdateRemoveButton();
                p.ToggleJoinButton(numPlayers >= minPlayers);
            }
        }

    }

    public override bool OnLobbyServerSceneLoadedForPlayer(GameObject lobbyPlayer, GameObject gamePlayer)
    {
        //This hook allows you to apply state data from the lobby-player to the game-player
        //just subclass "LobbyHook" and add it to the lobby object.

        if (_lobbyHooks)
            _lobbyHooks.OnLobbyServerSceneLoadedForPlayer(this, lobbyPlayer, gamePlayer);

        return true;
    }

    // --- Countdown management

    public override void OnLobbyServerPlayersReady()
    {
        bool allready = true;
        for(int i = 0; i < lobbySlots.Length; ++i)
        {
            if(lobbySlots[i] != null)
                allready &= lobbySlots[i].readyToBegin;
        }

        if(allready)
            StartCoroutine(ServerCountdownCoroutine());
    }

    public IEnumerator ServerCountdownCoroutine()
    {
        float remainingTime = prematchCountdown;
        int floorTime = Mathf.FloorToInt(remainingTime);

        while (remainingTime > 0)
        {
            yield return null;

            remainingTime -= Time.deltaTime;
            int newFloorTime = Mathf.FloorToInt(remainingTime);

            if (newFloorTime != floorTime)
            {//to avoid flooding the network of a message, we only send a notice to the client when the number of plain seconds changes.
                floorTime = newFloorTime;

                for (int i = 0; i < lobbySlots.Length; ++i)
                {
                    if (lobbySlots[i] != null)
                    {//there is maxPlayer slots, so some could be == null, need to test it before accessing!
                        (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(floorTime);
                    }
                }
            }
        }

        for (int i = 0; i < lobbySlots.Length; ++i)
        {
            if (lobbySlots[i] != null)
            {
                (lobbySlots[i] as LobbyPlayer).RpcUpdateCountdown(0);
            }
        }

        ServerChangeScene(playScene);
    }

    // ----------------- Client callbacks ------------------

    public override void OnClientConnect(NetworkConnection conn)
    {
        base.OnClientConnect(conn);

        infoPanel.gameObject.SetActive(false);

        conn.RegisterHandler(MsgKicked, KickedMessageHandler);

        if (!NetworkServer.active)
        {//only to do on pure client (not self hosting client)
            ChangeTo(lobbyPanel);
            backDelegate = StopClientClbk;
            SetServerInfo("Client", networkAddress);
        }
    }


    public override void OnClientDisconnect(NetworkConnection conn)
    {
        base.OnClientDisconnect(conn);
        ChangeTo(mainMenuPanel);
    }

    public override void OnClientError(NetworkConnection conn, int errorCode)
    {
        ChangeTo(mainMenuPanel);
        infoPanel.Display("Cient error : " + (errorCode == 6 ? "timeout" : errorCode.ToString()), "Close", null);
    }
}

}

我将在 Unity 中提出与增强现实相关的问题,如果有一个网站或一些文档可供查看,我会非常高兴。目前正在使用 Unity API 以及我能找到的任何可以帮助我的东西。

【问题讨论】:

  • 您需要发布包含实例化预制件的代码的脚本。否则很难查看您的问题
  • 我已经添加了生成预制件的大厅经理脚本。谢谢你帮助我! @不道德
  • 您确定脚本已附加到预制件上吗?当您在资产文件夹中选择预制件时,您会看到什么。右边的检查员,是否显示脚本?如果没有,那么您对场景中的预制对象进行了未应用的更改。
  • 尝试在 Inspector 中对场景中的 GameObject 使用“应用”选项。
  • Morasi 在资产文件夹中的预制件上没有应用按钮。我确信该方法仅适用于层次结构场景中的预制件。 @Immorality 是的,它已附加到预制件上,我将尝试上传显示预制件检查员的图像。

标签: c# visual-studio unity3d networking augmented-reality


【解决方案1】:

问题已解决:总而言之,如果预制件不是孩子,脚本将不会出现。因此对于预制件必须是一个孩子。

现在问题在于大厅管理器,因为它是统一的资产,乱搞可能会导致问题,但是,通过编辑内容并为游戏玩家预制添加控制,这个问题得到了解决。

问题在于 LobbyManager 会生成预制件的克隆,例如Idle 变为 Idle(Clone) 但使用此 code 覆盖系统。使用计数来识别不同的玩家,然后这个code 由预制件持有。代码遍历标记的所有成员和所有预制成员,然后将预制转换为标记的子项。

【讨论】:

    猜你喜欢
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    • 2016-12-22
    • 1970-01-01
    • 2011-10-06
    • 2011-05-01
    相关资源
    最近更新 更多