- Home /
Alternative for System.Collections.Generic.List, to reduce build size.
Hello, I just finished, built and uploaded my game to the Google Play Store and I just noticed that the build size is quite big considering it's actual functionality. All the game does is show you some text and some icons and then change the text and icons when you tap. The text and the icons come from a list.
I read that you can reduce the size of your build by avoiding System.dll, but in order to use the list I need System.generics. So I am looking for an alternative to the list so that I can reduce the size of mye build. Also any other tips on how to reduce the size of the game is very welcome.
Here is my editor log, showing what makes up the size of the build, as well as the dlls I'm using.
Textures 235.2 kb 4.7%
Meshes 0.0 kb 0.0%
Animations 0.0 kb 0.0%
Sounds 0.0 kb 0.0%
Shaders 175.5 kb 3.5%
Other Assets 45.9 kb 0.9%
Levels 7.3 kb 0.1%
Scripts 482.5 kb 9.7%
Included DLLs 3.9 mb 80.8%
File headers 8.5 kb 0.2%
Complete size 4.9 mb 100.0%
Mono dependencies included in the build
Dependency assembly - Mono.Security.dll
Dependency assembly - System.Core.dll
Dependency assembly - System.dll
Dependency assembly - mscorlib.dll
Dependency assembly - UnityEngine.Advertisements.dll
Dependency assembly - UnityEngine.UI.dll
Dependency assembly - UnityEngine.Networking.dll
Dependency assembly - Assembly-CSharp.dll
As you can see, dlls take up more than 75% of the size, which is inconvenient.
Here's how I use the List
using UnityEngine;
using System.Collections.Generic;
public class ListOfStatements : MonoBehaviour {
List<Statement> statements;
public List<Statement> shuffledList;
// Use this for initialization
void Awake () {
statements = new List<Statement>();
shuffledList = new List<Statement>();
FillList();
for (int i = 0; i < statements.Count;)
{
int r = Random.Range(0, statements.Count);
shuffledList.Add(statements[r]);
statements.Remove(statements[r]);
}
foreach (Statement s in shuffledList)
{
Debug.Log(s.text + " " + s.drinks + " " + s.category);
}
}
// Update is called once per frame
void FillList ()
{
statements.Add(new Statement("Vært vikar", 1, 1));
statements.Add(new Statement("Vært barnevakt", 2, 1));
statements.Add(new Statement("Bygd trehytte", 1, 1));
statements.Add(new Statement("Gravd en snøhule", 1, 1));
These are just 4 of the 300 or so statements in my List.
This is a Statement
public class Statement
{
public string text;
public int drinks;
public int category;
public Statement(string _text, int _drinks, int _category)
{
text = _text;
drinks = _drinks;
category = _category;
}
}
Aaand here's how I change the statements
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Advertisements;
public class StatementManager : MonoBehaviour {
public Text currentStatement;
public GameObject oneDrink, threeDrink, fiveDrink, oneShot;
GameObject currentDrink;
ListOfStatements listOfStatements;
int listIndex = 0;
public bool ranOnce = false;
int adIndex = 15;
void Awake()
{
listOfStatements = GetComponent<ListOfStatements>();
}
void Start()
{
currentStatement.text = listOfStatements.shuffledList[0].text;
ChangeIcon();
}
public void ChangeText()
{
if (!ranOnce)
{
if (listIndex == adIndex)
{
adIndex += 15;
//ShowDefaultAd();
}
ranOnce = true;
listIndex++;
Destroy(currentDrink);
currentStatement.text = listOfStatements.shuffledList[listIndex].text;
ChangeIcon();
}
if (listIndex == listOfStatements.shuffledList.Count-1)
{
listIndex = 0;
}
}
void ChangeIcon()
{
switch (listOfStatements.shuffledList[listIndex].drinks)
{
case 1:
currentDrink = Instantiate(oneDrink);
break;
case 2:
currentDrink = Instantiate(threeDrink);
break;
case 3:
currentDrink = Instantiate(fiveDrink);
break;
case 4:
currentDrink = Instantiate(oneShot);
break;
}
}
using UnityEngine;
public class TouchManager : MonoBehaviour
{
StatementManager statementManager;
void Awake()
{
statementManager = GetComponent<StatementManager>();
}
void Update()
{
if (Input.touchCount > 0)
{
statementManager.ChangeText();
}
if (Input.touchCount < 1)
{
statementManager.ranOnce = false;
}
}
}
Basicly, every Statement has a String and an int that decides what Text to show and which icon to show with it. The Statement has an int Category as well, which is not used in this build, but is in there for integrating a new function later.
I need a list or an array to hold these Statements and let me sequentially cycle through them.
Also, if you have any ideas on optimizing the shuffling of the List, I'd gladly accept.
Answer by Mindmapfreak · Oct 03, 2016 at 08:09 PM
EDIT: The following does not work, see Bunny83's comment below.
You can just use the relevant code from the reference source, remove the Contract statements and replace the ThrowHelper statements. The following code should work, but bear in mind that this snippet only contains the functions you use in your code. However, it should be fairly simple to add other functions if needed. You also still have to use System and it probably would not be worthwhile to replace the classes from System with the reference code, but hopefully the size gets small enough without System.Collections.Generic.
using System;
public interface IEnumerator
{
bool MoveNext();
System.Object Current
{
get;
}
void Reset();
}
public interface IEnumerator<out T> : IDisposable, IEnumerator
{
new T Current
{
get;
}
}
public class List<T>
{
private const int _defaultCapacity = 4;
private T[] _items;
private int _size;
private int _version;
static readonly T[] _emptyArray = new T[0];
public int Capacity
{
get
{
return _items.Length;
}
set
{
if (value < _size)
{
throw new ArgumentOutOfRangeException();
}
if (value != _items.Length)
{
if (value > 0)
{
T[] newItems = new T[value];
if (_size > 0)
{
Array.Copy(_items, 0, newItems, 0, _size);
}
_items = newItems;
}
else
{
_items = _emptyArray;
}
}
}
}
public int Count
{
get
{
return _size;
}
}
public List()
{
_items = _emptyArray;
}
private void EnsureCapacity(int min)
{
if (_items.Length < min)
{
int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2;
if ((uint)newCapacity > System.Int32.MaxValue) newCapacity = System.Int32.MaxValue;
if (newCapacity < min) newCapacity = min;
Capacity = newCapacity;
}
}
public T this[int index]
{
get
{
if ((uint)index >= (uint)_size)
{
throw new ArgumentOutOfRangeException();
}
return _items[index];
}
set
{
if ((uint)index >= (uint)_size)
{
throw new ArgumentOutOfRangeException();
}
_items[index] = value;
_version++;
}
}
public void Add(T item)
{
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
_version++;
}
public int IndexOf(T item)
{
return Array.IndexOf(_items, item, 0, _size);
}
public void RemoveAt(int index)
{
if ((uint)index >= (uint)_size)
{
throw new ArgumentOutOfRangeException();
}
_size--;
if (index < _size)
{
Array.Copy(_items, index + 1, _items, index, _size - index);
}
_items[_size] = default(T);
_version++;
}
public bool Remove(T item)
{
int index = IndexOf(item);
if (index >= 0)
{
RemoveAt(index);
return true;
}
return false;
}
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
[Serializable]
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private List<T> list;
private int index;
private int version;
private T current;
internal Enumerator(List<T> list)
{
this.list = list;
index = 0;
version = list._version;
current = default(T);
}
public void Dispose()
{
}
public bool MoveNext()
{
List<T> localList = list;
if (version == localList._version && ((uint)index < (uint)localList._size))
{
current = localList._items[index];
index++;
return true;
}
return MoveNextRare();
}
private bool MoveNextRare()
{
if (version != list._version)
{
throw new InvalidOperationException();
}
index = list._size + 1;
current = default(T);
return false;
}
public T Current
{
get
{
return current;
}
}
System.Object IEnumerator.Current
{
get
{
if (index == 0 || index == list._size + 1)
{
throw new InvalidOperationException();
}
return Current;
}
}
void IEnumerator.Reset()
{
if (version != list._version)
{
throw new InvalidOperationException();
}
index = 0;
current = default(T);
}
}
}
This looks awesome, thank you. I'm not that proficient at this stuff yet, so it'll take me a bit of time to understand and implement this, but I'll try it out and let you know how it plays out. Cheers, mate!
Sorry nut all that work is pointless and actually will increase the build size. The generic List is defined inside the mscorlib and not inside System.dll. A lot people seem to confuse the concept of namespaces with the concept of assemblies. The name of an assembly has no relation to the namespaces it contains. Actually most "System" and child namespaces of System are defined in the mscorlib. Only a few special classes are inside the System.dll or other assemblies.
If you want to track down what classes might be responsible i strongly recommend using ILSpy and have a look into the System.dll to see which classes / interfaces are defined there which you might be using.
Again, if a namespace starts with "System" it doesn't mean it's inside the System.dll. Namespaces are a way to seperate classes logically, while assemblies are there to seperate classes physically. The mscorlib as well as the System.dll define classes in the System.Collections.Generic
namespace, it depends on which you use. It contains things like the generic LinkedList, Queue, Stack, SortedDictionary and SortedList.
$$anonymous$$aybe you use something from the "System.Net" namespace ?
Oh, you are right. You can actually see that List is part of mscorelib in the reference code. As you said: I confused namespaces and assemblies.
Your answer
![](https://koobas.hobune.stream/wayback/20220612093909im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
A node in a childnode? 1 Answer
The program can't start because UnityPlayer.dll is missing from your computer. 2 Answers
Build C# to dll for .NET 3.5 w/ VS 2017 0 Answers
Build itextsharp dll Lite 1 Answer