0
\$\begingroup\$

I'm working on a tower defense game. I have this structure:
int array (public int[,,,] gridArray = new int[2000, 2000, 9, 9];)
that I'm using as a map-bible; by map-bible I mean that the array holds all the cell data that the game uses to build its map form.

What I am specifically asking for is a way to store that data in any file format without needing to massively rework my game.

The first two dimensions of the array store x and y, while the last two dimensions hold cell-specific data. In most cases, this cell-specific data stores building health or ammo. But the vast majority of the 81 cells are empty to accommodate more things down the line. It should be noted that all this data is simply integers that are passed on to game objects, for example:
newbuilding.health = gridArray [x,y,0,1];

It should be noted I am a novice level programmer and in way over my head, so detail would be appreciated.

New contributor
0ne Man shooter is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
  • 1
    \$\begingroup\$ What have you tried and why didn't it work as you expected? \$\endgroup\$ – Vaillancourt Nov 20 at 20:19
  • \$\begingroup\$ and thats a kinda big file if you fully populate it. 4 byte per int *2000 * 2000 * 9 * 9 is 1296 Megabyte \$\endgroup\$ – Zibelas Nov 20 at 20:23
  • \$\begingroup\$ Over the past week, I have tried JSON. But it, by default, will not serialize multidimensional arrays. Dipped my toes into XML, but as I said, I'm a novice, so that was a hard pass. and finally decided against binary for obvious reasons. And ya its a good amount of data. \$\endgroup\$ – 0ne Man shooter Nov 20 at 20:27
  • 2
    \$\begingroup\$ Tell us the "obvious reasons" you decided against binary please? Because a binary format will let you just read or write the entire thing in a single operation, bottlenecked only by disk speed. Text formats will always require slower parsing and data conversion, so you better have a very compelling reason for not preferring binary. \$\endgroup\$ – Maximus Minimus Nov 20 at 20:36
  • 1
    \$\begingroup\$ Hint: it's binary in memory too. \$\endgroup\$ – DMGregory Nov 20 at 21:22
3
\$\begingroup\$

What I am specifically asking for is a way to store that data in any file format without needing to massively rework my game.

It should be noted I am a novice level programmer and in way over my head, so detail would be appreciated.

No offense, but the clumsy way you're storing your data is just making things worse for you. You should seriously consider changing it, even if that means you need to rework some of your game. If you start from a bad foundation and just keep building on that bad foundation, you're just going to end up with code that is more and more of a mess until it gets to the point that it's impossible to make any progress. This often means giving up on the project and sometimes giving up on game development altogether.

In the engine, your data should probably be stored more along the lines of something like this:

[System.Serializable]
public struct Cell {
    [SerializeField] private int x;
    [SerializeField] private int y;
    [SerializeField] private BuildingInfo buildingInfo;
    [SerializeField] private int ammo;

    public int X{ get => x; set => x = value; }
    public int Y{ get => y; set => y = value; }
    public Vector2Int Position => new Vector2Int(x, y);
    public BuildingInfo BuildingInfo { get => buildingInfo; set => buildingInfo = value; }
    public int Ammo { get => ammo; set => ammo = value; }
    //etc
}

//if most cells will have data, we can consider a 2D table:
private Cell[,] cells = new Cell[2000, 2000];
//to retrieve a cell
var cell = cells[x,y];

//or if most cells will not have data, we should not waste an enormous amount of
//space populating a 2D table with empty cells
private Dictionary<Vector2Int, Cell> cells = new Dictionary<Vector2Int, Cell>(100);
//to add a cell:
var cell = new Cell();
cell.X = x;
cell.Y = y;
//etc
cells.Add(cell.Position, cell);

//to retrieve a cell
if (cells.TryGetValue(new Vector2Int(x, y), out var cell) {
    //do something with the cell here
}
//to loop through all cells
foreach (var cell in cells.Values) {
    //do something with the cell here
}

Because the struct in my example is serializable, you can put the structs into a ScriptableObject:

[CreateAssetMenu(menuName = "Saved Map")]
public class SavedMap : ScriptableObject {
    [SerializeField] private List<Cell> cells = new List<Cell>(100);

    public List<Cell> Cells { get => cells; set => cells = value; }

    public void SaveFromDictionary(Dictionary<Vector2Int, Cell> dict) {
        cells.Clear();
        foreach (var cell in dict.Values) {
            cells.Add(cell);
        }
        //special code that only runs in the Editor to make sure the Editor recognizes that the data changed and needs to be saved to disk
#if UNITY_EDITOR
        EditorUtility.SetDirty(this);
#endif
    }

    //this is very expensive, only call it once when you start the game and save the result to a variable
    public Dictionary<Vector2Int, Cell> ToDictionary() {
        Dictionary<Vector2Int, Cell> dict = new Dictionary<Vector2Int, Cell>(cells.Count);
        foreach (var cell in cells) {
            dict[cell.Position] = cell;
        }
        return dict;
    }
}

public class MapLoader : MonoBehaviour {
    [SerializeField] private SavedMap map;
    private Dictionary<Vector2Int, Cell> cells;

    private void Awake() {
        Assert.IsNotNull(map);
        cells = map.ToDictionary();
    }

    public Dictionary<Vector2Int, Cell> Cells => cells;
}

A ScriptableObject class defines a type of asset file that you can create, edit, and save in the Unity Editor. You can edit a ScriptableObject asset in the Inspector in the same way you edit any GameObject. In this case manually editing the cells in the Inspector would be a nightmare, so you'd probably want to have a script pass the data into the ScriptableObject to save.

If you don't know how to use Dictionaries or ScriptableObjects or anything else I've mentioned, please do a web search and read the official documentation. This is the best way to learn!

You might also want to eventually make a custom Editor or EditorWindow script for easily editing a SavedMap in the Unity Editor.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks for the help, and oh, dont worry I have no illusions about how much better I could have done things form the beginning. \$\endgroup\$ – 0ne Man shooter Nov 21 at 1:37

Your Answer

0ne Man shooter is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.