encompass-cs-docs/content/concepts/renderer.md

3.7 KiB

title date weight
Renderer 2019-05-22T14:16:06-07:00 30

A Renderer is responsible for reading the game state and telling the game engine what to draw to the screen.

{{% notice note %}} Remember: Encompass isn't a game engine and it doesn't have a rendering system. So Renderers aren't actually doing the rendering, it is just a way of structuring how we tell the game engine what to render. {{% /notice %}}

There are two kinds of renderers: GeneralRenderers and OrderedRenderers.

A GeneralRenderer is a Renderer which reads the game state in order to draw elements to the screen. It also requires a layer, which represents the order in which the Draw method will execute in relation to other Renderers.

If you were using FNA, a GeneralRenderer might look like this:

using System;
using Encompass;
using Microsoft.Xna.Framework;
using MyGame.Components;
using MyGame.Messages;

namespace MyGame.Renderers
{
    public class GridRenderer : GeneralRenderer
    {
        private int gridSize;
        private PrimitiveDrawer primitiveDrawer;

        public GridRenderer(PrimitiveDrawer primitiveDrawer)
        {
            this.primitiveDrawer = primitiveDrawer;
            this.gridSize = 16;
        }

        public override void Render()
        {
            if (SomeComponent<EditorModeComponent>() && SomeComponent<MouseComponent>())
            {
                var entity = ReadEntity<MouseComponent>();
                var transformComponent = GetComponent<TransformComponent>(entity);

                Rectangle rectangle = new Rectangle
                {
                    X = (transformComponent.Position.X / gridSize) * gridSize,
                    Y = (transformComponent.Position.Y / gridSize) * gridSize,
                    Width = gridSize,
                    Height = gridSize
                };

                primitiveDrawer.DrawBorder(rectangle, 0, new System.Numerics.Vector2(1, 1), Color.White, 1);
            }
        }
    }
}

This GeneralRenderer will draw a rectangle at the position of the mouse on the screen if an EditorModeComponent exists in the world.

GeneralRenderers are great for things like a heads-up display, where we always want a group of particular elements to be drawn at a specific layer regardless of the specifics of the game state.

An OrderedRenderer provides a structure for the common pattern of wanting to draw an individual Component at a specific layer. OrderedRenderers must specify a component that implements IDrawableComponent.

If you were using FNA, an OrderedRenderer might look like this:

using Encompass;
using Microsoft.Xna.Framework.Graphics;
using MyGame.Components;
using MyGame.Extensions;
using System;
using System.Numerics;

namespace MyGame.Renderers
{
    public class Texture2DRenderer : OrderedRenderer<Texture2DComponent>
    {
        private SpriteBatch spriteBatch;

        public Texture2DRenderer(SpriteBatch spriteBatch)
        {
            this.spriteBatch = spriteBatch;
        }

        public override void Render(Entity entity, Texture2DComponent textureComponent)
        {
            var transformComponent = GetComponent<TransformComponent>(entity);

            spriteBatch.Draw(
                textureComponent.Texture,
                transformComponent.Position,
                null,
                textureComponent.Color,
                transformComponent.Rotation,
                textureComponent.Origin,
                transformComponent.Scale,
                SpriteEffects.None,
                0
            );
        }
    }
}

For 2D games, you will need to use layers to be specific about the order in which elements are drawn to the screen. For a 3D game you will probably end up delegating most of the rendering to some kind of scene/camera system.