Forum begins after the advertisement:
[Part 25] I’m getting error-messages when creating a build.
Home › Forums › Video Game Tutorial Series › Creating a Rogue-like Shoot-em Up in Unity › [Part 25] I’m getting error-messages when creating a build.
- This topic has 7 replies, 3 voices, and was last updated 2 weeks, 2 days ago by
Alp Apustaja.
-
AuthorPosts
-
June 4, 2025 at 7:31 pm #18247::
Hey guys! After part 25 I’m not able to create a running build anymore. I get these error messages when trying to create a new build:
Assets\Scripts\UI\UILevelSelector.cs(57,19): error CS0246: The type or namespace name ‘SceneAsset’ could not be found (are you missing a using directive or an assembly reference?)
Assets\Scripts\UI\UILevelSelector.cs(41,16): error CS0246: The type or namespace name ‘SceneAsset’ could not be found (are you missing a using directive or an assembly reference?)
Error building Player because scripts had compiler errors
Build completed with a result of ‘Failed’ in 12 seconds (11507 ms) 3 errors UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
What can I do to fix this?
June 4, 2025 at 7:40 pm #18248::The error you’re encountering indicates that the
SceneAsset
type is not recognized in your script. This is likely becauseSceneAsset
is part of the UnityEditor namespace, which is not available in builds. Here are a few steps you can take to resolve this issue:-
Check the Namespace: Make sure you have the correct using directive at the top of your script:
using UnityEditor;
-
Conditional Compilation: If you’re using
SceneAsset
in code that will be included in a build, you need to wrap the code with a compilation directive to ensure it’s only included in the editor:#if UNITY_EDITOR using UnityEditor; // Your code that uses SceneAsset here #endif
-
Alternative Approach: If you need to reference scenes in your game logic and you’re trying to do this in a non-editor context (like at runtime), consider using string references for scene names instead of
SceneAsset
. You can then load scenes using their names with:SceneManager.LoadScene("SceneName");
-
Check for Other Issues: Ensure that there are no other missing references or compilation issues in your scripts that could be causing errors.
After making these changes, try rebuilding your project. This should resolve the errors you are seeing related to
SceneAsset
. If you still face issues, feel free to provide the specific code snippets in question for further assistance!June 4, 2025 at 7:51 pm #18250::Sadly, the last post wasn’t helpful. The Game runs perfect in the Editor but creating a build is still not possible.
June 4, 2025 at 7:52 pm #18251::Grim, you need to add directives to your code so that the
SceneAsset
is not compiled in builds (see yellow highlight).using System.Collections.Generic; using UnityEngine.SceneManagement; using UnityEditor; using UnityEngine.UI; using UnityEngine; using System.Text.RegularExpressions; using System; using System.Reflection; public class UILevelSelector : MonoBehaviour { public UISceneDataDisplay statsUI; public static int selectedLevel = -1; public static SceneData currentLevel; public List<SceneData> levels = new List<SceneData>(); [Header("Template")] public Toggle toggleTemplate; public string LevelNamePath = "Level Name"; public string LevelNumberPath = "Level Number"; public string LevelDescriptionPath = "Level Description"; public string LevelImagePath = "Level Image"; public List<Toggle> selectableToggles = new List<Toggle>(); public static BuffData globalBuff; public static bool globalBuffAffectsPlayer = false, globalBuffAffectsEnemies = false; public const string MAP_NAME_FORMAT = "^(Level .*?) ?- ?(.*)$"; [System.Serializable] public class SceneData { #if UNITY_EDITOR public SceneAsset scene; #endif public string sceneName; [Header("UI Display")] public string displayName; public string label; [TextArea] public string description; public Sprite icon; [Header("Modifiers")] public CharacterData.Stats playerModifier; public EnemyStats.Stats enemyModifier; [Min(-1)] public float timeLimit = 0f, clockSpeed = 1f; [TextArea] public string extraNotes = "--"; } public static List<string> GetAllSceneNames() { List<string> sceneNames = new List<string>(); #if UNITY_EDITOR string[] allAssetPaths = AssetDatabase.GetAllAssetPaths(); foreach (string assetPath in allAssetPaths) { if (assetPath.EndsWith(".unity")) { string sceneName = System.IO.Path.GetFileNameWithoutExtension(assetPath); if (Regex.IsMatch(sceneName, MAP_NAME_FORMAT)) { sceneNames.Add(sceneName); } } } #endif return sceneNames; } public void SceneChange(string name) { SceneManager.LoadScene(name); Time.timeScale = 1; } public void LoadSelectedLevel() { if (selectedLevel >= 0 && selectedLevel < levels.Count) { string sceneToLoad = levels[selectedLevel].sceneName; if (string.IsNullOrEmpty(sceneToLoad)) { Debug.LogError($"Scene name is empty for level index {selectedLevel}"); return; } if (!Application.CanStreamedLevelBeLoaded(sceneToLoad)) { Debug.LogError($"Scene '{sceneToLoad}' is not in Build Settings! Add it via File > Build Settings."); return; } Debug.Log($"Loading scene: {sceneToLoad}"); SceneManager.LoadScene(sceneToLoad); currentLevel = levels[selectedLevel]; selectedLevel = -1; Time.timeScale = 1f; } else { Debug.LogWarning("No level was selected!"); } } public void Select(int sceneIndex) { selectedLevel = sceneIndex; statsUI.UpdateFields(); globalBuff = GenerateGlobalBuffData(); globalBuffAffectsPlayer = globalBuff && IsModifierEmpty(globalBuff.variations[0].playerModifier); globalBuffAffectsEnemies = globalBuff && IsModifierEmpty(globalBuff.variations[0].enemyModifier); } public BuffData GenerateGlobalBuffData() { BuffData bd = ScriptableObject.CreateInstance<BuffData>(); bd.name = "Global Level Buff"; bd.variations[0].damagePerSecond = 0; bd.variations[0].duration = 0; bd.variations[0].playerModifier = levels[selectedLevel].playerModifier; bd.variations[0].enemyModifier = levels[selectedLevel].enemyModifier; return bd; } private static bool IsModifierEmpty(object obj) { Type type = obj.GetType(); FieldInfo[] fields = type.GetFields(); float sum = 0; foreach (FieldInfo f in fields) { object val = f.GetValue(obj); if (val is int) sum += (int)val; else if (val is float) sum += (float)val; } return Mathf.Approximately(sum, 0); } }
If that doesn’t solve the issue, please share your
UILevelSelector
script here.June 4, 2025 at 7:55 pm #18252::Could you provide the specific code from the
UILevelSelector.cs
script where theSceneAsset
is being used? Without seeing the exact implementation, I cannot pinpoint the precise cause of the build error.Specifically, I would like to see:
- The lines around lines 41 and 57 where the
SceneAsset
is referenced - Any using statements at the top of the script
- The context of how
SceneAsset
is being utilized
This additional context will help me provide a more targeted solution to your build issue.
June 4, 2025 at 8:05 pm #18253::Thank you! If I change the script as you recommended, the “UILevelSelectorEditor.cs” creates an error:
“UILevelSelector” has no definition for “GetAllMaps”.
June 4, 2025 at 8:11 pm #18254::The error you’re encountering indicates that the
UILevelSelector
class does not have a method calledGetAllMaps
. This issue is likely due to changes made in yourUILevelSelector
script, possibly related to removing or modifying the way you handle scenes.Here are some steps to resolve this issue:
-
Check
UILevelSelector
Class: Ensure that theGetAllMaps
method is defined in yourUILevelSelector
class. If it was removed or renamed, you’ll need to update theUILevelSelectorEditor.cs
script accordingly.Example of how it might look:
public class UILevelSelector : MonoBehaviour { // Add the GetAllMaps method back if it was removed public List GetAllMaps() { // Implementation to get all maps } }
-
Update
UILevelSelectorEditor.cs
: If you updated theUILevelSelector
class and no longer need theGetAllMaps
method, you’ll want to either remove or comment out any references toGetAllMaps
in yourUILevelSelectorEditor.cs
script.For example:
// Example of how you might be using it in the Editor script List maps = uiLevelSelector.GetAllMaps();
If
GetAllMaps
is no longer applicable, you need to replace or remove this line based on your new implementation. -
Consider Alternative Logic: If you changed how you handle scene references (for instance, switching to string references), make sure your editor class reflects those changes. Define a new method or structure that fits your new logic.
-
Check for Compilation Errors: After making these changes, ensure there are no other compilation errors in your scripts. Unity does not allow builds to proceed if any scripts contain errors.
If you can share the relevant portions of both the
UILevelSelector
andUILevelSelectorEditor
scripts, I can provide more specific guidance on how to modify them accordingly.June 4, 2025 at 8:19 pm #18255::This is my UILevelSelector.cs
using System.Collections.Generic; using UnityEngine.SceneManagement; using UnityEditor; using UnityEngine.UI; using UnityEngine; using System.Text.RegularExpressions; using System; using System.Reflection; public class UILevelSelector : MonoBehaviour { public UISceneDataDisplay statsUI; public static int selectedLevel = -1; public static SceneData currentLevel; public List<SceneData> levels = new List<SceneData>(); [Header("Template")] public Toggle toggleTemplate; public string LevelNamePath = "Level Name"; public string LevelNumberPath = "Level Number"; public string LevelDescriptionPath = "Level Description"; public string LevelImagePath = "Level Image"; public List<Toggle> selectableToggles = new List<Toggle>(); // The level modifiers will be applied to players and enemies using a buff. // The buff data is stored in this static variable. public static BuffData globalBuff; // Whenever a globalBuff is applied, we will check whether the buff has any // effect on the player or enemies and record them here. If there isn't, we don't // apply the buff to save overhead. public static bool globalBuffAffectsPlayer = false, globalBuffAffectsEnemies = false; // This is the regex which is used to identify which maps are level maps. public const string MAP_NAME_FORMAT = "^(Level .*?) ?- ?(.*)$"; [System.Serializable] public class SceneData { #if UNITY_EDITOR public SceneAsset scene; #endif [Header("UI Display")] public string displayName; public string label; [TextArea] public string description; public Sprite icon; [Header("Modifiers")] public CharacterData.Stats playerModifier; public EnemyStats.Stats enemyModifier; [Min(-1)] public float timeLimit = 0f, clockSpeed = 1f; [TextArea] public string extraNotes = "--"; } public static SceneAsset[] GetAllMaps() { List<SceneAsset> maps = new List<SceneAsset>(); // Populate the list with all Scenes starting with "Level -" (Editor only). #if UNITY_EDITOR string[] allAssetPaths = AssetDatabase.GetAllAssetPaths(); foreach (string assetPath in allAssetPaths) { if (assetPath.EndsWith(".unity")) { SceneAsset map = AssetDatabase.LoadAssetAtPath<SceneAsset>(assetPath); if (map != null && Regex.IsMatch(map.name, MAP_NAME_FORMAT)) { maps.Add(map); } } } #else Debug.LogWarning("This function cannot be called on builds."); #endif maps.Reverse(); return maps.ToArray(); } // For normal scene changes. public void SceneChange(string name) { SceneManager.LoadScene(name); Time.timeScale = 1; } // To load a level from the level select screen. public void LoadSelectedLevel() { if (selectedLevel >= 0) { SceneManager.LoadScene(levels[selectedLevel].scene.name); currentLevel = levels[selectedLevel]; selectedLevel = -1; Time.timeScale = 1f; } else { Debug.LogWarning("No level was selected!"); } } // Selects a scene that will be loaded with LoadSelectedLevel(). // Also creates the buff that will be applied on that level, and checks if // the modifier variables are empty (which are used by PlayerStats and EnemyStats). public void Select(int sceneIndex) { selectedLevel = sceneIndex; statsUI.UpdateFields(); globalBuff = GenerateGlobalBuffData(); globalBuffAffectsPlayer = globalBuff && IsModifierEmpty(globalBuff.variations[0].playerModifier); globalBuffAffectsEnemies = globalBuff && IsModifierEmpty(globalBuff.variations[0].enemyModifier); } // Generate a BuffData object to wrap around the playerModifer and enemyModifier variables. public BuffData GenerateGlobalBuffData() { BuffData bd = ScriptableObject.CreateInstance<BuffData>(); bd.name = "Global Level Buff"; bd.variations[0].damagePerSecond = 0; bd.variations[0].duration = 0; bd.variations[0].playerModifier = levels[selectedLevel].playerModifier; bd.variations[0].enemyModifier = levels[selectedLevel].enemyModifier; return bd; } // Used to check if the playerModifier or enemyModifier of the global buff is empty. private static bool IsModifierEmpty(object obj) { Type type = obj.GetType(); FieldInfo[] fields = type.GetFields(); float sum = 0; foreach (FieldInfo f in fields) { object val = f.GetValue(obj); if (val is int) sum += (int)val; else if (val is float) sum += (float)val; } return Mathf.Approximately(sum, 0); } }
June 4, 2025 at 8:20 pm #18256::This is my “UILevelSelectorEditor.cs”
using UnityEditor; using UnityEngine; using UnityEngine.UI; using TMPro; using UnityEditor.Events; using System.Linq; using System.Text.RegularExpressions; [DisallowMultipleComponent] [CustomEditor(typeof(UILevelSelector))] public class UILevelSelectorEditor : Editor { UILevelSelector selector; void OnEnable() { // Point to the UILevelSelector when it's in the inspector so its variables can be accessed. selector = target as UILevelSelector; } public override void OnInspectorGUI() { // Create a button in the inspector with the name, that creates the level structs/templates when clicked. base.OnInspectorGUI(); // If a Toggle Template isn't set, show a warning that the button will not completely work. if (!selector.toggleTemplate) EditorGUILayout.HelpBox( "You need to assign a Toggle Template for the button below to work properly.", MessageType.Warning ); if (GUILayout.Button("Find and Populate Levels")) { PopulateLevelsList(); CreateLevelSelectToggles(); } } // Function that finds all Scene files in our project, and assigns them to the levels list. public void PopulateLevelsList() { // Record the changes made to the UILevelSelector component as undoable and clears any null scenes (i.e. deleted/missing scenes) from the lists. Undo.RecordObject(selector, "Create New SceneData structs"); SceneAsset[] maps = UILevelSelector.GetAllMaps(); // Record a list of scenes that are already in. selector.levels.RemoveAll(levels => levels.scene == null); foreach (SceneAsset map in maps) { // If the current scene we are checking isn't in the Level list. // We exclude all scenes that are already in to avoid overwriting the user's settings. if (!selector.levels.Any(sceneData => sceneData.scene == map)) { // Extract information from the map name using regex. Match m = Regex.Match(map.name, UILevelSelector.MAP_NAME_FORMAT, RegexOptions.IgnoreCase); string mapLabel = "Level", mapName = "New Map"; if (m.Success) { if (m.Groups.Count > 1) mapLabel = m.Groups[1].Value; if (m.Groups.Count > 2) mapName = m.Groups[2].Value; } // Create a new SceneData object, initialise it with default variables, and add it to the levels list. selector.levels.Add(new UILevelSelector.SceneData { scene = map, label = mapLabel, displayName = mapName }); } } } // With a Toggle Template assigned, this function will create the UI toggles // that we can use to select the levels in-game. public void CreateLevelSelectToggles() { // If the toggle template is not assigned, leave a warning and abort. if (!selector.toggleTemplate) { Debug.LogWarning("Failed to create the Toggles for selecting levels. Please assign the Toggle Template."); return; } // Loop through all the children of the parent of the toggle template, // and deleting everything under it except the template. for (int i = selector.toggleTemplate.transform.parent.childCount - 1; i >= 0; i--) { Toggle tog = selector.toggleTemplate.transform.parent.GetChild(i).GetComponent<Toggle>(); if (tog == selector.toggleTemplate) continue; Undo.DestroyObjectImmediate(tog.gameObject); // Record the action so we can undo. } // Record the changes made to the UILevelSelector component as undoable and clears the toggle list. Undo.RecordObject(selector, "Updates to UILevelSelector."); selector.selectableToggles.Clear(); // For every level struct in the level selector, we create a toggle for them in the level selector. for (int i = 0; i < selector.levels.Count; i++) { Toggle tog; if (i == 0) { tog = selector.toggleTemplate; Undo.RecordObject(tog, "Modifying the template."); } else { tog = Instantiate(selector.toggleTemplate, selector.toggleTemplate.transform.parent); // Create a toggle of the current character as a child of the original template's parent. Undo.RegisterCreatedObjectUndo(tog.gameObject, "Created a new toggle."); } tog.gameObject.name = selector.levels[i].scene.name; // Finding the level name, number, description and image to assign. Transform levelName = tog.transform.Find(selector.LevelImagePath).Find("Name Holder").Find(selector.LevelNamePath); if (levelName && levelName.TryGetComponent(out TextMeshProUGUI lvlName)) { lvlName.text = selector.levels[i].displayName; } Transform levelNumber = tog.transform.Find(selector.LevelImagePath).Find(selector.LevelNumberPath); if (levelNumber && levelNumber.TryGetComponent(out TextMeshProUGUI lvlNumber)) { lvlNumber.text = selector.levels[i].label; } Transform levelDescription = tog.transform.Find(selector.LevelDescriptionPath); if (levelDescription && levelDescription.TryGetComponent(out TextMeshProUGUI lvlDescription)) { lvlDescription.text = selector.levels[i].description; } Transform levelImage = tog.transform.Find(selector.LevelImagePath); if (levelImage && levelImage.TryGetComponent(out Image lvlImage)) lvlImage.sprite = selector.levels[i].icon; selector.selectableToggles.Add(tog); // Remove all select events and add our own event that checks which character toggle was clicked. for (int j = 0; j < tog.onValueChanged.GetPersistentEventCount(); j++) { if (tog.onValueChanged.GetPersistentMethodName(j) == "Select") { UnityEventTools.RemovePersistentListener(tog.onValueChanged, j); } } UnityEventTools.AddIntPersistentListener(tog.onValueChanged, selector.Select, i); } // Registers the changes to be saved when done. EditorUtility.SetDirty(selector); } }
June 4, 2025 at 8:21 pm #18257::Based on the code you’ve provided, the issue is that the
SceneAsset
type is part of the UnityEditor namespace, which is not available in builds. To resolve this, you need to modify the code to use conditional compilation and ensure thatSceneAsset
-related code only runs in the Unity Editor.Here’s a solution:
- In the
UILevelSelector.cs
script, modify theSceneData
class andGetAllMaps()
method:
[System.Serializable] public class SceneData { #if UNITY_EDITOR public SceneAsset scene; #endif public string sceneName; // Add this field to store scene name for builds // Rest of the existing code... } #if UNITY_EDITOR public static SceneAsset[] GetAllMaps() { List maps = new List(); string[] allAssetPaths = AssetDatabase.GetAllAssetPaths(); foreach (string assetPath in allAssetPaths) { if (assetPath.EndsWith(".unity")) { SceneAsset map = AssetDatabase.LoadAssetAtPath(assetPath); if (map != null && Regex.IsMatch(map.name, MAP_NAME_FORMAT)) { maps.Add(map); } } } maps.Reverse(); return maps.ToArray(); } #endif // Modify LoadSelectedLevel method public void LoadSelectedLevel() { if (selectedLevel >= 0) { #if UNITY_EDITOR SceneManager.LoadScene(levels[selectedLevel].scene.name); #else SceneManager.LoadScene(levels[selectedLevel].sceneName); #endif currentLevel = levels[selectedLevel]; selectedLevel = -1; Time.timeScale = 1f; } else { Debug.LogWarning("No level was selected!"); } }
- In the
UILevelSelectorEditor.cs
script, update thePopulateLevelsList()
method:
public void PopulateLevelsList() { Undo.RecordObject(selector, "Create New SceneData structs"); #if UNITY_EDITOR SceneAsset[] maps = UILevelSelector.GetAllMaps(); selector.levels.RemoveAll(levels => levels.scene == null); foreach (SceneAsset map in maps) { if (!selector.levels.Any(sceneData => sceneData.scene == map)) { Match m = Regex.Match(map.name, UILevelSelector.MAP_NAME_FORMAT, RegexOptions.IgnoreCase); string mapLabel = "Level", mapName = "New Map"; if (m.Success) { if (m.Groups.Count > 1) mapLabel = m.Groups[1].Value; if (m.Groups.Count > 2) mapName = m.Groups[2].Value; } selector.levels.Add(new UILevelSelector.SceneData { scene = map, sceneName = map.name, // Add this line label = mapLabel, displayName = mapName }); } } #endif }
These changes will:
- Add a
sceneName
field to store the scene name for builds - Wrap editor-specific code in
#if UNITY_EDITOR
preprocessor directives - Ensure that scene loading works both in the editor and in builds
Make sure to save the scripts and rebuild your project. This should resolve the build errors you were experiencing.
June 4, 2025 at 8:21 pm #18258June 4, 2025 at 8:25 pm #18259June 4, 2025 at 8:38 pm #18260June 4, 2025 at 8:41 pm #18261::The issue likely stems from how scene names are being handled in the build. In the modified code, you’re using
levels[selectedLevel].sceneName
, but this might not be correctly set during the build process.Potential solutions:
- Ensure
sceneName
is correctly populated during build - Add debug logging to verify the scene name being used
- Manually set scene names in the inspector for each level
Can you confirm:
- Are the scene names in the
sceneName
field exactly matching the scene names in Build Settings? - Have you added all relevant scenes to the Build Settings?
- Can you add a debug log in
LoadSelectedLevel()
to print out the scene name being used?
has upvoted this post. June 4, 2025 at 8:59 pm #18263 -
-
AuthorPosts
- You must be logged in to reply to this topic.