Resolve WES-192 "Fix progress screen"
This commit is contained in:
263
Assets/Accounts/Scripts/ProgressGraph.cs
Normal file
263
Assets/Accounts/Scripts/ProgressGraph.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Class to handle and draw a nice line graph to a Texture2D
|
||||
/// </summary>
|
||||
public class ProgressGraph : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// UI reference to the plot
|
||||
/// </summary>
|
||||
public RawImage progressGraph;
|
||||
|
||||
/// <summary>
|
||||
/// Prefab of the highscore marker to display on the graph
|
||||
/// </summary>
|
||||
public GameObject highscoreMarker;
|
||||
|
||||
/// <summary>
|
||||
/// Prefab of the axes tick marker to display on the graph
|
||||
/// </summary>
|
||||
public GameObject axesTickMarker;
|
||||
|
||||
/// <summary>
|
||||
/// Color of the graph line
|
||||
/// </summary>
|
||||
public Color lineColor;
|
||||
|
||||
/// <summary>
|
||||
/// Bckground color
|
||||
/// </summary>
|
||||
public Color backgroundColor;
|
||||
|
||||
/// <summary>
|
||||
/// Color of the text and axes grid
|
||||
/// </summary>
|
||||
public Color textColor;
|
||||
|
||||
/// <summary>
|
||||
/// Color of the highscore line
|
||||
/// </summary>
|
||||
public Color highscoreColor;
|
||||
|
||||
/// <summary>
|
||||
/// Left and right padding of the graph
|
||||
/// </summary>
|
||||
private const int GRAPH_PADDING_X_PX = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Top and bottom padding of the graph
|
||||
/// </summary>
|
||||
private const int GRAPH_PADDING_Y_PX = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Radius of the point on the graph
|
||||
/// </summary>
|
||||
private const int GRAPH_POINT_RADIUS = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Size of the line on the graph
|
||||
/// </summary>
|
||||
private const int GRAPH_LINE_SIZE = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Plot points and a highscore on the graph
|
||||
/// </summary>
|
||||
/// <param name="scores">List of score values to plot</param>
|
||||
/// <param name="highscore">Highscore value (this will be plotted in a fancy color)</param>
|
||||
public void Plot(List<double> scores, double highscore)
|
||||
{
|
||||
// Remove previous marker(s)
|
||||
foreach (Transform child in progressGraph.gameObject.transform)
|
||||
Destroy(child.gameObject);
|
||||
|
||||
// Get texture reference
|
||||
Texture2D tex = progressGraph.texture as Texture2D;
|
||||
RectTransform rect = progressGraph.gameObject.transform as RectTransform;
|
||||
if (tex == null)
|
||||
{
|
||||
tex = new Texture2D(
|
||||
width: (int)rect.sizeDelta.x,
|
||||
height: (int)rect.sizeDelta.y,
|
||||
textureFormat: TextureFormat.ARGB32,
|
||||
mipCount: 3,
|
||||
linear: true
|
||||
);
|
||||
}
|
||||
tex.filterMode = FilterMode.Point;
|
||||
FillTexture(tex, backgroundColor);
|
||||
|
||||
// calculate positions and offsets
|
||||
int x0 = GRAPH_PADDING_X_PX, x1 = tex.width - GRAPH_PADDING_X_PX;
|
||||
int y0 = GRAPH_PADDING_Y_PX, y1 = tex.height - GRAPH_PADDING_Y_PX;
|
||||
double min = scores.Min();
|
||||
double max = scores.Max();
|
||||
|
||||
List<Tuple<int, int>> points = new List<Tuple<int, int>>();
|
||||
for (int i = 0; i < scores.Count; i++)
|
||||
{
|
||||
int _x = x0 + (scores.Count > 1 ? i * ((x1 - x0) / (scores.Count - 1)) : (x1 - x0) / 2);
|
||||
int _y = y0 + (int)((y1 - y0) * (min != max ? (scores[i] - min) / (max - min) : 0.5));
|
||||
points.Add(Tuple.Create(_x, _y));
|
||||
}
|
||||
|
||||
// Calculate scaling
|
||||
const int NUMBER_OF_AXES = 5;
|
||||
|
||||
double spacing = 0.0;
|
||||
if (min == max)
|
||||
{
|
||||
spacing = CalculateSpacing(highscore, NUMBER_OF_AXES);
|
||||
max = highscore + 2 * spacing;
|
||||
min = highscore - 2 * spacing;
|
||||
}
|
||||
|
||||
spacing = CalculateSpacing(max - min, NUMBER_OF_AXES);
|
||||
double begin = spacing * Math.Round(min / spacing);
|
||||
|
||||
// Draw axes
|
||||
double pixels_per_unit = (y1 - y0) / (max - min);
|
||||
double Y = begin;
|
||||
int y = y0 + (int)(pixels_per_unit * (Y - min));
|
||||
int total = 0;
|
||||
do
|
||||
{
|
||||
if (y0 <= y)
|
||||
{
|
||||
DrawLine(tex, x0, y, x1, y, 2, textColor);
|
||||
|
||||
GameObject tick = GameObject.Instantiate(axesTickMarker, rect);
|
||||
tick.GetComponent<RectTransform>().localPosition = new Vector3(-10 - rect.sizeDelta.y * rect.pivot.x, y - 25 - rect.sizeDelta.y * rect.pivot.y, 0);
|
||||
TMP_Text txt = tick.GetComponent<TMP_Text>();
|
||||
txt.text = $"{Y}";
|
||||
txt.color = textColor;
|
||||
}
|
||||
total += 1;
|
||||
Y += spacing;
|
||||
y = y0 + (int)(pixels_per_unit * (Y - min));
|
||||
|
||||
// Fail save
|
||||
if (2 * NUMBER_OF_AXES < total)
|
||||
break;
|
||||
} while (y <= y1);
|
||||
|
||||
|
||||
// Draw highscore
|
||||
if (min <= highscore && highscore <= max)
|
||||
{
|
||||
y = y0 + (int)(pixels_per_unit * (highscore - min));
|
||||
DrawLine(tex, x0, y, x1, y, GRAPH_LINE_SIZE, highscoreColor);
|
||||
GameObject marker = GameObject.Instantiate(highscoreMarker, rect);
|
||||
marker.GetComponent<RectTransform>().localPosition = new Vector3(tex.width - 50 - rect.sizeDelta.x * rect.pivot.x, y - 25 - rect.sizeDelta.y * rect.pivot.y, 0);
|
||||
}
|
||||
|
||||
// Draw points
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
Tuple<int, int> p = points[i];
|
||||
if (0 < i)
|
||||
{
|
||||
Tuple<int, int> q = points[i - 1];
|
||||
DrawLine(tex, p.Item1, p.Item2, q.Item1, q.Item2, GRAPH_LINE_SIZE, lineColor);
|
||||
}
|
||||
DrawPoint(tex, p.Item1, p.Item2, GRAPH_POINT_RADIUS, lineColor);
|
||||
}
|
||||
|
||||
// Apply to graph GameObject
|
||||
tex.Apply();
|
||||
progressGraph.texture = tex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate nice spacing
|
||||
/// </summary>
|
||||
/// <param name="mu">Either `max - min` if max != min, otherwise `highscore`</param>
|
||||
/// <param name="numberOfAxes">Number of horizontal axes grid lines shown on the graph</param>
|
||||
/// <returns>Spacing between each axes grid line</returns>
|
||||
private double CalculateSpacing(double mu, int numberOfAxes)
|
||||
{
|
||||
if (mu == 0)
|
||||
return 1.0;
|
||||
|
||||
double[] otherSpacings = { 0.5, 1.0, 2.0, 5.0 };
|
||||
|
||||
int mag = (int)Math.Floor(Math.Log10(Math.Abs(mu)));
|
||||
int MAG = (int)Math.Pow(10, mag);
|
||||
double spacing = MAG;
|
||||
foreach (double o in otherSpacings)
|
||||
{
|
||||
if (Math.Abs(mu - numberOfAxes * spacing) <= Math.Abs(mu - numberOfAxes * o * MAG))
|
||||
continue;
|
||||
spacing = o * MAG;
|
||||
}
|
||||
return spacing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set all the pixels of a texture to a given color
|
||||
/// </summary>
|
||||
/// <param name="tex">Texture to fill</param>
|
||||
/// <param name="color">Color to set the texture to</param>
|
||||
private void FillTexture(Texture2D tex, Color color)
|
||||
{
|
||||
for (int y = 0; y < tex.height; y++)
|
||||
for (int x = 0; x < tex.width; x++)
|
||||
tex.SetPixel(x, y, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw a point to a texture
|
||||
/// </summary>
|
||||
/// <param name="tex">Texture2D to plot point on</param>
|
||||
/// <param name="xc">Center x-pos</param>
|
||||
/// <param name="yc">Center y-pos</param>
|
||||
/// <param name="r">Radius (aka width and height)</param>
|
||||
/// <param name="color">Color of the point</param>
|
||||
private void DrawPoint(Texture2D tex, int xc, int yc, int r, Color color)
|
||||
{
|
||||
for (int y = yc - r; y < yc + r; y++)
|
||||
for (int x = xc - r; x < xc + r; x++)
|
||||
tex.SetPixel(x, y, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw a line to a texture
|
||||
/// </summary>
|
||||
/// <param name="tex">Texture2D to plot line on</param>
|
||||
/// <param name="x0">Starting x-pos</param>
|
||||
/// <param name="y0">Strating y-pos</param>
|
||||
/// <param name="x1">Ending x-pos</param>
|
||||
/// <param name="y1">Ending y-pos</param>
|
||||
/// <param name="size">Size of the line (width)</param>
|
||||
/// <param name="color">Color of the line</param>
|
||||
private void DrawLine(Texture2D tex, int x0, int y0, int x1, int y1, int size, Color color)
|
||||
{
|
||||
int w = x1 - x0;
|
||||
int h = y1 - y0;
|
||||
|
||||
int length = Mathf.Abs(x1 - x0);
|
||||
if (Mathf.Abs(y1 - y0) > length)
|
||||
length = Mathf.Abs(h);
|
||||
|
||||
double dx = w / (double)length;
|
||||
double dy = h / (double)length;
|
||||
|
||||
double x = x0;
|
||||
double y = y0;
|
||||
double r = size / 2;
|
||||
for (int i = 0; i <= length; i++)
|
||||
{
|
||||
for (int j = (int)(y - r); j < y + r; j++)
|
||||
for (int k = (int)(x - r); k < x + r; k++)
|
||||
tex.SetPixel(k, j, color);
|
||||
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user