Question by
HotBean · Aug 03, 2018 at 04:20 AM ·
c#2d gamelagproceduralprocessing
Game lagging when the map generates a new chunk
So for the game I am making, it is an infinite 2d tile map similar to stardew valley. I made a script that generates the world in chunks, and each chunk consists of 10x10 tiles. Each layer of the chunk is generated using perlin noise and is assigned a gameobject with the corresponding sprite. The issue is that every time a new chunk is loaded, the game lags and you can see the player's movement freeze momentarily. I would like to know some ways i can disperse the load of the world generation, so that less processing power is used, but the map looks the same.
Video
Code
(I like my code to be well spaced out):
void Start()
{
chunks = new Dictionary<Vector2, Chunk>();
layerHeights = new float[] { waterLevel, sandLevel, dirtLevel, grassLevel, darkGrassLevel };
}
void Update()
{
LoadChunksAroundPlayer();
}
/*
* Loads chunks around the player with an inputed render distance
*/
public void LoadChunksAroundPlayer()
{
int xPos = (int)player.transform.position.x;
int yPos = (int)player.transform.position.y;
for (int y = -renderDistance*chunkSize; y < renderDistance*chunkSize; y+=chunkSize)
{
for (int x = -renderDistance*chunkSize; x < renderDistance*chunkSize; x+=chunkSize)
{
MakeChunkAt(x + xPos, y + yPos);
}
}
DeleteChunks();
}
/*
* Makes a new chunk with tiles and objects at desired position
*/
public void MakeChunkAt(int x, int y)
{
int newX = (int)(x / chunkSize) * chunkSize;
int newY = (int)(y / chunkSize) * chunkSize;
if (!chunks.ContainsKey(new Vector2(newX, newY)))
{
//Creates an empty gameobject chunk to store the tiles
var chunkGO = Instantiate(chunkEmptyObject, new Vector3(newX, newY, 0), Quaternion.identity, transform);
var chunk = chunkGO.GetComponent<Chunk>();
chunkGO.name = "Chunk(" + newX + "," + newY + ")";
//Fills the chunk class component on the chunk GO
chunk.size = chunkSize;
chunk.posX = newX;
chunk.posY = newY;
chunk.tiles = new List<Tile>();
//Creates the tiles on the chunk
CreateLayers(chunk);
//Adds chunk to the total list of chunks
chunks.Add(new Vector2(newX, newY), chunk);
}
}
/*
* Deletes chunks around the player with an inputed delete distance
*/
public void DeleteChunks()
{
List<Chunk> deleteChunks = new List<Chunk>(chunks.Values);
for (int i = 0; i < deleteChunks.Capacity; i++)
{
int newX = (int)(player.transform.position.x / chunkSize) * chunkSize;
int newY = (int)(player.transform.position.y / chunkSize) * chunkSize;
float distance = Vector2.Distance(new Vector2(newX, newY), deleteChunks[i].gameObject.transform.position);
if (distance > deleteDistance * chunkSize)
{
chunks.Remove(deleteChunks[i].gameObject.transform.position);
Destroy(deleteChunks[i].gameObject);
}
}
}
/*
* Creates every layer of tiles changing by their respected heights
*/
private void CreateLayers(Chunk chunk)
{
for (int i = 0; i < layerHeights.Length; i++)
{
CreateTiles(chunk, i);
}
}
/*
* Creates a new tile object child of the current chunk
*/
private void CreateTiles(Chunk chunk, int layer)
{
int row = 0;
int column = 0;
for (int i = 0; i < chunkSize * chunkSize; i++)
{
Tile tile = null;
//Current tile perlin noise height
float currentHeight = Mathf.PerlinNoise((row + chunk.posX + seed) * scale, (column + chunk.posY + seed) * scale);
if (layer == 0 && currentHeight <= layerHeights[layer])
{
tile = new Tile(row * column, layer, row + chunk.posX, column + chunk.posY, (Type)layer); //New Tile
}
else if (layer == layerHeights.Length - 1 && currentHeight + buffer >= layerHeights[layer] && currentHeight <= 1)
{
tile = new Tile(row * column, layer, row + chunk.posX, column + chunk.posY, (Type)layer); //New Tile
}
else
{
if (layer < layerHeights.Length - 1) //NEED TO FIX THIS SO IT DOESN'T HAPPEN
{
if (currentHeight + buffer >= layerHeights[layer] && currentHeight <= layerHeights[layer + 1])
{
//Current tile
tile = new Tile(row * column, layer, row + chunk.posX, column + chunk.posY, (Type)layer);
}
}
}
//Only instantiates the tile if there is one present
if(tile != null)
{
//Finds the neighbors of the current tile to auto tile
FindNeighbors(chunk, tile, row, column);
//Fills the tile with the correct sprite
FillTile(tile, chunk.transform);
//Spawns objects
AddObjects(chunk, tile, row, column);
//Adds the current tile to the total tiles on the current chunk
chunk.tiles.Add(tile);
}
//Increments to the next column when it reaches the end of the chunksize(row)
if (row == chunkSize - 1)
{
column++;
row = 0;
}
else
{
row++;
}
}
}
/*
* Instantiates the tile as a gameobject and assigns the appropriate sprite to the sprite renderer
*/
private void FillTile(Tile tile, Transform chunkPosition)
{
//Assigns a gameobject tile with a sprite
if (tile != null)
{
Sprite[] sprites = null;
//Creates a new tile gameobject
var go = Instantiate(tilePrefab, new Vector3(tile.tileX, tile.tileY, 0), Quaternion.identity, chunkPosition);
go.name = "Tile (" + (tile.tileX) + "," + (tile.tileY) + ")";
var spriteID = tile.autotileID;
var sr = go.GetComponent<SpriteRenderer>();
sr.sortingOrder = tile.layer;
if (tile.type == Type.DarkGrass)
{
sprites = Resources.LoadAll<Sprite>(darkGrassTexture.name);
}
else if (tile.type == Type.Grass)
{
sprites = Resources.LoadAll<Sprite>(grassTexture.name);
}
else if (tile.type == Type.Dirt)
{
sprites = Resources.LoadAll<Sprite>(dirtTexture.name);
}
else if (tile.type == Type.Sand)
{
sprites = Resources.LoadAll<Sprite>(sandTexture.name);
}
else
{
sr.sprite = waterTexture;
}
if (spriteID >= 0 && tile.type != Type.Water && sprites != null)
{
sr.sprite = sprites[spriteID];
}
}
}
Comment