If I understand you right Ztormi, you would suggest a vertex array that covers the whole area the player can see? But if I move to one side, this would mean a rebuild of the whole array. Or did you have something else in mind?
No, I meant you forget the chunks and just draw the whole map, layer by layer.
Like Jesper Juhl mentioned, the method of updating and keeping track of your drawable items is probably more perfomance intensive operation than drawing itself.
Logic would go like this:
Sprite refers to a drawable object which's position is not tied into a tile.
- I have two classes, World, Renderer
- World notifies Renderer when tile is changed
- World notifies Renderer when sprite is created
- World notifies Renderer when sprite is changed
- World notifies Renderer when sprite is destroyed
- Renderer has two vertexarrays, tilelayer and spritelayer
- On draw, both vertexarrays are drawn in correct order
Tilelayer vertex array is really straightforward. However, the vertex array containing sprites is a bit trickier. For this to make sense, I scratched up an example. I use sfml.net with C# because that's how I roll.
Sprites:
public class Entity
: Transformable, IHasTexRect
{ public IntRect TextureRect
{ get; set; } }public interface IHasTexRect
{ IntRect TextureRect
{ get; }}public class MappedVertexArray
<T
> : Drawable
where T
: Transformable, IHasTexRect
{ private VertexArray _vertexArray
; private Dictionary
<T,
uint> _items
= new Dictionary
<T,
uint>(); private uint _lastIndex
; private Texture _texture
; public MappedVertexArray
(Texture t
) { _texture
= t
; } /// <summary> /// Update item's position and texcoords /// </summary> /// <param name="entity"></param> public void UpdateItem
(T entity
) { uint index
= _items
[entity
]; _vertexArray
[index
] = new Vertex
(entity
.Position,
new Vector2f
(entity
.TextureRect.Left, entity
.TextureRect.Top)); index
++; _vertexArray
[index
] = new Vertex
(entity
.Position + new Vector2f
(entity
.TextureRect.Width,
0),
new Vector2f
(entity
.TextureRect.Left + entity
.TextureRect.Width, entity
.TextureRect.Top)); index
++; _vertexArray
[index
] = new Vertex
(entity
.Position + new Vector2f
(entity
.TextureRect.Width, entity
.TextureRect.Height),
new Vector2f
(entity
.TextureRect.Left + entity
.TextureRect.Width, entity
.TextureRect.Top + entity
.TextureRect.Height)); index
++; _vertexArray
[index
] = new Vertex
(entity
.Position + new Vector2f
(0, entity
.TextureRect.Height),
new Vector2f
(entity
.TextureRect.Left, entity
.TextureRect.Top + entity
.TextureRect.Height)); } /// <summary> /// Add entity /// </summary> /// <param name="entity"></param> public void Add(T entity
) { _items
[entity
] = _lastIndex
; _vertexArray
.Append(new Vertex
(entity
.Position,
new Vector2f
(entity
.TextureRect.Left, entity
.TextureRect.Top))); _vertexArray
.Append(new Vertex
(entity
.Position + new Vector2f
(entity
.TextureRect.Width,
0),
new Vector2f
(entity
.TextureRect.Left + entity
.TextureRect.Width, entity
.TextureRect.Top))); _vertexArray
.Append(new Vertex
(entity
.Position + new Vector2f
(entity
.TextureRect.Width, entity
.TextureRect.Height),
new Vector2f
(entity
.TextureRect.Left + entity
.TextureRect.Width, entity
.TextureRect.Top + entity
.TextureRect.Height))); _vertexArray
.Append(new Vertex
(entity
.Position + new Vector2f
(0, entity
.TextureRect.Height),
new Vector2f
(entity
.TextureRect.Left, entity
.TextureRect.Top + entity
.TextureRect.Height))); _lastIndex
+= 4; } /// <summary> /// Remove entity from vertex array and rearrange vertices /// </summary> /// <param name="entity"></param> public void Remove(T entity
) { var old
= _items
; _items
.Clear(); _vertexArray
.Clear(); _lastIndex
= 0; foreach (var obj
in old
) { if (obj
.Key.Equals(entity
)) continue; Add(obj
.Key); } } public void Draw
(RenderTarget target, RenderStates states
) { states
.Texture = _texture
; _vertexArray
.Draw(target, states
); states
.Texture = null; }} Renderer:
public class Renderer
: Drawable
{ private TileVertexArray _groundLayer
; private MappedVertexArray
<Entity
> _entities
= new MappedVertexArray
<Entity
>(SomeTexture
); public Renderer
(World w
) { w
.OnEntityCreated += w_OnEntityCreated
; w
.OnEntityDestroyed += w_OnEntityDestroyed
; w
.OnEntityUpdated += w_OnEntityUpdated
; w
.OnTileChanged += OnTileChanged
; } void w_OnEntityUpdated
(object sender, Entity e
) { _entities
.UpdateItem(e
); } void w_OnEntityDestroyed
(object sender, Entity e
) { _entities
.Remove(e
); } void w_OnEntityCreated
(object sender, Entity e
) { _entities
.Add(e
); } void OnTileChanged
(object sender,
uint x,
uint y, FloatRect texcoords
) { _groundLayer
.SetQuadTexcoords(texcoords,x,y
); } public void Draw
(RenderTarget target, RenderStates states
) { _groundLayer
.Draw(target, states
); _entities
.Draw(target, states
); } } Notice a problem here?
Every time we remove object from MappedVertexArray we'll have to rearrange all the vertices. Again, referring to Jesper Juhl's post, you'll have to profile if this approach is worth it. Or would it be faster to just have a list of sprites in screen and draw them one by one.