Hello Guys,
i started to write my own Game like Stronghold Crusader in the Framework Monogame. I got literally all work, but one think i don't know how to handle. So i add here first my question and than i give you a insight to my Project:
How can i get my Objects that are infront of my tile don't get drawn Over by the Tile? Or someone have a idea how Stronghold handle it to get the Fake 3d look with the Heights involved, is there a technique?
In my Game i use a 2d Isometric Diamond Map. And for the different Heights i use different Layers. So if the height is for example 0 the Layer is 0, for 5 = Layer 1,10 = Layer 2, ...
The Problem with this Method is that the Objects infront are drawn over by the Tiles behind(because of Higher Layer).
I do like to have it similar to Stronghold Crusader, but don't understand how they did it. First i know if i change the Height of a Tile they draw a Image Behind the Tile like that:
And ingame that looks like that:
SideView:
Also i saw this Strange behavior that the first Soldier after the changed Tile in Height go a Layer underneath the Soldier afterwards,So the first one will be drawn over by second one, which is not correct?.
Sideview:
How can i approach the heights on my Isometric Map without ordering all Tiles + Objects by the y Position? I don't want to Order all of it because of 2 main reasons:
- Better Performance because of less Gpu calls(Spritesheet usage, Initiating on GPU)
- I don't need Ordering of the List by y value at all, that save me also most of the Time
GamePreview:
Here is also some Code, if you need to know something to answer the Question just ask me. :)
MapCode:
protected override void Update(float elaspedTime, ref Map component)
{
#region CameraViewChanged
ref Camera cameraData = ref _camera.Get<Camera>();
if (cameraData.ZoomChanged)
{
ColumnsToDraw = cameraData.VisibleArea.Width / tileWidth + 5;
RowsToDraw = cameraData.VisibleArea.Height / (int)tileHeightHalf + 6;
cameraData.ZoomChanged = false;
}
#endregion
#region Reset Layer
for (int i = 0; i < _layer.Length; i++)
{
_layer[i].Get<Layer>().End = 0;
_layer[i].Get<Layer>().Start = 0;
_layer[i].Get<Layer>().ActualCount = 0;
}
#endregion
#region Calculate Tile/Object IDS in View
var start = ScreenToWorldPosition(new Point(cameraData.VisibleArea.X, cameraData.VisibleArea.Y));
ref Map mapStruct = ref _map.Get<Map>();
int tiley;
int tilex;
start.X -= 3;
start.Y += 2;
int k = 0;
int actualLayer;
for (int x = 0; x < RowsToDraw; x++)
{
tiley = start.Y;
tilex = start.X;
for (int y = 0; y < ColumnsToDraw; y++)
{
var tile = tiley * component.Size.X + tilex;
if (tiley < 0) break;
if (tilex < 0)
{
tilex++;
tiley--;
continue;
}
if (tile < 0 || tile > _tiles.Length - 1)
{
tiley--;
tilex++;
continue;
}
tiley--;
tilex++;
actualLayer = _tiles[tile].Layer * 2;
if (_tiles[tile].IsVisible)
{
ref Layer layerTile = ref _layer[actualLayer].Get<Layer>();
layerTile.End++;
}
ref var layer = ref _layer[actualLayer + 1].Get<Layer>();
_quadrantGrid.GetEntitysCountOnTile(tile, ref layer);
if (_tiles[tile].Object.HasValue)
{
layer.End++;
}
k++;
_idsToDraw[k] = tile;
}
start.Y += (x + 1) % 2;
start.X += x % 2;
}
#endregion
#region Calculate Layer Start and End for Tile/Object Array
int numberTiles = 0;
int numberObjects = 0;
for (int i = 0; i < _layer.Length / 2 - 1; i++)
{
numberTiles += _layer[i * 2].Get<Layer>().End;
ref var layer = ref _layer[(i + 1) * 2].Get<Layer>();
layer.Start = numberTiles;
layer.ActualCount = numberTiles;
numberObjects += _layer[i * 2 + 1].Get<Layer>().End;
ref var layerObject = ref _layer[(i + 1) * 2 + 1].Get<Layer>();
layerObject.Start = numberObjects;
layerObject.ActualCount = numberObjects;
}
#endregion
#region SetVisible Objects/Tiles to Array that will be drawn
int layerID;
for (int i = 0; i < k; i++)
{
layerID = _tiles[_idsToDraw[i]].Layer * 2;
if (_tiles[_idsToDraw[i]].IsVisible)
{
ref var layerTiles = ref _layer[layerID].Get<Layer>();
ref MapTile tileData = ref mapStruct.TilesinView[layerTiles.ActualCount].Get<MapTile>();
tileData = _tiles[_idsToDraw[i]];
layerTiles.ActualCount++;
}
ref var layerObjects = ref _layer[layerID + 1].Get<Layer>();
_quadrantGrid.SetEntitysVisibleOnKey(_idsToDraw[i], ref layerObjects, ref mapStruct);
if (_tiles[_idsToDraw[i]].Object.HasValue)
{
mapStruct.EntitiesInView[layerObjects.ActualCount] = _objects[_tiles[_idsToDraw[i]].Object.Value];
layerObjects.ActualCount++;
}
}
#endregion
}
DrawCode:
protected override void Update(float elaspedTime, in Entity entity)
{
ref Layer layer = ref entity.Get<Layer>();
ref Map map = ref _map.Get<Map>();
if (layer.Object)
{
for (int i = layer.Start; i < layer.Start + layer.End; i++)
{
ref var gameObjectEntity = ref map.EntitiesInView[i];
ref GameObject gameObject = ref gameObjectEntity.Get<GameObject>();
ref Transform transform = ref gameObjectEntity.Get<Transform>();
ref TextureShared mapTextureShared = ref gameObjectEntity.Get<TextureShared>();
_batch.Draw(texture: mapTextureShared.TextureSheet, position: transform.Position + transform.Offset, sourceRectangle: gameObject.Source, color: Color.White);
}
return;
}
for (int i = layer.Start; i < layer.Start + layer.End; i++)
{
ref var tile = ref map.TilesinView[i];
ref MapTile mapTile = ref tile.Get<MapTile>();
ref TextureShared mapTextureShared = ref tile.Get<TextureShared>();
ref TileProperty tileProperty = ref _tilePropertys[mapTile.ID].Get<TileProperty>();
_batch.Draw(texture: mapTextureShared.TextureSheet, position: mapTile.Position + tileProperty.Offset + mapTile.Offset, sourceRectangle: tileProperty.Source, color: Color.White);
}
}