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; }
}
///
/// 笔刷半径,单位为Ui长度
///
public float radius = 20f;
///
/// RenderTexture尺寸比例
///
public float renderTexRadio = 0.5f;
public event UnityAction onCleanRatioUpdate;
///
/// 当前清空程度
///
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();
var rect = _rawImage.rectTransform.rect;
_min = rect.min;
_max = rect.max;
var dragComponent = gameObject.EnsureComponent();
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();
}
}
}