Hello everyone,
I’m currently working on my own game map generator, but have a few concerns regarding performance.
At the moment, I’m only instantiating blocks and then combining them to chucks, but if lets say the map size is 200x200, that would be 40 000 blocks to instantiate, which takes a considerable amount of time and I want to have an ability to create even bigger maps.
What should I do to improve this? Thank you
The script:
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
[SerializeField] int chunkSize = 50;
[Range(50, 200)]
[SerializeField] int map = 100;
[Range(0f, .5f)]
[SerializeField] float spacing = 0.25f;
[SerializeField] MeshFilter _block = null;
private int size
{
get
{
return map / 2;
}
}
void Start()
{
Generate();
}
private void Generate()
{
var blocks = new MeshFilter[map, map];
var startPos = (1 + spacing) * map;
startPos = -startPos / 2;
Vector3 pos = new Vector3(startPos, 0, startPos);
for (int x = 0; x < map; x++)
{
pos.x = startPos;
for (int z = 0; z < map; z++)
{
var newBlock = Instantiate(_block);
newBlock.transform.position = pos;
pos.x += 1 + spacing;
newBlock.name = $"Block_{x+1}/{z+1}";
blocks[x,z] = newBlock;
}
pos.z += 1 + spacing;
}
Combine(blocks);
}
private void Combine(MeshFilter[,] blocks)
{
int t = map / chunkSize; t *= t;
int xS = 0, zS = 0;
for (int i = 0; i < t; i++)
{
var combine = new List<CombineInstance>();
for (int x = xS; x < xS + chunkSize; x++)
{
for (int z = zS; z < zS + chunkSize; z++)
{
var newInstance = new CombineInstance
{
mesh = blocks[x, z].sharedMesh,
transform = blocks[x, z].transform.localToWorldMatrix
};
combine.Add(newInstance);
Destroy(blocks[x, z].gameObject);
}
}
xS += chunkSize;
if (xS >= map)
{
zS += chunkSize;
xS = 0;
}
#region Combine to Chunk
GameObject combined = new GameObject();
combined.transform.position = Vector3.zero;
combined.name = $"Chunk_{i}";
var filter = combined.AddComponent<MeshFilter>();
filter.mesh = new Mesh();
filter.mesh.CombineMeshes(combine.ToArray());
var renderer = combined.AddComponent<MeshRenderer>();
renderer.sharedMaterial = _block.gameObject.GetComponent<MeshRenderer>().sharedMaterial;
#endregion
}
}
}
Did you have any performance issues yet? Did you try to to increase the map size and test how good/bad it works?
If you don’t experience any issues yet, you shouldn’t worry about performance. Wait until something negative occurs, then you’ll b able to tackle that problem specifically. There are too many things one can theoretically optimize… runtime, memory, exception handling, quality of results, etc. If you don’t know what you need to work on, thing will likely get worse more than anything else.
That doesn’t mean you should write bad code on purpose, obviously. If you already know a better implementation, go ahead and use it. But other than that… don’t worry too much.
Thank you for the reply! Well after everything is created performance is fine, but if I try to generate a 200x200 map for example, is takes more than a minute for the map to fully generate. And considering that currently I’m only generating a floor without any elements, such as environment details, intractable objects and ect., to fully generate entire map with everything, it would take double, if not more time. So for even bigger map this could be an issue.
How big are these blocks? Are they all visible at once? Typically you would only generate a small area around the player then dynamically generate more as the player moves around.
I’m thinking on making a board like game, where each player is able to roll a dice and move x amount of cell / block. On each cell / block there’s curtain items, doodads or just a path. The cell size at the moment is 1x1, but it might be slightly different once proper assets are made. So because all players are going to be located across the map, the entire map needs to be already made. Also the map is not going to be infinite.
I think the problem that is causing the long process time is Instantiate and Destroy methods. I’m hoping their’s a way to optimize this, like creating a full mesh without instantiating each cell and then destroying it. As each cell will have the same mesh, maybe there’s a way to create a full chuck mesh by copying the cell mesh x amount of times and just shifting the position. So construct the full mesh in script and then create a new empty object and just use that mesh to draw all the cells. I hope that makes any sense…
Hey there! Yes, I thought about this, but the problem is that I want to implement biomes, so considering that the map will be randomly generated, you can’t really predefine it. There will be some slight variations with height, and also there will be cells like water and similar, so it’s really diverse.
At least ground tiles will be the same mesh with same material that will use a texture sheet, so everything will be combined with no problems. I just need to improve the generation process. The worst case scenario I will just leave everything as is. It just gonna take some time. Although it’s really not ideal…
Also thanks for the tip about arrays, I honestly haven’t thought multidimensional arrays were bad for performance.