You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity构建后IntroModalScreenPanel无法激活,编辑器运行正常

构建包中IntroModalScreenPanel无法激活的Unity问题

问题概述

  • 已尝试论坛所有推荐解决方案,耗时5天仍未解决
  • 问题仅出现在Windows/Mac/Linux平台的构建包中,Unity编辑器内运行完全正常
  • 【2022年12月1日补充】首次使用“Build and Run”构建并运行时无问题,但关闭后通过.exe文件重启游戏,问题依然存在

问题详情

场景中的IntroductionHUD为Canvas,TestText(TextMeshPro)用于检测IntroModalScreenPanel(Image)的激活状态,IntroModalScreenManager(空物体)挂载脚本负责控制IntroModalScreenPanel及其子物体的激活与失活。

IntroModalScreenManager的Awake方法会将IntroModalScreenPanel及其子物体设置为失活状态,脚本中通过SetActive(bool)方法控制物体状态,所有物体均已在Inspector中赋值。

但构建包中,IntroModalScreenPanel在Awake失活后无法再次激活,TestText检测显示该面板始终处于未激活状态。同一Canvas下的Background和TestText运行正常,仅IntroModalScreenPanel及其子物体受影响。

相关脚本

using System;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class IntroModalScreenManager : MonoBehaviour
{
    public bool IsIntroModalScreenActive() { return _isIntroModalScreenActive; }

    //Bool variables...
    [SerializeField] private bool _isIntroModalScreenActive;

    //INTRO MODAL SCREEN MANAGER
    [Header("INTRO MODAL SCREEN MANAGER")]
    [SerializeField] private GameObject _introModalScreenPanel;
    [SerializeField] private GameObject _introModalScreenHeader;
    [SerializeField] private GameObject _introModalScreenBody;
    [SerializeField] private GameObject _introModalScreenFooter;

    //INTRO MODAL SCREEN PANEL
    [Header("INTRO MODAL SCREEN PANEL")]
    [SerializeField] private Image _introModalScreenPanelImage;

    //HEADER
    [Header("HEADER")]
    [SerializeField] private Image _introModalScreenPanelImageHeaderImage;
    [SerializeField] private TextMeshProUGUI _introModalScreenPanelImageHeaderImageHeaderText;

    //BODY
    [Header("BODY")]
    [SerializeField] private Image _introModalScreenPanelImageBodyImage;
    [SerializeField] private Image _introModalScreenPanelImageBodyImageBodyImage;
    [SerializeField] private TextMeshProUGUI _introModalScreenPanelImageBodyImageBodyText;

    //FOOTER
    [Header("FOOTER")]
    [SerializeField] private Image _introModalScreenPanelImageFooterImage;
    [SerializeField] private Button _introModalScreenPanelImageFooterImageFooterNegativeButton;
    [SerializeField] private TextMeshProUGUI _introModalScreenPanelImageFooterImageFooterNegativeButtonText;
    [SerializeField] private Button _introModalScreenPanelImageFooterImageFooterAlternateButton;
    [SerializeField] private TextMeshProUGUI _introModalScreenPanelImageFooterImageFooterAlternateButtonText;
    [SerializeField] private Button _introModalScreenPanelImageFooterImageFooterPositiveButton;
    [SerializeField] private TextMeshProUGUI _introModalScreenPanelImageFooterImageFooterPositiveButtonText;

    public static IntroModalScreenManager Instance { get; private set; }

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

        DeactivateModalScreenDisplay();

        //DontDestroyOnLoad(this.gameObject);
    }

    //Called by Awake() in the begining and by other script to deactivate modal screen when needed
    public void DeactivateModalScreenDisplay()
    {
        DeactivateAndClearAll();

        _introModalScreenPanel.SetActive(false);

        _isIntroModalScreenActive = false;
    }

    void DeactivateAndClearAll()
    {
        DeactivateHeader();
        DeactivateBody();
        DeactivateFooter();
    }

    //Called by another script to activate modal screen when needed
    public void ActivateModalScreenDisplay(bool isBook, bool isBookWithAlternateOption, 
        bool isSinglePage, bool isSinglePageWithNegativeOption, bool isSinglePageWithNegativeAndAlternateOption, 
        bool needBodyImage, 
        string headerText = "", 
        Sprite bodyImageSprite = null, string bodyText = "", 
        string footerNegativeButtonText = "", string footerAlternateButtonText = "", string footerPositiveButtonText = "", 
        Action negativeActionOption = null, Action alternateActionOption = null, Action positiveActionOption = null)
    {
        _introModalScreenPanel.SetActive(true);

        //Book - has front and back navigation options
        if (isBook)
        {
            ActivateHeader(headerText);
            ActivateBody(needBodyImage, true, bodyImageSprite, bodyText);
            ActivateFooter(true, false, true, footerNegativeButtonText, footerAlternateButtonText, footerPositiveButtonText,
                negativeActionOption, alternateActionOption, positiveActionOption);
        }
        //BookWithAlternateOption - Book with an addition of alternate option. (Eg: Skip button)
        else if (isBookWithAlternateOption)
        {
            ActivateHeader(headerText);
            ActivateBody(needBodyImage, true, bodyImageSprite, bodyText);
            ActivateFooter(true, true, true, footerNegativeButtonText, footerAlternateButtonText, footerPositiveButtonText,
                negativeActionOption, alternateActionOption, positiveActionOption);
        }
        //SinglePage - has one button (positive option - Eg: Continue, start, etc. buttons)
        else if (isSinglePage)
        {
            ActivateHeader(headerText);
            ActivateBody(needBodyImage, true, bodyImageSprite, bodyText);
            ActivateFooter(false, false, true, footerNegativeButtonText, footerAlternateButtonText, footerPositiveButtonText, 
                negativeActionOption, alternateActionOption, positiveActionOption);
        }
        //SinglePageWithNegativeOption - Single page with an addition of negative option (Eg: Confirmations)
        else if (isSinglePageWithNegativeOption)
        {
            ActivateHeader(headerText);
            ActivateBody(needBodyImage, true, bodyImageSprite, bodyText);
            ActivateFooter(true, false, true, footerNegativeButtonText, footerAlternateButtonText, footerPositiveButtonText, 
                negativeActionOption, alternateActionOption, positiveActionOption);
        }
        //SinglePageWithNegativeAndAlternateOption - Single page with negative option and an aditional alternate button (Eg: 3rd option in any choice making scenes)
        else if (isSinglePageWithNegativeAndAlternateOption)
        {
            ActivateHeader(headerText);
            ActivateBody(needBodyImage, true, bodyImageSprite, bodyText);
            ActivateFooter(true, true, true, footerNegativeButtonText, footerAlternateButtonText, footerPositiveButtonText,
                negativeActionOption, alternateActionOption, positiveActionOption);
        }

        _isIntroModalScreenActive = true;
    }


    void ActivateHeader(string headerText)
    {
        //Only if the header text has some value, this component will be active... Implemented this only for header & footer, as header & footer is used for all types of modal screen layouts.
        if(headerText != "" && headerText != null)
        {
            //HEADER
            _introModalScreenHeader.SetActive(true);//Header Object

            _introModalScreenPanelImageHeaderImageHeaderText.gameObject.SetActive(true);//Header Text Object
            _introModalScreenPanelImageHeaderImageHeaderText.text = headerText;//Header Text
        }
    }

    void DeactivateHeader()
    {
        _introModalScreenPanelImageHeaderImageHeaderText.text = "";//Header Text
        if (_introModalScreenPanelImageHeaderImageHeaderText.gameObject.activeSelf)
        {
            _introModalScreenPanelImageHeaderImageHeaderText.gameObject.SetActive(false);//Header Text Object
        }

        if (_introModalScreenHeader.activeSelf)
        {
            _introModalScreenHeader.SetActive(false);//Header Object
        }
    }

    void ActivateBody(bool needBodyImage, bool needBodyText, Sprite bodyImageSprite, string bodyText)
    {
        //BODY
        _introModalScreenBody.SetActive(true);//Body Object

        _introModalScreenPanelImageBodyImageBodyImage.gameObject.SetActive(needBodyImage);//Body Image Object
        if (_introModalScreenPanelImageBodyImageBodyImage.gameObject.activeSelf)//Body Image Object Image Sprite
        { _introModalScreenPanelImageBodyImageBodyImage.sprite = bodyImageSprite; }

        _introModalScreenPanelImageBodyImageBodyText.gameObject.SetActive(needBodyText);//Body Text Object
        if (_introModalScreenPanelImageBodyImageBodyText.gameObject.activeSelf)//Body Text Object Text
        { _introModalScreenPanelImageBodyImageBodyText.text = bodyText; }
    }

    void DeactivateBody()
    {
        _introModalScreenPanelImageBodyImageBodyText.text = "";
        if (_introModalScreenPanelImageBodyImageBodyText.gameObject.activeSelf)
        {
            _introModalScreenPanelImageBodyImageBodyText.gameObject.SetActive(false);//Body Text Object
        }

        _introModalScreenPanelImageBodyImageBodyImage.sprite = null;
        if (_introModalScreenPanelImageBodyImageBodyImage.gameObject.activeSelf)
        {
            _introModalScreenPanelImageBodyImageBodyImage.gameObject.SetActive(false);//Body Image Object
        }

        if (_introModalScreenBody.activeSelf)
        {
            _introModalScreenBody.SetActive(false);//Body Object
        }
    }

    void ActivateFooter(bool needFooterNegativeButton, bool needFooterAlternateButton, bool needFooterPositiveButton, 
        string footerNegativeButtonText, string footerAlternateButtonText, string footerPositiveButtonText,
        Action negativeActionOption, Action alternateActionOption, Action positiveActionOption)
    {
        //FOOTER
        _introModalScreenFooter.SetActive(true);//Footer Object

        //When this footer button is needed, only if the footer text and action has some value, this component will be active... Implemented this only for header & footer, as header & footer is used for all types of modal screen layouts.
        if (needFooterNegativeButton && footerNegativeButtonText != null && footerNegativeButtonText != "" && negativeActionOption != null)
        {
            _introModalScreenPanelImageFooterImageFooterNegativeButton.gameObject.SetActive(needFooterNegativeButton);//Footer Negative Button

            if (_introModalScreenPanelImageFooterImageFooterNegativeButton.gameObject.activeSelf)
            {
                _introModalScreenPanelImageFooterImageFooterNegativeButtonText.text = footerNegativeButtonText;//Footer Negative Button Text
                _introModalScreenPanelImageFooterImageFooterNegativeButton.onClick.AddListener(new UnityEngine.Events.UnityAction(negativeActionOption));//Add listener to the button's OnClick
            }
        }
        else
        {
            _introModalScreenPanelImageFooterImageFooterNegativeButton.gameObject.SetActive(needFooterNegativeButton);//Footer Negative Button
        }

        //When this footer button is needed, only if the footer text and action has some value, this component will be active... Implemented this only for header & footer, as header & footer is used for all types of modal screen layouts.
        if (needFooterAlternateButton && footerAlternateButtonText != null && footerAlternateButtonText != "" && alternateActionOption != null)
        {
            _introModalScreenPanelImageFooterImageFooterAlternateButton.gameObject.SetActive(needFooterAlternateButton);//Footer Alternate Button

            if (_introModalScreenPanelImageFooterImageFooterAlternateButton.gameObject.activeSelf)
            {
                _introModalScreenPanelImageFooterImageFooterAlternateButtonText.text = footerAlternateButtonText;//Footer Alternate Button Text
                _introModalScreenPanelImageFooterImageFooterAlternateButton.onClick.AddListener(new UnityEngine.Events.UnityAction(alternateActionOption));//Add listener to the button's OnClick
            }
        }
        else
        {
            _introModalScreenPanelImageFooterImageFooterAlternateButton.gameObject.SetActive(needFooterAlternateButton);//Footer Alternate Button
        }

        //When this footer button is needed, only if the footer text and action has some value, this component will be active... Implemented this only for header & footer, as header & footer is used for all types of modal screen layouts.
        if (needFooterPositiveButton && footerPositiveButtonText != null && footerPositiveButtonText != "" && positiveActionOption != null)
        {
            _introModalScreenPanelImageFooterImageFooterPositiveButton.gameObject.SetActive(needFooterPositiveButton);//Footer Positive Button

            if (_introModalScreenPanelImageFooterImageFooterPositiveButton.gameObject.activeSelf)
            {
                _introModalScreenPanelImageFooterImageFooterPositiveButtonText.text = footerPositiveButtonText;//Footer Positive Button Text
                _introModalScreenPanelImageFooterImageFooterPositiveButton.onClick.AddListener(new UnityEngine.Events.UnityAction(positiveActionOption));//Add listener to the button's OnClick
            }
        }
        else
        {
            _introModalScreenPanelImageFooterImageFooterPositiveButton.gameObject.SetActive(needFooterPositiveButton);//Footer Positive Button
        }
    }

    void DeactivateFooter()
    {
        #region COMMENTED PART - NEDD TO RESOLVE LATER - KEPT FOR FUTURE UPGRADE...
        //To make the button not be in selected state after clicking once: is to set it's Navigation drop down option from inspector to none.
        //Or can do it by code as done for each button below.
        //Unfortunately, I tried, but it doesn't work that way. Maybe I did it wrong. For now lets do the inspector method.
        #endregion

        _introModalScreenPanelImageFooterImageFooterNegativeButton.onClick.RemoveAllListeners();//Remove all listeners to the button's OnClick
        //var nav = _introModalScreenPanelImageFooterImageFooterNegativeButton.navigation;
        //nav.mode = Navigation.Mode.None;
        if (_introModalScreenPanelImageFooterImageFooterNegativeButton.gameObject.activeSelf)
        {
            _introModalScreenPanelImageFooterImageFooterNegativeButton.gameObject.SetActive(false);//Footer Negative Button
        }

        _introModalScreenPanelImageFooterImageFooterAlternateButton.onClick.RemoveAllListeners();//Remove all listeners to the button's OnClick
        //nav = _introModalScreenPanelImageFooterImageFooterAlternateButton.navigation;
        //nav.mode = Navigation.Mode.None;
        if (_introModalScreenPanelImageFooterImageFooterAlternateButton.gameObject.activeSelf)
        {
            _introModalScreenPanelImageFooterImageFooterAlternateButton.gameObject.SetActive(false);//Footer Alternate Button
        }

        _introModalScreenPanelImageFooterImageFooterPositiveButton.onClick.RemoveAllListeners();//Remove all listeners to the button's OnClick
        //nav = _introModalScreenPanelImageFooterImageFooterPositiveButton.navigation;
        //nav.mode = Navigation.Mode.None;
        if (_introModalScreenPanelImageFooterImageFooterPositiveButton.gameObject.activeSelf)
        {
            _introModalScreenPanelImageFooterImageFooterPositiveButton.gameObject.SetActive(false);//Footer Positive Button
        }

        if (_introModalScreenFooter.activeSelf)
        {
            _introModalScreenFooter.SetActive(false);//Footer Object
        }
    }
}

内容的提问来源于stack exchange,提问作者Aravind Shanmugam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:20:23