Unity build not building game correctly - c#

So when I tried to build my unity project the options menu did not build correctly. I tried two unity version, a hard restart of my system, and changing settings. Nothing corrected the issue. The game works fine in the unity editor but does not work correctly when built.
Editor drop-down (How it should be):
Build drop-down (How it should not be):
If you look in the build picture it duplicates all the drop-down entries which may be cause by the script that generates it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
public class OptionsMenu : MonoBehaviour
{
public AudioMixer audioMixer;
public Dropdown resolutionDropdown;
Resolution[] resolutions;
void Start()
{
resolutions = Screen.resolutions;
resolutionDropdown.ClearOptions();
List<string> options = new List<string>();
int currentResolutionIndex = 0;
for (int i = 0; i < resolutions.Length; i++)
{
string option = resolutions[i].width + "X" + resolutions[i].height;
options.Add(option);
if (resolutions[i].width == Screen.currentResolution.width && resolutions[i].height == Screen.currentResolution.height)
{
currentResolutionIndex = i;
}
}
resolutionDropdown.AddOptions(options);
resolutionDropdown.value = currentResolutionIndex;
resolutionDropdown.RefreshShownValue();
The other problem is with the quality dropdown, In the editor it works fine but when I build it it does not change the game quality (It stays on low).
The other problem has only occurred on one build. The problem was that the mouse sensitivity to move the camera was very low, when I built it again the problem was fixed.

For duplicates, it's a known problem: the problem is on standalone where it appears to duplicate each resolution with refresh rates of 60Hz and 48Hz.
For example: 640x480#48Hz; 640x480#60Hz; etc
A solution could be a Linq statement, selecting only 60Hz frequencies (or 48Hz):
var resolutionsIEnumerable = Screen.resolutions.Where(resolution => resolution.refreshRate == 60);
resolutions = resolutionsIEnumerable.toArray();
Linq Where() returns IEnumerable so, you have to convert to array Resolution[] (with toArray())
In order to change resolution, you have to use
Screen.SetResolution(640, 480, true, 60);
You should change 640 and 480 on dropdown change with the selected resolution.

Related

Unity Script only works with long namespace name

I tried following this Unity ECS Entity Manager Tutorial from Turbo Makes Games.
I'm using Unity 2020.3.20f1.1086.
The Code works initially but I noticed, that Line 20 in SpawnEntitiesSystem.cs EntityManager.SetComponentData(newEntity, newPosition); stops working when I change or remove the namespace. After tinkering a bit with the code I can reproduce that the specific namespace is not important but the namespace has to be at least 18 characters long for the code to work as expected. If I change the namespace to 17 characters all entities are spawned at the same place. Other code after the faulty line 20 was executed but for readability I removed it from the code example. (Originally user input was also handled and in OnStartRunning a component was added to the new entitiy)
I only heard of similar problems in e.g. C++ when using pointer maths but I thought something like this shouldn't happen in C#. Does anyone have an idea what the core problem could be?
What I already tried without succes
restart Unity
delete Library, Obj and Logs folders
write code from scratch in new project
restart PC
SpawnEntitiesSystem.cs
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
namespace ALongNamespaceABCD {
public class SpawnEntitiesSystem : SystemBase {
private int2 _entitySpacing;
protected override void OnStartRunning() {
var entitySpawnData = GetSingleton<EntitySpawnData>();
var gridSize = entitySpawnData.SpawnGrid;
_entitySpacing = entitySpawnData.EntitySpacing;
for (int x = 0; x < gridSize.x; x++) {
for (int y = 0; y < gridSize.y; y++) {
var newEntity = EntityManager.Instantiate(entitySpawnData.EntityPrefab);
var newPosition = new LocalToWorld { Value = CalculateTransform(x, y) };
EntityManager.SetComponentData(newEntity, newPosition);
}
}
}
private float4x4 CalculateTransform(int x, int y) {
return float4x4.Translate(new float3 {
x = x * _entitySpacing.x,
y = 1f,
z = y * _entitySpacing.y
});
}
protected override void OnUpdate() {}
}
}
EntitySpawnData
using Unity.Entities;
using Unity.Mathematics;
[GenerateAuthoringComponent]
public struct EntitySpawnData : IComponentData {
public Entity EntityPrefab;
public int2 SpawnGrid;
public int2 EntitySpacing;
}
Edit:
I tried around a bit more and found out that it seems that the correct position will be set correctly at first. But it will instantly be overwritten by the prefabs Transform component. So maybe it has to do with converting the Prefab to an entity (I use the default Convert to Entity component) or a problem with some internal multithreading occurs.
Well, we finally got a response from Unity. Here is what they said:
This is intended behavior and will therefore be set to "won't fix".
The reasons are this:
Changing the name (and namespace) of a system changes its default position in the frame, this is expected behavior.
The SpawnEntitiesSystem from the provided repro project is not using any explicit system ordering attribute like
UpdateAfter/UpdateBefore/UpdateInGroup, so it follows the default.
Because it is expected behavior but nonetheless surprising, we have a task in the backlog about making the default order not depend on the
name in the future.
The prefab being instantiated has a Translation component and a Rotation component in addition to the LocalToWorld component.
The transform system from entities updates LocalToWorld based on the values of Translation and Rotation.
A direct modification of LocalToWorld conflicts with the transform system, and that modification will be overwritten.
Because Translation and Rotation are still at their default values, the expected outcome is that the transform system will compute an
identity LocalToWorld and put the instances back to the origin.
Unfortunately there is a bug in that particular setup (where the system doing the modification does it in OnStartRunning and executes
immediately after the transform system, if the namespace is long
enough to put it after the transform system) that causes the newly
spawned instances to never be noticed by the transform system. And it
is because of that bug that the cubes would show in the intended grid
layout by accident.
Source: https://issuetracker.unity3d.com/issues/entity-localtoworld-position-is-overwritten-by-prefab-position-when-namespace-is-17-characters-long-or-shorter
So, apparently, this whole situation happens because the LocalToWorld is sometimes being overwritten due to operation ordering that the length of the namespace is able to change. But this won't be the case in a future version.
A workaround is to set the Translation instead of the LocalToWorld Data.
Working code:
EntityManager.SetComponentData(newEntity, new Translation {
Value = new float3(
10.0f,
1.0f,
10.0f
)
});

How can I make a destroyer that destroys all the overtaken platforms in unity?

I'm doing a unity project for an exam I'm attending, so I'm not really good at unity, hope you can help.
I'm doing this 2d endless runner game and I created an empty object to set inactive all the platforms that the player has overtaken. The object moves forward and when its position is > than the platform position, it sets it inactive (since destroying them also removes them from the list so it wouldnt work for others platforms of the same kind). My problem is that I've created a list in which I put all the types of my prefabs but the way I did it, it only sets inactive the first prefab of a kind and then stops working.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DistruttoreLivelli : MonoBehaviour
{
public List<GameObject> objs;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < objs.Count; i++)
{
if (objs[i].transform.position.x < transform.position.x)
{
objs[i].SetActive(false);
}
}
}
}
How can I manage to make it go forever? I tried to use a while but it makes unity crash. :/
Ty for the help!
The easiest way to make it endless is to move the objects to the furthest position instead of deactivating them. Instead of objs[i].SetActive(false); it should be something like:
Vector3 endOfTheLinePos = objs[i].transform.position;
endOfTheLinePos .x = maxX;
objs[i].transform.position = endOfTheLinePos;
With maxX being a float parameter of the highest value of x that you are using on the objects.
Also, as already pointed out, on the for you should use i < objs.Count instead.

How to check how many scenes are in a build in Unity

I'm building a mobile game with many scenes (AKA Levels) in Unity, I also intend on adding more levels through updates later in the games life cycle. To cope with this I am attempting the make an automated script that see's how many scenes there are in the Unity build, and create corresponding UI buttons based on a prefab.
For clarity sake I'll note that when I say "scenes that are in ther Unity Build", I mean scenes that are in the build menu:
And already have an index number.
It's not a lot but here is my current script which I have a levelManager in the scene:
private Scene[] levels;
private void Start()
{
/// This is the line I'm requesting help with
levels = // Some way of getting all the scene's in a project put in an array
foreach (var item in levels)
{
// I will handle the button creation and modification later that will go here
}
}
As said you don't create that variable yourself but rather can simply read out SceneManager.sceneCountInBildSettings and then use SceneManager.GetSceneByBuildIndex in order to iterate and get all these scenes like
// Adjust this in the Inspector
// Set this to the index of level 1
[SerializeField] private int startIndex = 1;
var sceneCount = SceneManager.sceneCountInBildSettings;
levels = new Scene[sceneCount - startIndex];
for(var i = startIndex; i < sceneCount; i++)
{
level[i] = SceneManager.GetSceneByBuildIndex(i);
}
Alternatively you could also do it already before runtime via an editor script using EditorBuildSettings.scenes e.g.
#if UNITY_EDITOR
using UnityEditor;
#endif
...
// Make this field serialized so it gets stored together with the scene
[SerializeField] private Scene[] levels;
#if UNITY_EDITOR
[ContextMenu(nameof(StoreScenes))]
private void StoreScenes()
{
levels = EditorBuildSettings.scenes;
EditorUtility.SetDirty(this);
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
}
#endif
you would run this method before the build by going to the Inspector of your component, open the context menu and hit StoreScenes and it will fill your array. The #if UNITY_EDITOR has to wrap anything using the UnityEditor namespace as it will be stripped of in a build and you would get build exceptions otherwise.

Unity ECS doesn't show created entites since package Update

I tried to spawn some entities and assign a mesh and material to them. Somehow they do not appear, neither in the Editor nor the gameview. When I use a "GameObjectToEntity" Conversion Script the Entity does appear, I tried the new Alpha Version of the Editor (2020.1.0a25) but it didnt help. I'm also using the URP. It might be connected to the updating the preview packagets (Entities, Hybrid Render etc.) since I don't have the problem in a different project where I'm using older versions.
I might have missed something in my Code though.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;
using Unity.Rendering;
using Unity.Transforms;
using Unity.Mathematics;
using Unity.Collections;
public class EntityCreator : MonoBehaviour
{
[SerializeField] public Mesh theMesh;
[SerializeField] public Material theMaterial;
// Start is called before the first frame update
void Start()
{
EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
EntityArchetype eArch = entityManager.CreateArchetype(
typeof(RenderMesh),
typeof(Translation),
typeof(LocalToWorld),
typeof(MoveSpeedComponent)
);
NativeArray<Entity> eArray = new NativeArray<Entity>(10, Allocator.Temp);
entityManager.CreateEntity(eArch, eArray);
foreach (Entity ent in eArray)
{
entityManager.SetComponentData(ent, new Translation { Value = new Vector3(0f,0f, 0f) });
entityManager.SetSharedComponentData(ent, new RenderMesh
{
mesh = theMesh, material = theMaterial
});
}
eArray.Dispose();
}
}
Thanks a lot for taking the time
EntityArchetype eArch =
entityManager.CreateArchetype(
typeof(RenderMesh),
typeof(Translation),
typeof(LocalToWorld),
typeof(MoveSpeedComponent),
typeof(RenderBounds));

Why I'm getting duplicated resolutions values in the dropdown ui after changing resolution?

The resolutions changing is taking affect only when running the game from the built exe file.
When running the game I have 19 resolutions in the dropdown ui.
The first resolution is 640 x 480 and the last one and the current one is 2910 x 1080
When running the game from the built exe file and changing the resolutions for example from 640 x 480 to 720 x 480 or to 1920 x 1080 it will change the resolution but it will also duplicate the resolutions many times in the dropdown ui.
Screenshot when running the game from the exe built file. Even before changing/selecting any resolution I see them duplicated. For example the 640 x 480 is 7 times duplicated the next resultion is duplicated 5 times I think and so on...the last 1920 x 1080 is also 5 or 7 times duplicated.
It seems each resolution is duplicated few times.
But it's not duplicated in the editor only in the exe built file.
The script I'm using :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;
public class SettingsMenu : MonoBehaviour
{
public AudioMixer audioMixer;
public Text volumeInPercentages;
public Dropdown resolutionDropDown;
[SerializeField]
private Slider _volumeSlider;
[SerializeField]
private Dropdown _dropDownQuality;
private Resolution[] resolutions;
private void Start()
{
resolutions = Screen.resolutions;
resolutionDropDown.ClearOptions();
List<string> options = new List<string>();
int currentResolutionIndex = 0;
for (int i = 0; i < resolutions.Length; i++)
{
string option = resolutions[i].width + " x " + resolutions[i].height;
options.Add(option);
if (resolutions[i].width == Screen.currentResolution.width &&
resolutions[i].height == Screen.currentResolution.height)
{
currentResolutionIndex = i;
}
}
resolutionDropDown.AddOptions(options);
resolutionDropDown.value = currentResolutionIndex;
resolutionDropDown.RefreshShownValue();
}
public void SetVolume()
{
float volume = _volumeSlider.value;
Debug.Log("Volume " + volume);
audioMixer.SetFloat("MusicVol", Mathf.Log10(volume) * 20);
volumeInPercentages.text = Mathf.Round(volume * 100).ToString() + " %";
}
public void SetQuality()
{
int qualityIndex = _dropDownQuality.value;
QualitySettings.SetQualityLevel(qualityIndex);
}
public void SetFullScreen()
{
Screen.fullScreen = !Screen.fullScreen;
}
public void SetResolution()
{
Resolution resolution = resolutions[resolutionDropDown.value];
Screen.SetResolution(resolution.width, resolution.height, Screen.fullScreen);
}
}
And a screenshot of the ui dropdown inspector settings :
The SettingsMenu script is attached to the Canvas under the Main Menu.
This is because Unity differentiates between different refresh rates for the same resolution.
For example:
640x480 #60Hz is a separate resolution option from 640x480 #144Hz.
You can't see this easily if you're displaying only the height and width of the display, but debugging does reveal that this is the case.
I've had this issue before and my fix for this was to keep track of the Width and Height when adding options to the dropdown.
My solution was to cache the width and height of the resolution and compare it to the next option's width and height. If either was different I'd cache that, add a new option and then continue iterating over the options.
You can see in the documentation that the Resolution also contains the field for refreshRate.

Categories