Center Line

Now we need to draw the center line.

This will be a fairly basic renderer - it doesn’t need to react to anything.

In PongFE/Renderers/CenterLineRenderer.cs:

using System;
using Encompass;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PongFE.Components;

namespace PongFE.Renderers
{
    public class CenterLineRenderer : Renderer
    {
        public SpriteBatch SpriteBatch { get; }
        public Texture2D WhitePixel { get; }

        public CenterLineRenderer(SpriteBatch spriteBatch, Texture2D whitePixel)
        {
            SpriteBatch = spriteBatch;
            WhitePixel = whitePixel;
        }

        public override void Render(double dt, double alpha)
        {
            ref readonly var playAreaComponent = ref ReadComponent<PlayAreaComponent>();

            DrawDottedLine(playAreaComponent.Width / 2, 0, playAreaComponent.Width / 2, playAreaComponent.Height, 20, 20);
        }

        private void DrawDottedLine(float x1, float y1, float x2, float y2, int dash, int gap)
        {
            var dx = x2 - x1;
            var dy = y2 - y1;
            var angle = Math.Atan2(dy, dx);
            var st = dash + gap;
            var len = Math.Sqrt(dx * dx + dy * dy);
            var nm = (len - dash) / st;

            SpriteBatch.End();
            SpriteBatch.Begin(
                SpriteSortMode.Deferred,
                null,
                null,
                null,
                null,
                null,
                Matrix.CreateRotationZ((float)angle) * Matrix.CreateTranslation(x1, y1, 0)
            );

            for (var i = 0; i < nm; i++)
            {
                SpriteBatch.Draw(
                    WhitePixel,
                    new Rectangle(
                        (int)(i * st + gap * 0.5),
                        0,
                        dash,
                        1
                    ),
                    Color.White
                );
            }

            SpriteBatch.End();
            SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
        }
    }
}

I figured out the math for the dotted line procedure so you don’t have to. You’re welcome.

The main magic to understand here is the matrix transformation - the gist of it is that a matrix transformation lets us apply a translation, rotation, and scaling operation all at once and very efficiently. Here we compose a rotation and a translation matrix together so that we can just draw simple rectangles to create the dashed line. Then every SpriteBatch draw rectangle has this transformation applied to it.

Add our CenterLineRenderer to the WorldBuilder…

WorldBuilder.AddRenderer(new CenterLineRenderer());

center dashed line