207 lines
6.0 KiB
C#
207 lines
6.0 KiB
C#
using System;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.Events;
|
||
|
||
[RequireComponent(typeof(RawImage))]
|
||
public class ScratchTicket : MonoBehaviour
|
||
{
|
||
public Camera uiCamera
|
||
{
|
||
get { return UIManager.Instance().UICamera; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 笔刷半径,单位为Ui长度
|
||
/// </summary>
|
||
public float radius = 20f;
|
||
|
||
/// <summary>
|
||
/// RenderTexture尺寸比例
|
||
/// </summary>
|
||
public float renderTexRadio = 0.5f;
|
||
|
||
public event UnityAction<float> onCleanRatioUpdate;
|
||
|
||
/// <summary>
|
||
/// 当前清空程度
|
||
/// </summary>
|
||
private float _cleanPixel;
|
||
|
||
public float cleanRatio
|
||
{
|
||
get
|
||
{
|
||
if (_renderTexture == null)
|
||
return 0f;
|
||
else
|
||
{
|
||
var pixelCount = _renderTexture.width * _renderTexture.height;
|
||
return pixelCount > 0 ? _cleanPixel / pixelCount : 1f;
|
||
}
|
||
}
|
||
}
|
||
|
||
private RawImage _rawImage;
|
||
private Texture2D _renderTexture;
|
||
private Material _renderMaterial;
|
||
|
||
private Vector2 _min;
|
||
private Vector2 _max;
|
||
private bool _start;
|
||
|
||
private void Awake()
|
||
{
|
||
_rawImage = GetComponent<RawImage>();
|
||
var rect = _rawImage.rectTransform.rect;
|
||
_min = rect.min;
|
||
_max = rect.max;
|
||
var dragComponent = gameObject.EnsureComponent<UiDragComponent>();
|
||
dragComponent.onDrag += OnDrag;
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
if (_start)
|
||
Reset();
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
if (renderTexRadio <= 0f)
|
||
renderTexRadio = 1f;
|
||
if (_renderTexture == null)
|
||
{
|
||
var width = Mathf.FloorToInt((_max.x - _min.x) * renderTexRadio);
|
||
var height = Mathf.FloorToInt((_max.y - _min.y) * renderTexRadio);
|
||
_renderTexture = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
||
}
|
||
|
||
_renderMaterial = _rawImage.material;
|
||
if (_renderMaterial != null)
|
||
{
|
||
_renderMaterial = Instantiate(_renderMaterial);
|
||
_rawImage.material = _renderMaterial;
|
||
_renderMaterial.SetTexture("_ScratchTex", _renderTexture);
|
||
}
|
||
|
||
_start = true;
|
||
OnEnable();
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
if (_renderMaterial != null)
|
||
Destroy(_renderMaterial);
|
||
if (_renderTexture != null)
|
||
Destroy(_renderTexture);
|
||
}
|
||
|
||
public void OnDrag(Vector2 lastPoint, Vector2 currentPoint)
|
||
{
|
||
var pixelRadius = radius / (_max.x - _min.x) * _renderTexture.width;
|
||
if (pixelRadius > 0)
|
||
{
|
||
Vector2 start;
|
||
Vector2 end;
|
||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(_rawImage.rectTransform, lastPoint, uiCamera,
|
||
out start) &&
|
||
RectTransformUtility.ScreenPointToLocalPointInRectangle(_rawImage.rectTransform, currentPoint, uiCamera,
|
||
out end))
|
||
{
|
||
var radiusSqr = pixelRadius * pixelRadius;
|
||
var width = _renderTexture.width;
|
||
var height = _renderTexture.height;
|
||
start = LocalPointToPixelPos(start);
|
||
end = LocalPointToPixelPos(end);
|
||
var dirty = false;
|
||
for (var x = 0; x < width; x++)
|
||
{
|
||
for (var y = 0; y < height; y++)
|
||
{
|
||
var distSqr = DistanceSqrToLine(new Vector2(x, y), start, end);
|
||
if (distSqr < radiusSqr)
|
||
{
|
||
var ratio = distSqr / radiusSqr;
|
||
if (ratio < 0.1f)
|
||
ratio = 0f;
|
||
var color = _renderTexture.GetPixel(x, y);
|
||
if (color.a > ratio)
|
||
{
|
||
dirty = true;
|
||
_cleanPixel += color.a - ratio;
|
||
color.a = ratio;
|
||
_renderTexture.SetPixel(x, y, color);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (dirty)
|
||
{
|
||
_renderTexture.Apply();
|
||
if (onCleanRatioUpdate != null)
|
||
onCleanRatioUpdate.Invoke(cleanRatio);
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
private Vector2 LocalPointToPixelPos(Vector2 localPoint)
|
||
{
|
||
var uv = new Vector2(
|
||
(localPoint.x - _min.x) / (_max.x - _min.x),
|
||
(localPoint.y - _min.y) / (_max.y - _min.y));
|
||
uv.x = uv.x * _renderTexture.width;
|
||
uv.y = uv.y * _renderTexture.height;
|
||
return uv;
|
||
}
|
||
|
||
private float DistanceSqrToLine(Vector2 point, Vector2 start, Vector2 end)
|
||
{
|
||
var a = DistanceSqrToPoint(point, start);
|
||
if (a < 0.0001f)
|
||
return 0f;
|
||
var b = DistanceSqrToPoint(point, end);
|
||
if (b < 0.0001f)
|
||
return 0f;
|
||
var c = DistanceSqrToPoint(start, end);
|
||
if (c < 0.0001f)
|
||
return a;
|
||
if (a > b + c)
|
||
return b;
|
||
if (b > a + c)
|
||
return a;
|
||
var la = Mathf.Sqrt(a);
|
||
var lb = Mathf.Sqrt(b);
|
||
var lc = Mathf.Sqrt(c);
|
||
var l = (la + lb + lc) * 0.5f;
|
||
l = l * (l - la) * (l - lb) * (l - lc);
|
||
return 4 * l / c;
|
||
}
|
||
|
||
private float DistanceSqrToPoint(Vector2 point, Vector2 end)
|
||
{
|
||
return (point.x - end.x) * (point.x - end.x) + (point.y - end.y) * (point.y - end.y);
|
||
}
|
||
|
||
public void Reset()
|
||
{
|
||
_cleanPixel = 0f;
|
||
if (_renderTexture != null)
|
||
{
|
||
var colors = _renderTexture.GetPixels();
|
||
for (var i = 0; i < colors.Length; i++)
|
||
{
|
||
var color = colors[i];
|
||
color.a = 1f;
|
||
colors[i] = color;
|
||
}
|
||
|
||
_renderTexture.SetPixels(colors);
|
||
_renderTexture.Apply();
|
||
}
|
||
}
|
||
} |