- Home /
DOTS Grid-based generation question.
Hello, i am currently working on a grid-based (just code, not object) dots procedural generation project and i need some help. I want to have a system where the game "activates" grid cells(from now on "chunks") around players and then generates them. I already have the generation done, but i need some help with the chosing what chunk it is. I dont know if cycling through the entire grid is a good idea and i want it to do this:
Know which grid cells to activate (the coordinates of the chunk)
Keep track which chunks are already activated so it doesnt activate those
Deactivate chunks that are far away
So as i said i already have code for genereation that will activate with the activation of each chunk and i can easily add code to deactivating etc. but i dont know how to do the system that decides what is active or not and what to activate or deactivate. I thought of using native containers to store the data which chunks are active and add/remove at run time. or maybe an simple array that just changes the coordinates that are active when you move, without actually making active chunks special. Any help, tips or ideas are welcomed. Also sorry for any grammatic errors.
Answer by andrew-lukasik · Nov 03, 2020 at 02:03 AM
players moving around, loaded cells are highlighted:
load distance:
point to cell index, cell index to point conversion:
Here is a code that shows general idea how you can do this (not dots-specific). It uses my NativeGrid package to simplify index finding
(you may want to install it (see Installation readme notes) OR deep copy this specific function (more work imo)).
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;
[ExecuteAlways]
public class GridTester : MonoBehaviour
{
[SerializeField] float2 _gridWorldSize = new float2{ x=10 , y=10 };
[SerializeField] int2 _gridResolution = new int2{ x=16 , y=16 };
[SerializeField] Transform[] _players = new Transform[0];
[SerializeField][Range(0,10)] int _loadDistance = 1;
HashSet<int2> _active = new HashSet<int2>();// cells we want to be loaded
HashSet<int2> _loaded = new HashSet<int2>();// cells that are loaded
HashSet<int2> _redundant = new HashSet<int2>();// cells to unload
void Update ()
{
// create list of active cells:
_active.Clear();
foreach( Transform player in _players )
{
int2 playerI2 = PointToIndex2d( player.position );
for( int oy=-_loadDistance ; oy<=_loadDistance ; oy++ )
for( int ox=-_loadDistance ; ox<=_loadDistance ; ox++ )
{
int2 i2 = playerI2 + new int2{ x=ox , y=oy };
if( i2.x>=0 && i2.x<_gridResolution.x && i2.y>=0 && i2.y<_gridResolution.y )// bounds checks
_active.Add( i2 );
}
}
// load active cells
foreach( int2 i2 in _active )
{
if( !_loaded.Contains(i2) )
{
/*
insert code that loads cell's content here
*/
_loaded.Add(i2);
}
}
// unload redundant cells:
_redundant.Clear();
foreach( int2 i2 in _loaded )
if( !_active.Contains(i2) )
_redundant.Add(i2);
foreach( int2 i2 in _redundant )
{
/*
insert code that unloads cell's content here
*/
_loaded.Remove(i2);
}
}
#if UNITY_EDITOR
void OnDrawGizmos ()
{
float3 cellSize = new float3{
x = _gridWorldSize.x / _gridResolution.x ,
y = 0f ,
z = _gridWorldSize.y / _gridResolution.y
};
// draw grid:
Gizmos.color = new Color{ r=1 , g=1 , b=1 , a=0.2f };
for( int Y=0 ; Y<_gridResolution.y ; Y++ )
for( int X=0 ; X<_gridResolution.x ; X++ )
{
float3 cellOriginLocal = new float3{
x = X * cellSize.x ,
y = 0f ,
z = Y * cellSize.z
};
float3 cellCenterLocal = cellOriginLocal + cellSize*0.5f;
Gizmos.DrawWireCube( cellCenterLocal , cellSize );
}
// draw loaded cells:
Gizmos.color = new Color{ r=0 , g=1 , b=1 , a=0.2f };
foreach( int2 i2 in _loaded )
{
float3 cellOriginLocal = new float3{
x = i2.x * cellSize.x ,
y = 0f ,
z = i2.y * cellSize.z
};
float3 cellCenterLocal = cellOriginLocal + cellSize*0.5f;
Gizmos.DrawCube( cellCenterLocal , cellSize );
}
// draw player positions:
Gizmos.color = Color.cyan;
float sphereRadius = math.min(cellSize.x,cellSize.z)*0.25f;
foreach( Transform player in _players )
{
float3 pos = player.position;
Gizmos.DrawLine( pos , new float3{ x=pos.x , y=0 , z=pos.z } );
Gizmos.DrawSphere( pos , sphereRadius );
}
// highlight grid cell under mouse pointer:
int2 i2Highlighted = int2.zero;
{
Ray ray = UnityEditor.HandleUtility.GUIPointToWorldRay( Event.current.mousePosition );
new Plane( inNormal:transform.up , inPoint:transform.position ).Raycast( ray , out float dist );
float3 hit = ray.origin + ray.direction*dist;
Gizmos.color = new Color{ r=1 , g=1 , b=1 , a=0.35f };
Gizmos.DrawWireSphere( hit , sphereRadius );
int2 i2 = PointToIndex2d( hit );
float3 cellOriginLocal = new float3{
x = i2.x * cellSize.x ,
y = 0f ,
z = i2.y * cellSize.z
};
float3 cellCenterLocal = cellOriginLocal + cellSize*0.5f;
Gizmos.DrawCube( cellCenterLocal , cellSize );
Gizmos.DrawLine( hit , cellOriginLocal );
i2Highlighted = i2;
}
// any i2 to cell origin, conversion example:
{
float3 cellOriginLocal = Index2dToPoint( i2Highlighted );
Gizmos.color = Color.magenta;
Gizmos.DrawWireSphere( cellOriginLocal , sphereRadius*0.25f );
}
}
#endif
/// <returns> Cell index2d </returns>
public int2 PointToIndex2d ( FLOAT3 worldPoint )
{
return NativeGrid.PointToIndex2d(
// point: worldPoint.XZ()-((FLOAT3)transform.position).XZ() ,
point: worldPoint.XZ() ,
worldSize: _gridWorldSize ,
width: _gridResolution.x ,
height: _gridResolution.y
);
}
/// <returns> Cell origin point </returns>
public float3 Index2dToPoint ( INT2 i2 )
{
float2 point2d = NativeGrid.Index2dToPoint( i2:i2 , step:_gridWorldSize/_gridResolution );
return new float3{ x=point2d.x , y=0 , z=point2d.y };
}
}
Thank you! Its close to what i thought it´ll be. I´ll look into it.
Oh also, gridResolution is basically grid cell´s lenght, right?
Btw.: You can replace HashSet<int2>
with List<int2>
if ever needed. Just know I'm using hashset because it's Contains()
method is O(1) fast where lists can be O(n).
In places where int2 i2
comes up it means cell's 2D grid coordinates packed as a pair of integers with i2.x
and i2.y
coordinates.
Thanks! I am working on it, i hope the result will be like yours.
Anticipating future need I added Index2dToPoint(i2)
method so you'll know how to find cell origin in 3d space (to place meshes and and objects associated with this cell, for example)
Your answer
Follow this Question
Related Questions
How can i make the Unity2d grid use rounded numbers? 1 Answer
Procedural mesh with texture atlas, how to get rid of material artifacts? 0 Answers
How do you find adjacent tiles of the same type in grid array [x,y].type == [x+1,y].type 0 Answers
Problem making a grid for a TBS game 2 Answers
grid checking for objects 1 Answer