Ribbon Compass Script

I made this script for a freelancer project originally, which was a sailing game with pirates and ships. We needed a compass, and we wanted to show the player, how the wind affects his sailing speed.

The basic idea here is to have a horizontal grid layout with Text elements. I call this the ribbon. The script moves this ribbon horizontally based on where the character is facing.

I only want part of the ribbon visible, so I use the mask component.

The problem I encountered is circularity. I wanted to translate from the end of the ribbon to its start seamlessly. The setup below resulted in a failure, the compass ran out of letters.

SE — S — SW — W — NW — N — NE — E —

I figured out I have to make duplicates. I only move the ribbon between the two S letter and let the overflowing part simulate the circularity.

The script

public class RibbonCompass : MonoBehaviour
{
    [SerializeField] Vector3 NorthDirection = new Vector3(0,0,1);
    [SerializeField] Transform Actor;
    [SerializeField] GridLayoutGroup ribbon;
            
    float _angleMultiplier;

    void OnEnable()
    {
        _angleMultiplier = 2 * ribbon.cellSize.x / 45;
    }

    void Update()
    {
        Vector3 actorDirection = Actor.forward;
        float angle = Vector3.SignedAngle(actorDirection, NorthDirection, Vector3.up);

        Vector3 ribbonPosition = ribbon.transform.localPosition;                   
        ribbonPosition.x = angle * _angleMultiplier;
        ribbon.transform.localPosition = ribbonPosition;           
    }       
}

The script is pretty simple. We need three variable for the inspector: 

  • The direction of the north: as default, I set it to Vector3.forward.
  • The actor transform. We’ll compare it’s forward direction to the north direction.
  • The ribbon. This will be a GridLayoutGroup.

We also need a private variable to store the angle multiplier. I’ll explain it later but first, let’s see what this script does.

  1. Calculates the angle between the actors forward and the north direction.
  2. Then sets the ribbon position in a way to show the right letter.

I’m using text game objects for the letters and for the separators (—). Each of these cells has the same width value, defined in the GridLayoutGroup.

Between North and North West there is 45 degrees difference in angle. If I’m staying in the center of the N letter, I have to move 2 cells:

  • I move the ribbon half cell to arrive at the start of the separator.
  • One full cell (the separator).
  • Half cell again to reach the center of the NW cell.

That’s being said, every 45° needs to move the ribbon with 2 cell width. Instead of calculating each time in the update function, I precalculate this and store it on the _angleMultiplier variable.

How to use the component

The component you can download from the Gumroad (for free) has a slightly better inspector, and also contains the color changing feature.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.