c# - 为什么即使未选中禁用编辑器中的脚本,它仍然可以工作并使对象可交互?

标签 c# unity-game-engine

脚本有点长,也许我应该删除顶部的所有变量?该脚本为用户提供了与对象交互的选项。但即使我在编辑器中取消选中禁用脚本,然后运行游戏,我也可以与脚本附加到的对象进行交互。

只有当我先从编辑器中的对象中删除脚本然后运行游戏时,它才无法交互。

什么使脚本即使未经检查也能正常工作?

也许问题出在 FPEInteractableBaseScript 脚本中,因为 FPEInteractableActivateScript 是 FPEInteractableBaseScript 的类型?

using UnityEngine;

    public class FPEInteractableActivateScript : FPEInteractableBaseScript
    {

        [SerializeField, Tooltip("If true, player can interact with this while holding something. If false, they cannot.")]
        protected bool canInteractWithWhileHoldingObject = true;

        [Header("Inventory Item Requirements (Optional)")]
        [SerializeField, Tooltip("If true, activation will require an inventory item with the parameters as configured below")]
        private bool requireInventoryItem = false;
        public bool RequireInventoryItem { get { return requireInventoryItem; } }

        [SerializeField, Tooltip("The type of inventory item required to activate")]
        private FPEInventoryManagerScript.eInventoryItems requiredItemType = FPEInventoryManagerScript.eInventoryItems.APPLE;
        public FPEInventoryManagerScript.eInventoryItems RequiredItemType { get { return requiredItemType; } }

        [SerializeField, Tooltip("The quantity of inventory item required for the activation")]
        private int requiredInventoryQuantity = 1;
        public int RequiredInventoryQuantity {  get { return requiredInventoryQuantity; } }

        public enum eInventoryRequirementMode
        {
            IN_HAND = 0,
            IN_INVENTORY = 1,
            IN_HAND_OR_INVENTORY = 2 
        }

        [SerializeField, Tooltip("Specify how the inventory item must be in player's possession for activation. Things like keycards might be required to be in hand, whereas a secret password written down on a scrap of paper can be in inventory or in hand.")]
        private eInventoryRequirementMode requiredToBeInHand = eInventoryRequirementMode.IN_HAND_OR_INVENTORY;
        public eInventoryRequirementMode RequiredToBeInHand {  get { return requiredToBeInHand; } }

        [SerializeField, Tooltip("If true, the activation will remove the item(s) once activation is triggered. (e.g. Remove battery when placed in radio. Don't remove keycard when swiped to open door.")]
        private bool removeOnUse = false;
        public bool RemoveOnUse {  get { return removeOnUse; } }

        [Header("Type of Activation and Events")]
        [SerializeField, Tooltip("This will dictate the nature of the events. ONCE: Will only fire the first time. EVERYTIME: Will fire on every activation.")]
        private FPEGenericEvent.eEventFireType eventFireType = FPEGenericEvent.eEventFireType.ONCE;
        public FPEGenericEvent.eEventFireType EventFireType {  get { return eventFireType; } }

        [SerializeField, Tooltip("If using the EVERYTIME event fire type, set this time to some value (in seconds) which will suspend the interaction for that amount of time before the activation can be repeated. Not to be used as a replacement for complex state management.")]
        private float eventRepeatDelay = 0.0f;
        private float eventRepeatCounter = 0.0f;
        private string previousInteractionString = "";

        [Header("Shared 'Activation' and 'Toggle On' Event")]
        [SerializeField, Tooltip("If specified, this event will fire on activation. It will adhere to defined occurrence type (e.g. fire once, fire every time, etc.)")]
        private FPEGenericEvent ActivationEvent;

        [Header("Shared 'Activation Failure' Event")]
        [SerializeField, Tooltip("If specified, this event is fired when the player needs inventory to activate the object but does not have it. (e.g. beep and flash a 'keycard required' warning light)")]
        private FPEGenericEvent ActivationFailureEvent;

        [Header("TOGGLE-specific 'Toggle Off' Event")]
        [SerializeField, Tooltip("If specified, this event will fire on de-activation or 'toggle off'.")]
        private FPEGenericEvent DeactivationEvent;

        [SerializeField, Tooltip("If true, toggling object OFF will also adhere to inventory requirements above")]
        private bool toggleOffRequiresInventory = false;
        public bool ToggleOffRequiresInventory { get { return toggleOffRequiresInventory; } }

        [SerializeField, Tooltip("Overrides interaction string, and applied when toggle is currently OFF")]
        private string toggleOnInteractionString;
        [SerializeField, Tooltip("Overrides interaction string, and applied when toggle is currently ON")]
        private string toggleOffInteractionString;

        [SerializeField, Tooltip("If true, the toggle will toggle ON and fire the ToggleOnEvent when scene starts.")]
        private bool toggleOnAtStart = false;
        [SerializeField, Tooltip("If true, the toggle will toggle OFF and fire the ToggleOnEvent when scene starts.")]
        private bool toggleOffAtStart = false;

        [Header("Save Game Options")]
        [SerializeField, Tooltip("If Event Fire Type is TOGGLE, and this value is true, the Toggle On and Toggle Off events will re-occur when game is loaded. For some objects like lights, a value of true is advised. For other objects like doors, a value of false makes more sense.")]
        private bool fireToggleEventsOnLoadGame = true;

        private bool toggleOn = false;
        public bool IsToggledOn { get { return toggleOn; } }

        private bool eventHasFiredOnce = false;

        public override void Awake()
        {

            base.Awake();
            interactionType = eInteractionType.ACTIVATE;
            // You may want to override assigned Inspector value for canInteractWithWhileHoldingObject in child classes, depending on the object and use case

            if (requireInventoryItem && requiredInventoryQuantity > 1 && requiredToBeInHand == eInventoryRequirementMode.IN_HAND)
            {
                Debug.LogError("FPEInteractableActivateScript:: Object '"+gameObject.name+"' is configured to require more than one '"+requiredItemType+"' but also that the '"+ requiredItemType + "'s are in player's hand. Player can only activate with one object in hand at a time. This activation will not work correctly.", gameObject);
            }
            else if (requireInventoryItem && requiredInventoryQuantity > 1 && requiredToBeInHand == eInventoryRequirementMode.IN_HAND_OR_INVENTORY)
            {
                Debug.LogWarning("FPEInteractableActivateScript:: Object '" + gameObject.name + "' is configured to require more than one '" + requiredItemType + "' but also that the '" + requiredItemType + "'s are in either in player's hand or in inventory. Player can only activate with one object in hand at a time. This activation may not work as expected.", gameObject);
            }

            if(toggleOnAtStart && toggleOffAtStart)
            {
                Debug.LogWarning("FPEInteractableActivateScript:: Object '" + gameObject.name + "' has both Toggle On At Start and Toggle Off At Start set to true.");
            }

        }

        public override void Start()
        {

            base.Start();

            // Some sanity checks if the wrong checkboxes are checked
            if (eventFireType == FPEGenericEvent.eEventFireType.ONCE || eventFireType == FPEGenericEvent.eEventFireType.EVERYTIME)
            {

                if(DeactivationEvent.GetPersistentEventCount() != 0)
                {
                    Debug.LogWarning("Object '"+gameObject.name+"' is of fire type '"+ eventFireType + "', but has a DeactivationEvent specified. This event will not fire unless you use TOGGLE type.", gameObject);
                }

            }
            else if (eventFireType == FPEGenericEvent.eEventFireType.TOGGLE)
            {
                if (DeactivationEvent.GetPersistentEventCount() == 0)
                {
                    Debug.LogWarning("Object '" + gameObject.name + "' is of fire type 'TOGGLE', but has no DeactivationEvent specified. Consider using a different type.");
                }
            }

            if (eventFireType == FPEGenericEvent.eEventFireType.TOGGLE)
            {

                if (toggleOnAtStart)
                {
                    doToggleOn();
                }
                if(toggleOffAtStart)
                {
                    doToggleOff();
                }

            }

        }

        void Update()
        {

            if (eventFireType == FPEGenericEvent.eEventFireType.EVERYTIME && eventRepeatCounter > 0.0f)
            {

                eventRepeatCounter -= Time.deltaTime;

                if (eventRepeatCounter <= 0.0f)
                {
                    interactionString = previousInteractionString;
                }

            }

        }

        public override bool interactionsAllowedWhenHoldingObject()
        {
            return canInteractWithWhileHoldingObject;
        }

        public virtual void activate()
        {

            base.interact();

            if (eventFireType == FPEGenericEvent.eEventFireType.ONCE)
            {

                if (!eventHasFiredOnce)
                {

                    eventHasFiredOnce = true;

                    if (ActivationEvent != null)
                    {
                        ActivationEvent.Invoke();
                    }

                }

            }
            else if (eventFireType == FPEGenericEvent.eEventFireType.EVERYTIME)
            {

                if (ActivationEvent != null && eventRepeatCounter <= 0.0f)
                {

                    ActivationEvent.Invoke();

                    if (eventRepeatDelay > 0.0f)
                    {

                        eventRepeatCounter = eventRepeatDelay;
                        previousInteractionString = interactionString;
                        interactionString = "";

                    }

                }

            }
            else if (eventFireType == FPEGenericEvent.eEventFireType.TOGGLE)
            {

                if (toggleOn)
                {
                    doToggleOff();
                }
                else
                {
                    doToggleOn();
                }

            }
            else
            {
                Debug.LogWarning("FPEInteractableActivateGenericScript:: eventFireType '" + eventFireType + "' not yet implemented!");
            }

#if UNITY_EDITOR
            if (ActivationEvent.GetPersistentEventCount() == 0)
            {
                Debug.LogError("FPEInteractableActivateScript:: Object '" + gameObject.name + "' has no Activation Event assigned!", gameObject);
            }
#endif

        }

        public void failToActivate()
        {

            if(ActivationFailureEvent != null)
            {
                ActivationFailureEvent.Invoke();
            }

#if UNITY_EDITOR
            if (ActivationFailureEvent.GetPersistentEventCount() == 0)
            {
                Debug.LogError("FPEInteractableActivateScript:: Object '" + gameObject.name + "' has no Activation Failure Event assigned! If this was intentional, you can ignore this error.", gameObject);
            }
#endif

        }

        private void doToggleOn()
        {

            toggleOn = true;
            interactionString = toggleOffInteractionString;

            if (ActivationEvent != null)
            {
                ActivationEvent.Invoke();
            }

#if UNITY_EDITOR
            if (ActivationEvent.GetPersistentEventCount() == 0)
            {
                Debug.LogError("FPEInteractableActivateScript:: Object '" + gameObject.name + "' has no Activation Event assigned!", gameObject);
            }
#endif

        }

        private void doToggleOff()
        {

            toggleOn = false;
            interactionString = toggleOnInteractionString;

            if (DeactivationEvent != null)
            {
                DeactivationEvent.Invoke();
            }

#if UNITY_EDITOR
            if (DeactivationEvent.GetPersistentEventCount() == 0)
            {
                Debug.LogError("FPEInteractableActivateScript:: Object '" + gameObject.name + "' has no Deactivation Event assigned!", gameObject);
            }
#endif

        }

        #region GAME_SAVE_LOAD

        public FPEActivateSaveData getSaveGameData()
        {

            // If we're in the middle of a repeat delay, save the previous interaction string so we don't load with a blank string :)
            string interactionStringToSave = (interactionString == "" ? previousInteractionString : interactionString);
            return new FPEActivateSaveData(gameObject.name, eventHasFiredOnce, toggleOn, interactionStringToSave);

        }

        public void restoreSaveGameData(FPEActivateSaveData data)
        {

            eventHasFiredOnce = data.FiredOnce;
            toggleOn = data.ToggleCurrentlyOn;
            interactionString = data.InteractionString;

            if (eventFireType == FPEGenericEvent.eEventFireType.TOGGLE && fireToggleEventsOnLoadGame)
            {

                if (toggleOn)
                {
                    doToggleOn();
                }
                else
                {
                    doToggleOff();
                }

            }

        }

        #endregion

    }

最佳答案

当您禁用脚本时,它只会禁用类似 Start 的功能, Update , FixedUpdate等(请参阅 documentation 中的完整列表)。另请参阅Behaviour.enabled其中说:

Enabled Behaviours are Updated, disabled Behaviours are not. This is shown as the small checkbox in the inspector of the behaviour.

这意味着如果在另一个脚本中您有:
GetComponent<FPEInteractableActivateScript>().activate();
activate即使 FPEInteractableActivateScript 也会被调用已禁用。
另外,如果您有 activate设置为按钮的处理程序,即使脚本被禁用,它也会被调用。

你能做的就是用 Behaviour.isActiveAndEnabled 来守护:

public virtual void activate()
{
    if(!isActiveAndEnabled) return;    
    ...
} 

或者在调用之前检查游戏对象是否处于事件状态/脚本是否已启用,在本例中为激活。

关于c# - 为什么即使未选中禁用编辑器中的脚本,它仍然可以工作并使对象可交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60572757/

相关文章:

c# - 403 禁止 Unity3D C#

c# - 使游戏对象在有限的时间内出现和消失

unity-game-engine - if 语句表现不佳

c# - 无法加载文件或程序集 'WindowsAzureTelemetryEvents.dll' 或其依赖项之一。文件名或扩展名太长

c# - C# 中的元组和解包赋值支持?

c# - 透明 UWP 窗口 10

java - 如何将2个不同的项目放入一个APK中

c# - 使用 System.Reflection 检索 const 字符串字段的列表

c# - 你如何在 C# 中传递字符串?

facebook-unity-sdk parse.com 无法让它工作