Objects appearing in play mode but not in build

Howdy folks. Testing out some aspects of a game I’ve been working on in an actual build. Most things are working correct except for one glaring problem.

I have a script to run dialogue when the player either interacts with a specific game object, or when they walk into a trigger area. Everything works fine in play mode. When I build and run the game, the interactable dialogue works, but none of the trigger area dialogue panels fire anymore. Adding logs and checking the build log shows that not only is the code not running but the OnTriggerEnter2D isn’t firing at all, it’s like the dialogue area doesn’t exist at all in the built scene.

Here’s what I’ve checked.

  • The dialogue area game object is tagged appropriately with a tag that matches what the code is asking for.
  • The dialogue area game object exists, it’s checked off in the hierarchy. It’s a child of a parent object and that object exists too.
  • The dialogue script has the necessary dialogue data populated in the respective fields.
  • Verified that the hasRun bool is not somehow checked already which would fail the whole thing.
  • Verified that the player has the Player tag.
  • Verified that collision is on between the player’s layer and the object’s layer.

Here’s a screenshot of the object in the hierarchy.

And the code for DialogueArea.cs.

using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class DialogueArea : MonoBehaviour, IInteractable
{
    public Dialogue dialogueData;
    public GameObject dialoguePanel;
    public GameObject partnerPanel;
    public TMP_Text dialogueText, nameText, partnerText, partnerName;
    public Image portraitImage, partnerPortrait;
    BoxCollider2D areaCollider;
    
    public int dialogueIndex;
    private bool isTyping, isDialogueActive;

    public bool hasRun = false;

    public Conversation conversation;
    private int turnIndex;
    private Dialogue currentDialogue;
    private TMP_Text currentText;
    
    //if you have auto progressing lines you have to check the Auto Progress lines bool for EACH LINE ELEMENT that auto progresses.
    void Start()
    {
        areaCollider = GetComponent<BoxCollider2D>();
    }

    void Update()
    {
        if (isDialogueActive && (Keyboard.current.escapeKey.wasPressedThisFrame || Keyboard.current.eKey.wasPressedThisFrame))
        {
            EndDialogue();
        }
    }

    public bool CanInteract()
    {
        if (gameObject.CompareTag("DialogueArea")) return false;
        
        return !isDialogueActive;
    }

    public void Interact()
    {
        if(dialogueData == null) return;
        
        if(isDialogueActive)
        {
            NextLine();
        }
        else
        {
            StartDialogue();
        }
    }
    
    void SwitchUIFor(Dialogue d)
    {
        bool partner = d.isPartner;

        dialoguePanel.SetActive(!partner);
        if (partnerPanel != null)
        {
            partnerPanel.SetActive(partner);

        }

        currentText = partner ? partnerText : dialogueText;
    }
    
    void StartDialogue()
    {
        isDialogueActive=true;
        turnIndex = 0;
        dialogueIndex = 0;
        
        currentDialogue=conversation.turns[turnIndex];
        SwitchUIFor(currentDialogue);
        StartCoroutine(TypeLine());
        //pause game if you have that set up
    }
    
    void NextLine()
    {
        if(isTyping)
        {
            StopAllCoroutines();
            dialogueText.SetText(dialogueData.dialogueLines[dialogueIndex]);
            isTyping=false;
            return;
        }

        dialogueIndex++;
        
        if(dialogueIndex < currentDialogue.dialogueLines.Length)
        {
            StartCoroutine(TypeLine());
            return;
        }

        turnIndex++;
        
        if(turnIndex < conversation.turns.Length)
        {
            dialogueIndex = 0;
            currentDialogue = conversation.turns[turnIndex];
            SwitchUIFor(currentDialogue);
            StartCoroutine(TypeLine());
            return;
        }

        EndDialogue();
    }

    IEnumerator TypeLine()
    {
        isTyping=true;
        currentText.SetText("");

        string line = currentDialogue.dialogueLines[dialogueIndex];
            
        foreach(char letter in currentDialogue.dialogueLines[dialogueIndex])
        {
            currentText.text += letter;
            SoundEffectManager.Play("Narrator Dialogue");
            yield return new WaitForSeconds(dialogueData.typingSpeed);
        }

        isTyping = false;

        if(currentDialogue.autoProgressLines != null &&
            currentDialogue.autoProgressLines.Length > dialogueIndex && 
           currentDialogue.autoProgressLines[dialogueIndex])
        {
            yield return new WaitForSeconds(dialogueData.autoProgressDelay);
            NextLine();
        }
    }

    private void HideHostPanel()
    {
        if (dialoguePanel != null)
        {
            dialogueText.SetText("");
            dialoguePanel.SetActive(false);
        }
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if (!other.CompareTag("Player")) return; 
        
        if (hasRun) return; 
        
        if (gameObject.CompareTag(("DialogueArea")))
        {
            if(isDialogueActive)
            {
                NextLine();
            }
            else
            {
                StartDialogue();
                hasRun = true;
            }
        }
    }

    public void EndDialogue()
    {
        StopAllCoroutines();
        isDialogueActive = false;
        if(dialoguePanel != null)
        {
            dialogueText.SetText("");
            dialoguePanel.SetActive(false);            
        }
        //unpause game if you have that
    }
}

Why might the dialogue be triggering correctly in play mode but not in the build? Thank you all for your help.

Do all the tags (mentioned in code or assigned in the Inspector) exist in the Tags and Layers settings of Project? You might have accidentally deleted some of them from the list.


By any chance, do you have objects on the Scene:

Thanks so much for the reply. Uh, I went and checked tags and layers, and I did not expect this but it doesn’t look like the Player tag is actually in the list.

But Player is a Unity default tag isn’t it? The Player object also has the tag attached to them…yet it doesn’t exist in the tags in Project Settings?

Order of execution changes between editor and build.

You may also get an exception in a build, possibly because of that. Make sure you build with Development Build checkbox enabled so you see any runtime errors/exceptions on-screen. Otherwise check the player.log for details.

You can also attach the debugger to a running build process to inspect live what’s going on.

This is a recent change, built-in (uneditable) tags will no longer be displayed in the tags list. But they remain valid.

Yes, Player tag is built-in.

Wheres the canvas at the root of all that diaglog stuff?

Okay so the Player tag thing shouldn’t be the problem theoretically then.

The canvas is labeled UI up above, a separate game object.
Yellow is the DialogueArea object we’re looking at, a child of Room (5).

It does reference the UI game object which is a canvas. Though the NPCDialoguePanel is inactive right now, it gets activated through the DialogueArea.cs code from earlier, in the SwitchUIFor() method.

I am able to turn on the Development Build checkbox in Build Settings, but I’m not sure I see a practical difference in the built game. I was able to check the player log earlier and there are no apparent errors or exceptions. Here is a recent log from when the NPC dialogue worked but not the area dialogue, if that’s worth anything. Not sure if it should be codeblocked or not but I will anyway for clarity.

Mono path[0] = 'C:/Users/Peter/Unity projects/faberge/Builds/faberge_Data/Managed'
Mono config path = 'C:/Users/Peter/Unity projects/faberge/Builds/MonoBleedingEdge/etc'
Starting managed debugger on port 56706
Using monoOptions --debugger-agent=transport=dt_socket,embedding=1,server=y,suspend=n,address=0.0.0.0:56706
Found 1 interfaces on host : 0) 192.168.1.124
Player connection [12368]  Target information:

Player connection [12368]  * "[IP] 192.168.1.124 [Port] 55000 [Flags] 2 [Guid] 3398313706 [EditorId] 999192079 [Version] 1048832 [Id] WindowsPlayer(2,DESKTOP-GKMS74U) [Debug] 1 [PackageName] WindowsPlayer [ProjectName] faberge" 

Player connection [12368] Started UDP target info broadcast (1) on [225.0.0.222:54997].

Input System module state changed to: Initialized.
[Physics::Module] Initialized fallback backend.
[Physics::Module] Id: 0xdecafbad
Initialize engine version: 6000.2.10f1 (d3d30d158480)
[Subsystems] Discovering subsystems at path C:/Users/Peter/Unity projects/faberge/Builds/faberge_Data/UnitySubsystems
[D3D12 Device Filter] Vendor Name: NVIDIA
[D3D12 Device Filter] Device Name: NVIDIA GeForce RTX 4060 Ti
[D3D12 Device Filter] Driver Version: 32.0.15.8180
[D3D12 Device Filter] Feature Level: 12.1
[D3D12 Device Filter] Graphics Memory: 7949 MB
[D3D12 Device Filter] Processor Count: 8
[D3D12 Device Filter] Device Type: Discrete
GfxDevice: creating device client; kGfxThreadingModeSplitJobs
d3d12: failed to query info queue interface (0x80004002).
Direct3D:
    Version:         Direct3D 12 [level 12.1]
    Renderer:        NVIDIA GeForce RTX 4060 Ti (ID=0x2803)
    Vendor:          NVIDIA
    VRAM:            7949 MB
    App VRAM Budget: 7181 MB
    Driver:          32.0.15.8180
Begin MonoManager ReloadAssembly
- Loaded All Assemblies, in  0.225 seconds
- Finished resetting the current domain, in  0.003 seconds
[Physics::Module] Selected backend.
[Physics::Module] Name: PhysX
[Physics::Module] Id: 0xf2b8ea05
[Physics::Module] SDK Version: 4.1.2
[Physics::Module] Integration Version: 1.0.0
[Physics::Module] Threading Mode: Multi-Threaded
<RI> Initializing input.

Using Windows.Gaming.Input
UnloadTime: 0.745700 ms
RenderGraph is now enabled.
UnityEngine.Debug:ExtractStackTraceNoAlloc (byte*,int,string)
UnityEngine.StackTraceUtility:ExtractStackTrace () (at C:/build/output/unity/unity/Runtime/Export/Scripting/StackTrace.cs:35)
UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object)
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[]) (at C:/build/output/unity/unity/Runtime/Export/Logging/DebugLogHandler.cs:9)
UnityEngine.Logger:Log (UnityEngine.LogType,object) (at C:/build/output/unity/unity/Runtime/Export/Logging/Logger.cs:60)
UnityEngine.Debug:Log (object) (at C:/build/output/unity/unity/Runtime/Export/Debug/Debug.bindings.cs:123)
UnityEngine.Rendering.Universal.UniversalRenderPipeline:.ctor (UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset) (at ./Library/PackageCache/com.unity.render-pipelines.universal@4976252adeb8/Runtime/UniversalRenderPipeline.cs:273)
UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset:CreatePipeline () (at ./Library/PackageCache/com.unity.render-pipelines.universal@4976252adeb8/Runtime/Data/UniversalRenderPipelineAsset.cs:800)
UnityEngine.Rendering.RenderPipelineAsset:InternalCreatePipeline () (at C:/build/output/unity/unity/Runtime/Export/RenderPipeline/RenderPipelineAsset.cs:15)
UnityEngine.Rendering.RenderPipelineManager:TryPrepareRenderPipeline (UnityEngine.Rendering.RenderPipelineAsset) (at C:/build/output/unity/unity/Runtime/Export/RenderPipeline/RenderPipelineManager.cs:172)
UnityEngine.Rendering.RenderPipelineManager:DoRenderLoop_Internal (UnityEngine.Rendering.RenderPipelineAsset,intptr,UnityEngine.Object) (at C:/build/output/unity/unity/Runtime/Export/RenderPipeline/RenderPipelineManager.cs:146)

(Filename: C:/build/output/unity/unity/Runtime/Export/Debug/Debug.bindings.cs Line: 123)

[Physics::Module] Cleanup current backend.
[Physics::Module] Id: 0xf2b8ea05
Input System module state changed to: ShutdownInProgress.
Input System polling thread exited.
Input System module state changed to: Shutdown.
GarbageCollector disposing of ComputeBuffer. Please use ComputeBuffer.Release() or .Dispose() to manually release the buffer.
PlayerConnection::Cleanup##utp:{"type":"MemoryLeaks","version":2,"phase":"Immediate","time":1775409094689,"processId":15144,"allocatedMemory":68571,"memoryLabels":[{"Default":136},{"NewDelete":760},{"Thread":7872},{"Manager":9046},{"VFX":-104},{"GfxDevice":2704},{"GfxThread":792},{"Serialization":520},{"JobScheduler":32768},{"String":506},{"HashMap":5120},{"PoolAlloc":192},{"CloudService":288},{"WebRequest":3563},{"VR":1864},{"Video":144},{"Tilemap":1536},{"NativeArray":648},{"Subsystems":96},{"CoreBusinessMetrics":120}]}


Log whether the trigger enter method runs. There’s a chance everything is in order but the UI may be scaled incorrectly. If you’ve never tested, or never even designed the UI to consider varying resolutions and aspect ratios you may simply face an issue where the UI you expect to see is simply moved off-screen. Especially when you use hard-coded / fixed offsets.

When you run the build I assume it runs fullscreen at the native desktop resolution. Make your game view use that exact resolution (you can add a custom resolution if it’s not in the list) and play the game in the editor to see if the UI appears as expected.

Thanks for your continued help on this, I really appreciate it.

I started by logging the OnTriggerEnter2D like you said, and that actually did start firing appropriately. Then I logged out each step, it looked like this.

    void OnTriggerEnter2D(Collider2D other)
    {
        Debug.Log("Player enters area");
        
        if (!other.CompareTag("Player")) 
        {   Debug.Log("Object is not tagged as player, returning out");
            return;
        } 
        
        if (hasRun)
        {
            Debug.Log("HasRun is on already, returning out");
            return; 
        }
        
        if (gameObject.CompareTag(("DialogueArea")))
        {
            Debug.Log("This object does indeed have the DialogueArea tag");

            if(isDialogueActive)
            {
                Debug.Log("Dialogue is already active, next line");
                NextLine();
            }
            else
            {
                Debug.Log("All is well, starting dialogue");
                StartDialogue();
                hasRun = true;
            }
        }

        Debug.Log("Nothing else triggered, ending method.");
    }

After doing that, the first log fired–the one saying “Object not tagged as player, returning out.” Very weird since the Player tag is built-in like we said, but I indulged it and commented out that code section.

After that, unfortunately, the OnTriggerEnter2D log still triggered, but then it just zipped through the rest of the code to the last log without triggering anything.

I guess then the conclusion would be that the dialogue area does not have the DialogueArea tag? But it does!

I’m interested in the UI scaling issue potentially being a problem. I will note that the other elements in the scene like the health markers and a toggleable UI grid are appearing okay, and they’re contained within the same UI canvas as the culprit that’s not working. Here’s a screenshot of what the built game looks like with the dialogue firing correctly at the NPC.

Scratch that, I think that log may have just been the NPC dialogue correctly firing and I mistook it for the automatic dialogue area because I forgot to include the tag in the log. :frowning:

I finally figured it out!!!

In case anybody finds this in the future. My problem turned out to be that the scene plugged into the build profile was NOT the one that I was using in-editor. They looked very similar but were not the same. A few months ago the project crashed and I had to create a recovery scene, but I’d never thought to plug that recovery scene into build profiles. So this whole time my build was building from that old pre-recovery scene three months ago. The pre-recovery default scene name is “SampleScene” and my recovered scene was just named “0”.

yes, that makes a lot of sense, it is important to be sure you’re using the real thing :smiley: