Hello,
I am currently working on a Hexagon Map project. There is a map with tiles, and when the player zooms in, the tiles spawn smaller tiles sort of like a “zoom in”.
I am currently generating the colliders of the smaller tiles through entities instantiated from a Command Buffer on a ISystem.
Now I want to do the graphics rendering part. I am using GPUInstancing.
What I want, is to grab the data in the components created from the command buffer to do the rendering.
What I need, is that the ISystem creates the ComponentData, stores it somewhere, and I can get that data for GPUInstancing from Monobehaviour at runtime.
Since entities are being spawned and destroyed all the time due to distance, I can’t keep track of a fixed set of entities. Also, there are larger WorldMap tiles, and smaller Overworld tiles. I only need the smaller overworld tiles.
I have to somehow, when I give the call, get all the “WorldMapTileData” components of the entities that also have the “OverworldTileTag” component, and process them to render.
This is the code I have for the Update on the ISystem:
public void OnUpdate(ref SystemState state)
{
// Only run system if world map systems are active.
bool worldMapSystems = false;
Entity rulesEntity = Entity.Null;
foreach (var dataHolder in SystemAPI.Query<GameWorldEntityHolderData>())
{
rulesEntity = dataHolder.rulesEntity;
worldMapSystems = dataHolder.worldMapSystems;
}
if (!worldMapSystems) return;
// Grab command buffer for entity creation / modification / destruction
EndSimulationEntityCommandBufferSystem.Singleton commandBufferSystem = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();
#region WORLD TILE LEVELS
// Grab camera entity
Entity cameraEntity = Entity.Null;
foreach (var camera in SystemAPI.Query<WorldCameraTag>())
cameraEntity = camera.cameraEntity;
var worldMapRulesEntityLookup = state.GetComponentLookup<GameWorldEntityHolderData>(true);
GameWorldEntityHolderData rulesData = worldMapRulesEntityLookup[rulesEntity];
// Get Current World Map Tile Position and World Map Render state
var localTransforms = state.GetComponentLookup<LocalTransform>(true);
var worldMapTilesData = state.GetComponentLookup<WorldMapTileData>(true);
var overworldTileTags = state.GetComponentLookup<OverworldTileTag>(true);
WorldMapCameraPositionSystem worldMapCameraPositionSystem = new()
{
cameraEntity = cameraEntity,
localTransforms = localTransforms,
physicsWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>(),
worldMapTilesData = worldMapTilesData,
overworldTileTags = overworldTileTags
};
state.Dependency = worldMapCameraPositionSystem.Schedule(state.Dependency);
state.Dependency.Complete();
// World Map Render update
worldMapRulesEntityLookup = state.GetComponentLookup<GameWorldEntityHolderData>(true);
rulesData = worldMapRulesEntityLookup[rulesEntity];
// Flag WorldMapTiles to render Whole or Split
WorldMapTileTargetRenderSystem worldMapTileTargetRenderSystem = new()
{
rulesDataLookup = worldMapRulesEntityLookup,
};
state.Dependency = worldMapTileTargetRenderSystem.ScheduleParallel(state.Dependency);
// Split flagged WorldMapTiles
WorldMapTileRenderSystem worldMapTileRenderSystem = new()
{
commandBuffer = commandBufferSystem.CreateCommandBuffer(state.WorldUnmanaged),
rulesData = rulesData,
};
state.Dependency = worldMapTileRenderSystem.Schedule(state.Dependency);
// Destroy distant overworld tiles
OverworldTileDistantClearSystem overworldTileDistantClearSystem = new()
{
commandBuffer = commandBufferSystem.CreateCommandBuffer(state.WorldUnmanaged),
rulesDataLookup = worldMapRulesEntityLookup,
};
state.Dependency = overworldTileDistantClearSystem.Schedule(state.Dependency);
// Flag OverworldTiles to render whole or split
OverworldTileTargetRenderSystem overworldTileTargetRenderSystem = new()
{
rulesDataLookup = worldMapRulesEntityLookup,
};
state.Dependency = overworldTileTargetRenderSystem.ScheduleParallel(state.Dependency);
// Split flagged WorldMapTiles
OverworldTileRenderSystem overworldTileRenderSystem = new()
{
commandBuffer = commandBufferSystem.CreateCommandBuffer(state.WorldUnmanaged),
rulesData = rulesData,
};
state.Dependency = overworldTileRenderSystem.Schedule(state.Dependency);
// Destroy distant WorldPlace tiles
WorldPlaceTileDistantClearSystem worldPlaceTileDistantClearSystem = new()
{
commandBuffer = commandBufferSystem.CreateCommandBuffer(state.WorldUnmanaged),
rulesDataLookup = worldMapRulesEntityLookup,
};
state.Dependency = worldPlaceTileDistantClearSystem.Schedule(state.Dependency);
// World Map Update done
WorldMapRulesUpdateDoneSystem worldMapRulesUpdateDoneSystem = new()
{
};
state.Dependency = worldMapRulesUpdateDoneSystem.Schedule(state.Dependency);
#endregion
}
This is the code the Instantiates the new smaller tiles and the components I need to access later:
[BurstCompile]
private partial struct WorldMapTileRenderSystem : IJobEntity
{
public EntityCommandBuffer commandBuffer;
public GameWorldEntityHolderData rulesData;
public void Execute(ref WorldMapTileData worldMapTileData)
{
// Skip if no change is needed
if (worldMapTileData.tileRender == worldMapTileData.targetRender) return;
//Debug.Log("World map tile " + worldMapTileData.index + " updating render to " + worldMapTileData.targetRender);
Entity tileInstance;
WorldMapTileData tileData;
Entity gameTileEntity = rulesData.overworldTilePrefab;
float3 position;
quaternion rotation = quaternion.LookRotation(Vector3.right, Vector3.up);
if (worldMapTileData.targetRender == WorldMapTileRenderSplit)
{
for (int hexa = 0; hexa < HexasPerHexa; hexa++)
{
// Instantiate World Tile Entities with Mesh Collider
tileInstance = this.commandBuffer.Instantiate(gameTileEntity);
// Set and Add WorldTileData
tileData = GetDefaultOverworldTileData(hexa, tileInstance);
tileData.worldMapRulesEntity = worldMapTileData.worldMapRulesEntity;
tileData.tileRenderType = (ushort) OverworldRender;
this.commandBuffer.AddComponent(tileInstance, tileData);
this.commandBuffer.AddComponent(tileInstance, new OverworldTileTag { worldMapTile = worldMapTileData.index });
// Set Position and Rotation.
position = GetWorldMapTileHexaPosition(worldMapTileData.index, hexa, rulesData.worldX, rulesData.worldZ);
position = new()
{
x = position.x,
y = position.y + -6f,
z = position.z
};
// Set LocalTransform
this.commandBuffer.SetComponent(tileInstance,
LocalTransform.FromPositionRotation(position, rotation));
}
//Debug.Log("World Map Tile " + worldMapTileData.index + " has spawned overworld tiles");
}
worldMapTileData.tileRender = worldMapTileData.targetRender;
}
}
There are lots of WorldMapTileData going around. Most of them belonging to the larger original WorldMap tiles. The new ones have a “OverworldTileTag” to flag them as the smaller ties. So I don’t need all the “WorldMapTileData” components, as that would include also the larger tiles. I just need the WorldMapTileData components created for the newly instantiated overworld tiles.
How can I go about this?
Thank you for your time and help.