备份CatanBuilding瘦身独立工程
This commit is contained in:
576
Assets/Scripts/UI/ScratchTicket/ScratchCard/ScratchCard.cs
Normal file
576
Assets/Scripts/UI/ScratchTicket/ScratchCard/ScratchCard.cs
Normal file
@@ -0,0 +1,576 @@
|
||||
using asap.core;
|
||||
using cfg;
|
||||
using DG.Tweening;
|
||||
using GameCore;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class ScratchCard : MonoBehaviour, IBeginDragHandler, IDragHandler
|
||||
{
|
||||
[Header("Mask")]
|
||||
public List<ScratchCardMaskUGUI> m_MaskList = new List<ScratchCardMaskUGUI>();
|
||||
[SerializeField] private int m_CDFrame = 5;
|
||||
[SerializeField] private string m_Ticket_Mask_Texture_Name = "sp_scratchticket_ticket_mask";
|
||||
|
||||
[Header("Brush")]
|
||||
[SerializeField] private EditablePolygon m_OperatingArea;
|
||||
[SerializeField] private GameObject m_BrushRoot;
|
||||
[SerializeField] private Image m_Brush;
|
||||
|
||||
[SerializeField] private float m_BrushDurationTime = 1.0f;
|
||||
[SerializeField] private float m_BrushSpeed = 1000.0f;
|
||||
[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;
|
||||
[SerializeField] private EventScratchTicketScratchType m_ScratchType = EventScratchTicketScratchType.TypeInvalid;
|
||||
|
||||
[Header("Animation")]
|
||||
[SerializeField] private Animation m_Animation;
|
||||
[SerializeField] private string m_Anim_Ticket_Out = "ticket_out";
|
||||
[SerializeField] private float m_Anim_Ticket_Out_DurationTime = 1.1f;
|
||||
|
||||
[SerializeField] private CanvasGroup m_ShadowCanvasGroup;
|
||||
[SerializeField] private CanvasGroup m_TicketCanvasGroup;
|
||||
|
||||
[Header("音效")]
|
||||
[SerializeField] private List<OutPlaySound> m_ScratchOutPlaySoundList = new List<OutPlaySound>();
|
||||
[SerializeField] private List<float> m_ScratchOutPlaySoundTimeList = new List<float>();
|
||||
|
||||
[Header("Toast相关")]
|
||||
[SerializeField] private float m_ToastIntervalTime = 1.0f;
|
||||
|
||||
private int m_CumulativeFrame = 0;
|
||||
private int m_MaskIndex = 0;
|
||||
private float m_BrushCumulativeTime = 0f;
|
||||
|
||||
#region 音效相关
|
||||
private bool m_IsPlayingSound = false;
|
||||
private float m_PlayingSoundTime = 0;
|
||||
private float m_PlayingSoundCumulativeTime = 0f;
|
||||
private void PlayScratchSound()
|
||||
{
|
||||
int count = m_ScratchOutPlaySoundList.Count;
|
||||
if (count < 1) return;
|
||||
|
||||
foreach (var item in m_ScratchOutPlaySoundList)
|
||||
{
|
||||
if (item.gameObject.activeSelf)
|
||||
{
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
int index = UnityEngine.Random.Range(0, count);
|
||||
|
||||
m_IsPlayingSound = true;
|
||||
m_PlayingSoundTime = m_ScratchOutPlaySoundTimeList[index];
|
||||
m_PlayingSoundCumulativeTime = 0f;
|
||||
|
||||
m_ScratchOutPlaySoundList[index].gameObject.SetActive(true);
|
||||
}
|
||||
private void StopScratchSound()
|
||||
{
|
||||
foreach (var item in m_ScratchOutPlaySoundList)
|
||||
{
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
m_IsPlayingSound = false;
|
||||
m_PlayingSoundTime = float.MaxValue;
|
||||
m_PlayingSoundCumulativeTime = float.MinValue;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ScratchCardMask 相关
|
||||
public void InitMaskList()
|
||||
{
|
||||
foreach (var item in m_MaskList)
|
||||
{
|
||||
item.InitMaskUGUI(m_BrushMaterial, m_BrushSize, m_InterpolationMaxCount, m_InterpolationMinDistance);
|
||||
//item.RevealProgressChanged = OnRevealProgressChangedCallback;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRevealProgressChangedCallback(ScratchCardMask mask, float progress, bool isRevealed)
|
||||
{
|
||||
//Debug.LogError("--- ScratchCard OnRevealProgressChangedCallback mask:" + mask + ", progress:" + progress + ", isRevealed:" + isRevealed);
|
||||
|
||||
bool flag = true;
|
||||
foreach (var item in m_MaskList)
|
||||
{
|
||||
if (!item.IsRevealed())
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if (flag)
|
||||
//{
|
||||
// Debug.LogError("--- they have all revealed");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// Debug.LogError("--- they have not all revealed");
|
||||
//}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Brush 相关
|
||||
private bool m_IsBrushPainting = false;
|
||||
public void SetBrushPosition(Vector2 screenPosition)
|
||||
{
|
||||
if (!m_OperatingArea.ContainsPoint(screenPosition))
|
||||
{
|
||||
return;
|
||||
}
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
transform as RectTransform,
|
||||
screenPosition,
|
||||
UIManager.Instance.UICanvas.worldCamera,
|
||||
out Vector2 localPoint);
|
||||
|
||||
|
||||
if (!m_Brush.gameObject.activeSelf)
|
||||
{
|
||||
m_Brush.gameObject.SetActive(true);
|
||||
|
||||
m_Brush.rectTransform.localPosition = localPoint;
|
||||
}
|
||||
|
||||
float distance = Vector2.Distance(m_Brush.rectTransform.localPosition, localPoint);
|
||||
|
||||
float time = distance / m_BrushSpeed;
|
||||
|
||||
m_Brush.rectTransform.DOKill();
|
||||
m_Brush.rectTransform.DOLocalMove(localPoint, time).SetEase(Ease.Linear);
|
||||
|
||||
//m_BrushCumulativeTime = 0f;
|
||||
}
|
||||
private void OnMaskBeginDrag()
|
||||
{
|
||||
Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(UIManager.Instance.UICanvas.worldCamera, m_Brush.transform.position);
|
||||
foreach (var item in m_MaskList)
|
||||
{
|
||||
item.OnMaskBeginDrag(screenPoint);
|
||||
}
|
||||
}
|
||||
private void OnMaskDrag()
|
||||
{
|
||||
bool flag = false;
|
||||
Vector2 screenPoint = RectTransformUtility.WorldToScreenPoint(UIManager.Instance.UICanvas.worldCamera, m_Brush.transform.position);
|
||||
foreach (var item in m_MaskList)
|
||||
{
|
||||
if (item.OnMaskDrag(screenPoint))
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
//if (flag)
|
||||
//{
|
||||
// bool isAllRevealed = true;
|
||||
// foreach (var item in m_MaskList)
|
||||
// {
|
||||
// if (!item.IsRevealed())
|
||||
// {
|
||||
// isAllRevealed = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (isAllRevealed)
|
||||
// {
|
||||
// Debug.LogError("=== ok");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IBeginDragHandler + IDragHandler 相关
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (m_ScratchType != EventScratchTicketScratchType.TypeScratch1) return;
|
||||
//Debug.LogWarning("---- ScratchCard OnBeginDrag");
|
||||
|
||||
SetBrushPosition(eventData.position);
|
||||
|
||||
m_BrushCumulativeTime = 0f;
|
||||
|
||||
//foreach (var item in m_MaskList)
|
||||
//{
|
||||
// item.OnMaskBeginDrag(eventData.position);
|
||||
//}
|
||||
}
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (m_ScratchType != EventScratchTicketScratchType.TypeScratch1) return;
|
||||
//Debug.LogWarning("---- ScratchCard OnDrag");
|
||||
|
||||
SetBrushPosition(eventData.position);
|
||||
|
||||
m_BrushCumulativeTime = 0f;
|
||||
|
||||
//bool flag = false;
|
||||
//foreach (var item in m_MaskList)
|
||||
//{
|
||||
// if (item.OnMaskDrag(eventData.position))
|
||||
// {
|
||||
// flag = true;
|
||||
// }
|
||||
//}
|
||||
//if (flag)
|
||||
//{
|
||||
// bool isAllRevealed = true;
|
||||
// foreach (var item in m_MaskList)
|
||||
// {
|
||||
// if (!item.IsRevealed())
|
||||
// {
|
||||
// isAllRevealed = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (isAllRevealed)
|
||||
// {
|
||||
// Debug.LogError("=== ok");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TypeScratch1 动画等相关
|
||||
private IEnumerator PlayTicketOutAnim(EventScratchTicketScratchType scratchType)
|
||||
{
|
||||
// 播放 m_Anim_Ticket_Out
|
||||
m_Animation.Play(m_Anim_Ticket_Out);
|
||||
yield return new WaitForSeconds(m_Anim_Ticket_Out_DurationTime);
|
||||
|
||||
// 重置 ScratchCard 图片资源,并将ticket和shadow的alpha设置为1(显示)
|
||||
foreach (var item in m_MaskList)
|
||||
{
|
||||
item.Restore();
|
||||
//item.Reload();
|
||||
}
|
||||
m_ShadowCanvasGroup.alpha = 1.0f;
|
||||
m_TicketCanvasGroup.alpha = 1.0f;
|
||||
|
||||
if (scratchType == EventScratchTicketScratchType.TypeScratch1)
|
||||
{
|
||||
FishingScratchTicketAct.Publish(new EventScratchTicketPanelPlayEndAnimData()
|
||||
{
|
||||
ScratchType = scratchType
|
||||
});
|
||||
}
|
||||
else if (scratchType == EventScratchTicketScratchType.TypeScratch5)
|
||||
{
|
||||
FishingScratchTicketAct.Publish(new EventScratchTicketPlayScratchType5());
|
||||
}
|
||||
}
|
||||
private IEnumerator PlayCardRevealedAnimInScratch1(EventScratchTicketScratchType scratchType)
|
||||
{
|
||||
// 隐藏笔刷
|
||||
m_Brush.gameObject.SetActive(false);
|
||||
// 确认奖励
|
||||
EventScratchCard scratchCard = m_DataManager.GetCurrentEventScratchCard();
|
||||
if (scratchCard.DropReward == 0)
|
||||
{
|
||||
// 空奖
|
||||
FishingScratchTicketAct.Publish(new EventScratchTicketRewardEmptyData()
|
||||
{
|
||||
ScratchType = EventScratchTicketScratchType.TypeScratch1
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// 播放 m_Anim_Ticket_Out
|
||||
m_Animation.Play(m_Anim_Ticket_Out);
|
||||
yield return new WaitForSeconds(m_Anim_Ticket_Out_DurationTime);
|
||||
|
||||
// 重置 ScratchCard 图片资源,并将ticket和shadow的alpha设置为1(显示)
|
||||
foreach (var item in m_MaskList)
|
||||
{
|
||||
item.Restore();
|
||||
//item.Reload();
|
||||
}
|
||||
m_ShadowCanvasGroup.alpha = 1.0f;
|
||||
m_TicketCanvasGroup.alpha = 1.0f;
|
||||
|
||||
// RewardFly
|
||||
FishingScratchTicketAct.Publish(new EventScratchTicketStampRewardFlyData()
|
||||
{
|
||||
ScratchType = scratchType,
|
||||
SrcPosition = ticket_reward.transform.position,
|
||||
LocalScale = ticket_reward.transform.localScale,
|
||||
IconSize = ticket_reward.rectTransform.sizeDelta.x
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TypeScratch5 动画等相关
|
||||
private IEnumerator PlayCardRevealedAnimInScratch5(EventScratchTicketScratchType scratchType)
|
||||
{
|
||||
// 隐藏笔刷
|
||||
m_Brush.gameObject.SetActive(false);
|
||||
|
||||
// 确认奖励
|
||||
EventScratchCard scratchCard = m_DataManager.GetCurrentEventScratchCard();
|
||||
if (scratchCard.DropReward == 0)
|
||||
{
|
||||
// 空奖
|
||||
FishingScratchTicketAct.Publish(new EventScratchTicketRewardEmptyData()
|
||||
{
|
||||
ScratchType = scratchType
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// 播放 m_Anim_Ticket_Out
|
||||
m_Animation.Play(m_Anim_Ticket_Out);
|
||||
yield return new WaitForSeconds(m_Anim_Ticket_Out_DurationTime);
|
||||
|
||||
// 重置 ScratchCard 图片资源,并将ticket和shadow的alpha设置为1(显示)
|
||||
foreach (var item in m_MaskList)
|
||||
{
|
||||
item.Restore();
|
||||
//item.Reload();
|
||||
}
|
||||
m_ShadowCanvasGroup.alpha = 1.0f;
|
||||
m_TicketCanvasGroup.alpha = 1.0f;
|
||||
|
||||
FishingScratchTicketAct.Publish(new EventScratchTicketPlayScratchType5());
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 事件
|
||||
private void InitEvent()
|
||||
{
|
||||
FishingScratchTicketAct.Subscribe<EventScratchTicketChangeScratchTypeData>(ChangeScratchType);
|
||||
FishingScratchTicketAct.Subscribe<EventScratchTicketRevealedAllData>(OnScratchCardRevealedAll);
|
||||
FishingScratchTicketAct.Subscribe<EventScratchTicketUpdateEventScratchCardData>(UpdateEventScratchCardData);
|
||||
FishingScratchTicketAct.Subscribe<EventScratchTicketOutData>(OnEventScratchTicketOutDataListener);
|
||||
}
|
||||
private void OnEventScratchTicketOutDataListener(EventScratchTicketOutData data)
|
||||
{
|
||||
StartCoroutine(PlayTicketOutAnim(data.ScratchType));
|
||||
}
|
||||
private void UpdateEventScratchCardData(EventScratchTicketUpdateEventScratchCardData data)
|
||||
{
|
||||
var scratchCard = m_DataManager.GetCurrentEventScratchCard();
|
||||
if (scratchCard == null) return;
|
||||
|
||||
var sprite = m_DataManager.GetSprite(scratchCard.Card);
|
||||
|
||||
ticket_reward.sprite = sprite;
|
||||
|
||||
ticket_maskCore.UpdateScratchCardMask(sprite.texture);
|
||||
ticket_maskCore.Restore();
|
||||
ticket_maskCore.SetThreshold(scratchCard.CorePercent);
|
||||
|
||||
ticket_mask.Restore();
|
||||
}
|
||||
private void OnScratchCardRevealedAll(EventScratchTicketRevealedAllData data)
|
||||
{
|
||||
StopScratchSound();
|
||||
EventScratchCard scratchCard = m_DataManager.GetCurrentEventScratchCard();
|
||||
if (scratchCard.DropReward > 0)
|
||||
{
|
||||
m_DataManager.AddScratchStamp(scratchCard.ID);
|
||||
}
|
||||
|
||||
if (data.ScratchType == EventScratchTicketScratchType.TypeScratch1)
|
||||
{
|
||||
StartCoroutine(PlayCardRevealedAnimInScratch1(EventScratchTicketScratchType.TypeScratch1));
|
||||
}
|
||||
else if (data.ScratchType == EventScratchTicketScratchType.TypeScratch5)
|
||||
{
|
||||
StartCoroutine(PlayCardRevealedAnimInScratch5(EventScratchTicketScratchType.TypeScratch5));
|
||||
}
|
||||
}
|
||||
private void ChangeScratchType(EventScratchTicketChangeScratchTypeData data)
|
||||
{
|
||||
m_ScratchType = data.ScratchType;
|
||||
if (m_ScratchType != EventScratchTicketScratchType.TypeInvalid)
|
||||
{
|
||||
m_BrushRoot.SetActive(true);
|
||||
m_Brush.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UI
|
||||
private Image ticket_reward;
|
||||
private ScratchCardMaskUGUI ticket_maskCore;
|
||||
private ScratchCardMaskUGUI ticket_mask;
|
||||
|
||||
private void InitUI()
|
||||
{
|
||||
ticket_reward = transform.Find("ticket_reward").GetComponent<Image>();
|
||||
ticket_maskCore = transform.Find("ticket_maskCore").GetComponent<ScratchCardMaskUGUI>();
|
||||
ticket_mask = transform.Find("ticket_mask").GetComponent<ScratchCardMaskUGUI>();
|
||||
}
|
||||
|
||||
public void RefreshData()
|
||||
{
|
||||
UpdateEventScratchCardData(null);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 生命周期
|
||||
private EventScratchTicketDataManager m_DataManager;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
m_DataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
|
||||
|
||||
InitUI();
|
||||
|
||||
InitMaskList();
|
||||
|
||||
InitEvent();
|
||||
|
||||
RefreshData();
|
||||
}
|
||||
|
||||
private bool m_IsToasting = false;
|
||||
private float m_CumulativeToastIntervalTime = 0f;
|
||||
private void Update()
|
||||
{
|
||||
if (m_ScratchType == EventScratchTicketScratchType.TypeInvalid)
|
||||
{
|
||||
if (Input.GetMouseButtonDown(0) || Input.GetMouseButton(0))
|
||||
{
|
||||
if (!m_IsToasting && m_OperatingArea.ContainsPoint(Input.mousePosition))
|
||||
{
|
||||
ToastPanel.Show(LocalizationMgr.GetText("UI_EventScratchTicketPanel_9"));
|
||||
m_IsToasting = true;
|
||||
m_CumulativeToastIntervalTime = 0f;
|
||||
}
|
||||
}
|
||||
if (m_IsToasting)
|
||||
{
|
||||
if (m_CumulativeToastIntervalTime >= m_ToastIntervalTime)
|
||||
{
|
||||
m_CumulativeToastIntervalTime = 0f;
|
||||
m_IsToasting = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CumulativeToastIntervalTime += Time.deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_ScratchType == EventScratchTicketScratchType.TypeScratch1)
|
||||
{
|
||||
bool flag = false;
|
||||
if (!Input.GetMouseButtonDown(0) && !Input.GetMouseButton(0))
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
else if (!m_OperatingArea.ContainsPoint(Input.mousePosition))
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (m_BrushCumulativeTime >= m_BrushDurationTime)
|
||||
{
|
||||
if (m_Brush.gameObject.activeSelf)
|
||||
{
|
||||
m_Brush.gameObject.SetActive(false);
|
||||
m_IsBrushPainting = false;
|
||||
StopScratchSound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BrushCumulativeTime += Time.deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_ScratchType != EventScratchTicketScratchType.TypeInvalid)
|
||||
{
|
||||
if (m_Brush.gameObject.activeSelf)
|
||||
{
|
||||
if (m_IsPlayingSound)
|
||||
{
|
||||
m_PlayingSoundCumulativeTime += Time.deltaTime;
|
||||
if (m_PlayingSoundCumulativeTime >= m_PlayingSoundTime)
|
||||
{
|
||||
PlayScratchSound();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayScratchSound();
|
||||
}
|
||||
|
||||
if (m_IsBrushPainting == false)
|
||||
{
|
||||
m_IsBrushPainting = true;
|
||||
|
||||
OnMaskBeginDrag();
|
||||
}
|
||||
else
|
||||
{
|
||||
OnMaskDrag();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (m_ScratchType == EventScratchTicketScratchType.TypeInvalid || m_ScratchType == EventScratchTicketScratchType.TypeTemporary) return;
|
||||
if (m_BrushRoot.activeInHierarchy == false || m_Brush.gameObject.activeSelf == false) return;
|
||||
|
||||
if (m_CumulativeFrame > m_CDFrame)
|
||||
{
|
||||
m_CumulativeFrame = 1;
|
||||
m_MaskIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_CumulativeFrame;
|
||||
}
|
||||
|
||||
int count = m_MaskList.Count;
|
||||
int step = Mathf.CeilToInt((float)count / m_CDFrame);
|
||||
int endIndex = m_MaskIndex + step;
|
||||
|
||||
while (m_MaskIndex < count && m_MaskIndex < endIndex)
|
||||
{
|
||||
m_MaskList[m_MaskIndex].UpdateTempTexture();
|
||||
++m_MaskIndex;
|
||||
}
|
||||
|
||||
bool flag = true;
|
||||
foreach (var mask in m_MaskList)
|
||||
{
|
||||
if (!mask.IsRevealed())
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
//Debug.LogError("--- all ok");
|
||||
FishingScratchTicketAct.Publish(new EventScratchTicketRevealedAllData
|
||||
{
|
||||
ScratchType = m_ScratchType
|
||||
});
|
||||
m_ScratchType = EventScratchTicketScratchType.TypeTemporary;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d76a92f177c3b424aa14c040bfd5b8f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public abstract class ScratchCardMask : MonoBehaviour
|
||||
{
|
||||
//public Action<ScratchCardMask, float, bool> RevealProgressChanged;
|
||||
|
||||
public bool IsRevealed()
|
||||
{
|
||||
if (m_Threshold <= 0f) return true;
|
||||
return GetRevealProgress() >= m_Threshold;
|
||||
}
|
||||
public void SetThreshold(float threshold)
|
||||
{
|
||||
m_Threshold = threshold;
|
||||
}
|
||||
|
||||
[Header("Mask")]
|
||||
[Range(0f, 1.0f)]
|
||||
[SerializeField] protected float m_Threshold = 0.75f;
|
||||
[SerializeField] protected float m_AlphaThreshold = 0.5f;
|
||||
|
||||
public abstract float GetRevealProgress();
|
||||
|
||||
//protected void OnRevealProgressChanged()
|
||||
//{
|
||||
// float progress = 0f;
|
||||
// bool isRevealed = false;
|
||||
|
||||
// if (m_Threshold <= 0)
|
||||
// {
|
||||
// isRevealed = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// progress = GetRevealProgress();
|
||||
// isRevealed = progress >= m_Threshold;
|
||||
// }
|
||||
|
||||
// //RevealProgressChanged?.Invoke(this, progress, isRevealed);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad3f7edb405dd0a479a0fb223cc7ede7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,348 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64dbd9ff05166e44bbf1f72c86c717c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
101
Assets/Scripts/UI/ScratchTicket/ScratchCard/ScratchCardUtils.cs
Normal file
101
Assets/Scripts/UI/ScratchTicket/ScratchCard/ScratchCardUtils.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace game
|
||||
{
|
||||
public class ScratchCardUtils
|
||||
{
|
||||
public static void UpdateTexture2D(Texture2D texture2D, RenderTexture renderTexture, int width, int height)
|
||||
{
|
||||
RenderTexture tmp = RenderTexture.active;
|
||||
RenderTexture.active = renderTexture;
|
||||
texture2D.ReadPixels(new Rect(0, 0, width, height), 0, 0);
|
||||
RenderTexture.active = tmp;
|
||||
texture2D.Apply();
|
||||
}
|
||||
|
||||
public static Texture2D GetReadableCopy(RenderTexture renderTexture, TextureFormat format = TextureFormat.ARGB32, bool mipMaps = false, int width = 0, int height = 0)
|
||||
{
|
||||
var newTexture = default(Texture2D);
|
||||
|
||||
if (renderTexture != null)
|
||||
{
|
||||
if (width <= 0)
|
||||
{
|
||||
width = renderTexture.width;
|
||||
}
|
||||
|
||||
if (height <= 0)
|
||||
{
|
||||
height = renderTexture.height;
|
||||
}
|
||||
|
||||
if (CanReadPixels(format) == true)
|
||||
{
|
||||
newTexture = new Texture2D(width, height, format, mipMaps, false);
|
||||
|
||||
var tmp = RenderTexture.active;
|
||||
RenderTexture.active = renderTexture;
|
||||
newTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
|
||||
RenderTexture.active = tmp;
|
||||
|
||||
newTexture.Apply();
|
||||
}
|
||||
}
|
||||
|
||||
return newTexture;
|
||||
}
|
||||
|
||||
public static RenderTexture ReleaseRenderTexture(RenderTexture renderTexture)
|
||||
{
|
||||
return ReleaseTemporary(renderTexture);
|
||||
}
|
||||
|
||||
public static RenderTexture ReleaseTemporary(RenderTexture renderTexture)
|
||||
{
|
||||
if (renderTexture != null)
|
||||
{
|
||||
renderTexture.DiscardContents();
|
||||
|
||||
RenderTexture.ReleaseTemporary(renderTexture);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool CanReadPixels(TextureFormat format)
|
||||
{
|
||||
if (format == TextureFormat.RGBA32 || format == TextureFormat.ARGB32 || format == TextureFormat.RGB24 || format == TextureFormat.RGBAFloat || format == TextureFormat.RGBAHalf)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static RenderTexture GetRenderTexture(RenderTextureDescriptor desc, bool sRGB)
|
||||
{
|
||||
desc.sRGB = sRGB;
|
||||
|
||||
return GetTemporary(desc, "ScratchCardUtils GetRenderTexture");
|
||||
}
|
||||
|
||||
public static RenderTexture GetTemporary(RenderTextureDescriptor desc, string title)
|
||||
{
|
||||
var renderTexture = RenderTexture.GetTemporary(desc);
|
||||
|
||||
// TODO: For some reason RenderTexture.GetTemporary ignores the useMipMap flag?!
|
||||
if (renderTexture.useMipMap != desc.useMipMap)
|
||||
{
|
||||
renderTexture.Release();
|
||||
|
||||
renderTexture.descriptor = desc;
|
||||
|
||||
renderTexture.Create();
|
||||
}
|
||||
|
||||
return renderTexture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2690d82f025dba34d90f948f4b59367b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user