349 lines
9.6 KiB
C#
349 lines
9.6 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
namespace game
|
|
{
|
|
[RequireComponent(typeof(RawImage))]
|
|
[RequireComponent(typeof(RectTransform))]
|
|
public class ScratchCardMaskUGUI : ScratchCardMask
|
|
{
|
|
private static readonly int OffsetScalePropertyId = Shader.PropertyToID("_OffsetScale");
|
|
|
|
internal RawImage Image
|
|
{
|
|
get
|
|
{
|
|
if (image == null)
|
|
{
|
|
image = GetComponent<RawImage>();
|
|
}
|
|
|
|
return image;
|
|
}
|
|
}
|
|
|
|
private RectTransform RectTransform
|
|
{
|
|
get
|
|
{
|
|
if (rectTransform == null)
|
|
{
|
|
rectTransform = GetComponent<RectTransform>();
|
|
}
|
|
|
|
return rectTransform;
|
|
}
|
|
}
|
|
|
|
[Header("Brush")]
|
|
[SerializeField]
|
|
private Material m_BrushMaterial;
|
|
[SerializeField] private Vector2 m_BrushSize = new Vector2(50f, 50f);
|
|
[SerializeField]
|
|
private int m_InterpolationMaxCount = 4;
|
|
[SerializeField]
|
|
private int m_InterpolationMinDistance = 8;
|
|
|
|
[Header("Mask Texture")]
|
|
[SerializeField]
|
|
private float maskTextureScale = 1.0f;
|
|
[SerializeField]
|
|
private float maxMaskTextureSize = 512;
|
|
|
|
private bool baseTextureSaved;
|
|
private Material brush;
|
|
|
|
private RectTransform rectTransform;
|
|
private RenderTexture targetTexture;
|
|
private Texture baseTexture;
|
|
private RawImage image;
|
|
private Vector2 prevDrawPosition;
|
|
|
|
private float m_Progress = 0f;
|
|
|
|
#region 笔刷相关
|
|
private Texture2D m_TempTexture;
|
|
private void CreateTempTexture()
|
|
{
|
|
m_TempTexture = ScratchCardUtils.GetReadableCopy(targetTexture);
|
|
}
|
|
|
|
public void UpdateTempTexture()
|
|
{
|
|
if (m_Threshold <= 0f)
|
|
{
|
|
//Debug.LogWarning("---- " + gameObject.name + " ok");
|
|
return;
|
|
}
|
|
|
|
m_TempTexture.Reinitialize(targetTexture.width, targetTexture.height);
|
|
|
|
ScratchCardUtils.UpdateTexture2D(m_TempTexture, targetTexture, targetTexture.width, targetTexture.height);
|
|
|
|
Color[] colorArray = m_TempTexture.GetPixels();
|
|
|
|
int count = 0;
|
|
int total = colorArray.Length;
|
|
for (int i = 0; i < total; ++i)
|
|
{
|
|
if (colorArray[i].a <= m_AlphaThreshold)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
m_Progress = (float)count / total;
|
|
|
|
//if (m_Progress >= m_Threshold)
|
|
//{
|
|
// Debug.LogWarning("---- " + gameObject.name + " ok 当前进度为: " + m_Progress);
|
|
//}
|
|
//else
|
|
//{
|
|
// Debug.LogWarning("---- " + gameObject.name + " 当前进度为: " + m_Progress);
|
|
//}
|
|
}
|
|
#endregion
|
|
|
|
#region 生命周期
|
|
private void Awake()
|
|
{
|
|
SaveBaseTexture();
|
|
|
|
m_Progress = 0f;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
Reload();
|
|
|
|
m_Progress = 0f;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
DisposeTargetTexture();
|
|
DisposeBrush();
|
|
}
|
|
|
|
private void OnRectTransformDimensionsChange()
|
|
{
|
|
SaveBaseTexture();
|
|
Reload();
|
|
|
|
m_Progress = 0f;
|
|
}
|
|
public void UpdateScratchCardMask(Texture texture)
|
|
{
|
|
baseTexture = texture;
|
|
baseTextureSaved = true;
|
|
|
|
m_Progress = 0f;
|
|
}
|
|
|
|
public void InitMaskUGUI(Material brushMaterial, Vector2 brushSize, int interpolationMaxCount, int interpolationMinDistance)
|
|
{
|
|
this.m_BrushMaterial = brushMaterial;
|
|
this.m_BrushSize = brushSize;
|
|
this.m_InterpolationMaxCount = interpolationMaxCount;
|
|
this.m_InterpolationMinDistance = interpolationMinDistance;
|
|
|
|
CreateBrush();
|
|
}
|
|
#endregion
|
|
|
|
public void Reload()
|
|
{
|
|
var rect = RectTransform.rect;
|
|
if (rect.width <= 0 || rect.height <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AcquireTargetTexture(rect);
|
|
}
|
|
|
|
private void SaveBaseTexture()
|
|
{
|
|
if (!baseTextureSaved)
|
|
{
|
|
if (Image.texture != null)
|
|
{
|
|
baseTexture = Image.texture;
|
|
}
|
|
|
|
baseTextureSaved = true;
|
|
}
|
|
}
|
|
|
|
private void CreateBrush()
|
|
{
|
|
if (m_BrushMaterial == null)
|
|
{
|
|
m_BrushMaterial = Resources.Load<Material>("Materials/ScratchCard_DefaultBrush");
|
|
}
|
|
|
|
DisposeBrush();
|
|
|
|
brush = new Material(m_BrushMaterial);
|
|
}
|
|
|
|
private void DisposeBrush()
|
|
{
|
|
if (brush != null)
|
|
{
|
|
Destroy(brush);
|
|
brush = null;
|
|
}
|
|
}
|
|
|
|
private void AcquireTargetTexture(Rect rect)
|
|
{
|
|
var aspect = rect.height / rect.width;
|
|
var width = (int)Mathf.Min(maxMaskTextureSize, rect.width * maskTextureScale);
|
|
var height = (int)(width * aspect);
|
|
|
|
if (targetTexture != null && (targetTexture.width != width || targetTexture.height != height))
|
|
{
|
|
DisposeTargetTexture();
|
|
}
|
|
|
|
if (targetTexture == null)
|
|
{
|
|
targetTexture = RenderTexture.GetTemporary(width, height, -1, RenderTextureFormat.ARGB32);
|
|
Image.texture = targetTexture;
|
|
|
|
ClearTexture();
|
|
|
|
CreateTempTexture();
|
|
}
|
|
}
|
|
|
|
private void DisposeTargetTexture()
|
|
{
|
|
if (targetTexture != null)
|
|
{
|
|
RenderTexture.ReleaseTemporary(targetTexture);
|
|
targetTexture = null;
|
|
}
|
|
}
|
|
|
|
private void ClearTargetWithColor(Color color)
|
|
{
|
|
var tmp = RenderTexture.active;
|
|
RenderTexture.active = targetTexture;
|
|
GL.Clear(true, true, color);
|
|
RenderTexture.active = tmp;
|
|
}
|
|
|
|
private void ClearTexture()
|
|
{
|
|
if (baseTexture != null)
|
|
{
|
|
ClearTargetWithColor(Color.clear);
|
|
Graphics.Blit(baseTexture, targetTexture, Image.material);
|
|
}
|
|
else
|
|
{
|
|
ClearTargetWithColor(Color.white);
|
|
}
|
|
}
|
|
|
|
public override float GetRevealProgress()
|
|
{
|
|
return m_Progress;
|
|
}
|
|
|
|
public bool IsComputeShaderSupported()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
[ContextMenu("Restore")]
|
|
public void Restore()
|
|
{
|
|
ClearTexture();
|
|
m_Progress = 0f;
|
|
}
|
|
|
|
public void OnMaskBeginDrag(Vector2 position)
|
|
{
|
|
prevDrawPosition = position;
|
|
}
|
|
|
|
public bool OnMaskDrag(Vector2 position)
|
|
{
|
|
if (targetTexture == null || brush == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var drawPosition = position;
|
|
var progressChanged = false;
|
|
|
|
var delta = drawPosition - prevDrawPosition;
|
|
if (delta != drawPosition)
|
|
{
|
|
var distance = delta.magnitude;
|
|
var count = Mathf.Min(m_InterpolationMaxCount, (int)distance / m_InterpolationMinDistance);
|
|
|
|
for (int i = 1; i < count; ++i)
|
|
{
|
|
progressChanged |= DrawAt(prevDrawPosition + delta * ((float)i / count));
|
|
}
|
|
}
|
|
|
|
progressChanged |= DrawAt(drawPosition);
|
|
prevDrawPosition = drawPosition;
|
|
|
|
if (progressChanged)
|
|
{
|
|
//OnRevealProgressChanged();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool DrawAt(Vector2 screenPoint)
|
|
{
|
|
var point = EventScratchTicketConfig.ScreenToGraphicLocalPoint(Image, screenPoint); // 将屏幕坐标转换为Image的本地坐标
|
|
var rect = RectTransform.rect;
|
|
|
|
Vector2 brushScale = new Vector2(m_BrushSize.x / rect.width, m_BrushSize.y / rect.height);
|
|
|
|
brush.SetVector(OffsetScalePropertyId, CalculateOffsetScale(RectTransform, point, brushScale));
|
|
Graphics.Blit(brush.mainTexture, targetTexture, brush);
|
|
|
|
return true;
|
|
}
|
|
|
|
internal static Vector4 CalculateOffsetScale(RectTransform rt, Vector2 localPoint, Vector2 scale)
|
|
{
|
|
var rect = rt.rect;
|
|
localPoint += rt.pivot * rect.size; // 从左到右,从下到上,距离左下角原点位置
|
|
|
|
var aspect = rect.height / rect.width;
|
|
var sx = scale.x * aspect;
|
|
var sy = scale.y;
|
|
var px = (localPoint.x / rect.width) - (0.5f * sx);
|
|
var py = (localPoint.y / rect.height) - (0.5f * sy);
|
|
|
|
return new Vector4(px, py, 1.0f / sx, 1.0f / sy);
|
|
}
|
|
|
|
private void OnRevealProgressChangedCallback(ScratchCardMask mask, float progress, bool isRevealed)
|
|
{
|
|
Debug.LogError("--- mask:" + mask + ", progress:" + progress + ", isRevealed:" + isRevealed);
|
|
}
|
|
|
|
public void DrawInCenter()
|
|
{
|
|
int width = UnityEngine.Screen.width;
|
|
int height = UnityEngine.Screen.height;
|
|
|
|
Vector2 center = new Vector2(width >> 1, height >> 1);
|
|
DrawAt(center);
|
|
}
|
|
}
|
|
}
|