You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

195 lines
6.6 KiB

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UltraCombos
{
[ExecuteAlways]
public class DroppingPaint : MonoBehaviour
{
[SerializeField] private float size = 1;
[SerializeField, Min(8)] private int segments = 16;
[SerializeField] private float smooth = 3f;
[SerializeField] private Vector2 distanceMinMax = new Vector2(1, 2);
[SerializeField] private bool isDrop = false;
[SerializeField] private bool isClear = false;
private List<List<Vector2>> paints = new List<List<Vector2>>();
private List<List<Vector2>> smoothedPaints = new List<List<Vector2>>();
private void Update()
{
if (isDrop)
{
isDrop = false;
Drop();
}
if (isClear)
{
isClear = false;
Clear();
}
var t = Time.deltaTime * smooth;
for (int i = 0; i < paints.Count; i++)
{
var points = paints[i];
for (int j = 0; j < points.Count; j++)
{
smoothedPaints[i][j] = Vector2.Lerp(smoothedPaints[i][j], points[j], t);
}
}
}
public void Drop()
{
var r = Random.Range(size * 0.1f, size * 0.2f);
var px = Random.Range(-size * 0.4f, +size * 0.4f);
var py = Random.Range(-size * 0.4f, +size * 0.4f);
var angle = Mathf.PI * 2 / segments;
var circle = Enumerable.Range(0, segments).Select(i =>
{
var x = px + r * Mathf.Cos(angle * i);
var y = py + r * Mathf.Sin(angle * i);
return new Vector2(x, y);
}).ToList();
var center = new Vector2(px, py);
var minDist = size / segments * distanceMinMax.x;
var maxDist = size / segments * distanceMinMax.y;
var index = 0;
foreach (var points in paints)
{
var pre = points.Select(p => ApplyPaintDrop(p, center, r)).ToArray();
var incs = pre.Select((p, i) =>
{
var dist = (p - pre[(i + 1) % pre.Length]).magnitude;
return dist < minDist ? 0 : Mathf.CeilToInt(dist / minDist);
}).ToArray();
var newPoints = new List<Vector2>();
for (int i = 0; i < points.Count; i++)
{
var inc = incs[i];
if (inc == 0)
{
newPoints.Add(points[i]);
}
else
{
var p1 = points[i];
var p2 = points[(i + 1) % points.Count];
for (int k = 0; k < inc; k++)
{
var p = Vector2.Lerp(p1, p2, (float)k / inc);
newPoints.Add(p);
}
}
}
points.Clear();
points.AddRange(newPoints);
smoothedPaints[index].Clear();
smoothedPaints[index].AddRange(newPoints);
for (int i = 0; i < points.Count; i++)
{
points[i] = ApplyPaintDrop(points[i], center, r);
}
index++;
}
paints.Add(circle);
smoothedPaints.Add(circle.Select(c => center).ToList());
}
public void Clear()
{
paints.Clear();
smoothedPaints.Clear();
}
private void OnDrawGizmos()
{
#if UNITY_EDITOR
using var mtx = new Handles.DrawingScope(transform.localToWorldMatrix);
Handles.DrawWireCube(Vector3.zero, Vector2.one * size);
if (smoothedPaints.Count == 0)
return;
var dh = 1f / smoothedPaints.Count;
var h = 0f;
var minDist = size / segments * distanceMinMax.x;
var maxDist = size / segments * distanceMinMax.y;
foreach (var points in smoothedPaints)
{
using var col = new Handles.DrawingScope(Color.HSVToRGB(h, 0.7f, 0.8f));
foreach (var point in points)
{
Handles.DrawWireDisc(new Vector3(point.x, point.y, 0), Vector3.forward, 0.02f);
}
//Handles.DrawPolyLine(points.Select(p => new Vector3(p.x, p.y, 0)).ToArray());
//Handles.DrawAAConvexPolygon(points.Select(p => new Vector3(p.x, p.y, 0)).ToArray());
for (int i = 0; i < points.Count; ++i)
{
var p1 = points[i];
var p2 = points[(i + 1) % points.Count];
var dist = (p1 - p2).magnitude;
var t = Mathf.Clamp01((dist - minDist) / (maxDist - minDist));
var c = Color.Lerp(Color.cyan, Color.magenta, t);
using var lc = new Handles.DrawingScope(c);
Handles.DrawLine(p1, p2);
}
h += dh;
}
#endif
}
private Vector2 ApplyPaintDrop(Vector2 p, Vector2 c, float r)
{
var d = Vector2.Distance(p, c);
if (d > r)
{
return c + (p - c) * Mathf.Sqrt(1 + (r * r) / (d * d));
}
var edge = c + (p - c) * (r / d + 0.002f);
return ApplyPaintDrop(edge, c, r);
}
private List<Vector2> ResamplePoints(List<Vector2> points, float minSpacing, float maxSpacing)
{
List<Vector2> newPoints = new List<Vector2>();
int count = points.Count;
for (int i = 0; i < count; i++)
{
Vector2 p1 = points[i];
Vector2 p2 = points[(i + 1) % count];
float dist = Vector2.Distance(p1, p2);
newPoints.Add(p1);
if (dist > maxSpacing)
{
int numNewPoints = Mathf.FloorToInt(dist / minSpacing);
for (int j = 1; j <= numNewPoints; j++)
{
float t = j / (float)(numNewPoints + 1);
newPoints.Add(Vector2.Lerp(p1, p2, t));
}
}
}
return newPoints;
}
}
}