Files
JJBB/Assets/Project/Script/GUI/Base/ScratchTicket.cs
2024-08-23 15:49:34 +08:00

207 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
}
}
}