How do you create a progress bar without mask support?

Avatar
  • updated
  • Answered

Hi, thanks for the asset. I've just started to play with it so apologies if I'm missing something obvious.

I'm trying to create a simple progress bar with a background and fill using 2 lines.  The problem I'm running into is that when the line is very short the end caps don't play nice which is understandable.


Here's my attempt just by shrinking the fill length:

https://imgur.com/4FtcTY6


What I'd like to achieve with shapes is something like my implementation with sprites but this requires a mask which I haven't figured out a way to get to work with shapes:

https://imgur.com/Atx7eQL


In my sprite implementation I'm just translating the fill and letting the mask do the rest.  The problem with that is if you get two progress bars close together they overlap hah...

Is there a good way to implement that with shapes?


Thanks!

Reporting a bug? please specify Unity version:
Reporting a bug? please specify Shapes version:
Reporting a bug? please specify Render Pipeline:
Pinned replies
Avatar
Freya Holmér creator
  • Answer
  • Answered

currently there's no masking support in Shapes, as it's potentially a bit of a can of worms to open up stencil buffer, especially as they are used in different ways across render pipelines and projects
I'll consider this mostly as a question and not a feature request! feel free to open topics if you want something more specific.

There is, however, a hack you can do to solve it in this case~
it's a bit of a mess because of the round caps, but:


  • Enable dashed lines
  • Set it to round dashes
  • Make the dash length the same as the length of the line + thickness (to account for the caps)
  • Set dash spacing to 3*dashLength
  • Let x be the constant (length*8)/thickness
  • Dash offset at -x now means full health
  • Dash offset at -x-0.25 now means no health
  • You can use Lerp to have a normalized health value to work in this range, eg:
  • dashOffset = lerp( -x-0.25, -x, t ) where t is health from 0 to 1


Hope it helps!

Avatar
Freya Holmér creator
  • Answer
  • Answered

currently there's no masking support in Shapes, as it's potentially a bit of a can of worms to open up stencil buffer, especially as they are used in different ways across render pipelines and projects
I'll consider this mostly as a question and not a feature request! feel free to open topics if you want something more specific.

There is, however, a hack you can do to solve it in this case~
it's a bit of a mess because of the round caps, but:


  • Enable dashed lines
  • Set it to round dashes
  • Make the dash length the same as the length of the line + thickness (to account for the caps)
  • Set dash spacing to 3*dashLength
  • Let x be the constant (length*8)/thickness
  • Dash offset at -x now means full health
  • Dash offset at -x-0.25 now means no health
  • You can use Lerp to have a normalized health value to work in this range, eg:
  • dashOffset = lerp( -x-0.25, -x, t ) where t is health from 0 to 1


Hope it helps!

Avatar
dillon shook

Yes that helped thanks!

The math you listed wasn't working for me with line thicknesses < 1f but I figured it out hacking around with the math like normal game dev :p

Here's my script for anyone else that comes across this


using UnityEngine;
using Shapes;

[ExecuteInEditMode]
public class FilledBar : MonoBehaviour
{
  public Line background;
  public Line fill;

  public Color color = Color.gray;
  public Color bgColor = Colors.mediumGray;

  [Range(0f, 1f)]
  public float fillAmt = 0.5f;

  public float length = 1f;

  public float lineThickness = 0.2f;
  public float fillPadding = 0.08f;

  void Awake()
  {
  }

  void Update()
  {

    if(background == null || fill == null){ return; }

    background.Color = bgColor;
    fill.Color = color;

    background.Thickness = lineThickness;
    fill.Thickness = lineThickness - fillPadding;

    fill.Dashed = true;
    fill.DashSpace = DashSpace.Meters;
    fill.DashSnap = DashSnapping.Off;

    background.Start = fill.Start = new Vector3(-length / 2f, 0, 0);
    background.End = new Vector3(length / 2f, 0, 0);
    fill.End = background.End;


    fill.DashSize = fill.Thickness + length;
    fill.DashSpacing = fill.DashSize * 3f;
    var emptyOffset = -fill.Thickness * 2.25f;
    var fullOffset = -fill.Thickness / 8f;
    fill.DashOffset = Mathf.Lerp(emptyOffset, fullOffset, fillAmt);
  }

}