备份CatanBuilding瘦身独立工程

This commit is contained in:
JSD\13999
2026-05-26 16:15:54 +08:00
commit 2d0e6a61b7
12001 changed files with 2431925 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: defa652e288f2404b9b6cf9a48c44ad9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
using asap.core;
using cfg;
using GameCore;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
namespace game
{
public class EventScratchTicketChainPackData : IChainPackData
{
private const int SlotCount = 6;
private List<int> ChainList { get; set; }
private Pack[] Packs { get; set; }
public bool IsEndGame => ChainProgress > ChainList.Count - SlotCount;
public int ChainListCount => ChainList.Count;
private int m_ChainProgress = 0;
public int ChainProgress
{
set
{
EventScratchTicketDataManager dataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
m_ChainProgress = value;
dataManager.SetChainProgress(m_ChainProgress);
}
get
{
EventScratchTicketDataManager dataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
m_ChainProgress = dataManager.GetChainProgress();
return m_ChainProgress;
}
}
//public int ChainProgress { get; set; }
public int EventId { get; set; }
private DateTime ExpireTime { get; set; }
public TimeSpan RemainingTime => ExpireTime - ZZTimeHelper.UtcNow();
public bool IsChainPackDepleted => ChainProgress >= ChainListCount;
public bool DoNeedPackRedPoint
{
get
{
if (!IsChainPackDepleted && ChainProgress < ChainListCount)
return Packs[ChainProgress].IAPID == 0;
return false;
}
}
public string RedPointKey => RedPointName.Home_ScratchTicket + ".pack";
public EventScratchTicketChainPackData(List<int> chainList, DateTime expireTime, Pack[] packs, int eventId, int chainProgress)
{
ChainList = chainList;
ChainProgress = chainProgress;
EventId = eventId;
ExpireTime = expireTime;
Packs = packs;
}
public Pack GetChainPackByChainProgress(int chainProgress)
{
// Debug.Log($"[EventBreak] chainProgress: {chainProgress}");
return Packs[chainProgress];
}
public int GetChainProgressBySlotIdx(int slotIdx)
{
int res;
if (ChainProgress > ChainList.Count - SlotCount)
res = ChainList.Count - SlotCount + slotIdx;
else
res = ChainProgress + slotIdx;
Assert.IsTrue(res < ChainList.Count, $"Progress {res} out of range: {ChainListCount}");
// Debug.Log($"[EventBreak] slotIdx: {slotIdx}, chainProgress: {res}");
return res;
}
// Is this needed or what?
public List<int> GetTokenProgressRewardAfterAddingToken(int tokenAdded)
{
throw new NotImplementedException();
}
public void UploadData()
{
EventScratchTicketDataManager dataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
dataManager.ScratchTicketData.ChainPackProgress = ChainProgress;
dataManager.SyncData();
}
public void OnBuySuccess()
{
ChainProgress++;
UploadData();
}
public List<ItemData> GetItemsByPackDropId(int dropId)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 06183f569011c7a42a7f7d0dcc6b2d59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,236 @@
using GameCore;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace game
{
[RequireComponent(typeof(PolygonCollider2D))]
[RequireComponent(typeof(Image))]
public class EditablePolygon : MonoBehaviour
{
public Color polygonColor = new Color(0.5f, 0.5f, 1f, 0.5f);
public Vector2[] points = new Vector2[]
{
new Vector2(0, 0),
new Vector2(100, 50),
new Vector2(50, 100),
new Vector2(-50, 50)
};
private PolygonCollider2D polygonCollider;
private Image image;
void OnValidate()
{
UpdatePolygon();
}
void Awake()
{
UpdatePolygon();
}
public void UpdatePolygon()
{
if (polygonCollider == null) polygonCollider = GetComponent<PolygonCollider2D>();
if (image == null) image = GetComponent<Image>();
polygonCollider.points = points;
image.color = polygonColor;
}
public bool IsDown()
{
if (EventSystem.current == null)
{
return true;
}
PointerEventData pointerEventData = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerEventData, results);
if (results.Count > 0 && results[0].gameObject == gameObject)
{
return true;
}
return false;
}
public bool ContainsPoint(Vector2 position)
{
if (!IsDown())
{
return false;
}
RectTransformUtility.ScreenPointToLocalPointInRectangle(
transform as RectTransform,
position,
UIManager.Instance.UICanvas.worldCamera,
out Vector2 localPoint);
//bool flag = polygonCollider.OverlapPoint(localPoint);
//if (IsPointInPolygon(localPoint, polygonCollider.points))
//{
// Debug.LogError("点在多边形内");
//}
//else
//{
// Debug.LogError("点不在多边形内");
//}
return IsPointInPolygon(localPoint, points);
}
bool IsPointInPolygon(Vector2 point, Vector2[] polygon)
{
int polygonLength = polygon.Length;
bool inside = false;
// 从点向右发射水平射线
for (int i = 0, j = polygonLength - 1; i < polygonLength; j = i++)
{
Vector2 pi = polygon[i];
Vector2 pj = polygon[j];
// 检查点是否在顶点上
if (Mathf.Approximately(point.x, pi.x) && Mathf.Approximately(point.y, pi.y))
return true;
// 检查边是否与射线相交
if (((pi.y > point.y) != (pj.y > point.y)) &&
(point.x < (pj.x - pi.x) * (point.y - pi.y) / (pj.y - pi.y) + pi.x))
{
inside = !inside;
}
}
return inside;
}
}
}
#if UNITY_EDITOR
namespace game
{
using UnityEditor;
[CustomEditor(typeof(EditablePolygon))]
public class EditablePolygonEditor : Editor
{
private EditablePolygon polygon;
private SerializedProperty pointsProperty;
private SerializedProperty colorProperty;
private const float handleSize = 10f;
private int selectedIndex = -1;
void OnEnable()
{
polygon = (EditablePolygon)target;
pointsProperty = serializedObject.FindProperty("points");
colorProperty = serializedObject.FindProperty("polygonColor");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(colorProperty);
EditorGUILayout.LabelField("多边形顶点", EditorStyles.boldLabel);
for (int i = 0; i < pointsProperty.arraySize; i++)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(pointsProperty.GetArrayElementAtIndex(i),
new GUIContent("顶点 " + i));
if (GUILayout.Button("删除", GUILayout.Width(50)))
{
pointsProperty.DeleteArrayElementAtIndex(i);
serializedObject.ApplyModifiedProperties();
polygon.UpdatePolygon();
return;
}
EditorGUILayout.EndHorizontal();
}
if (GUILayout.Button("添加顶点"))
{
pointsProperty.arraySize++;
serializedObject.ApplyModifiedProperties();
polygon.UpdatePolygon();
}
serializedObject.ApplyModifiedProperties();
}
void OnSceneGUI()
{
RectTransform rectTransform = polygon.GetComponent<RectTransform>();
for (int i = 0; i < polygon.points.Length; i++)
{
Vector2 point = polygon.points[i];
Vector3 worldPoint = rectTransform.TransformPoint(point);
Handles.color = i == selectedIndex ? Color.red : Color.green;
// 绘制可拖拽的handle
EditorGUI.BeginChangeCheck();
var fmh_147_21_638823244657839550 = Quaternion.identity; Vector3 newWorldPoint = Handles.FreeMoveHandle(
worldPoint,
handleSize,
Vector3.zero,
Handles.CircleHandleCap);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(polygon, "Move Polygon Point");
polygon.points[i] = rectTransform.InverseTransformPoint(newWorldPoint);
polygon.UpdatePolygon();
}
// 检查点击选择
if (Event.current.type == EventType.MouseDown &&
Event.current.button == 0 &&
Vector2.Distance(HandleUtility.WorldToGUIPoint(worldPoint),
Event.current.mousePosition) < handleSize)
{
selectedIndex = i;
Event.current.Use();
}
}
// 绘制多边形线框
Handles.color = polygon.polygonColor;
Vector3[] worldPoints = new Vector3[polygon.points.Length + 1];
for (int i = 0; i < polygon.points.Length; i++)
{
worldPoints[i] = rectTransform.TransformPoint(polygon.points[i]);
}
worldPoints[worldPoints.Length - 1] = worldPoints[0];
Handles.DrawPolyLine(worldPoints);
// 删除选中的顶点
if (selectedIndex != -1 && Event.current.type == EventType.KeyDown &&
Event.current.keyCode == KeyCode.Delete)
{
Undo.RecordObject(polygon, "Delete Polygon Point");
var newPoints = new Vector2[polygon.points.Length - 1];
for (int i = 0, j = 0; i < polygon.points.Length; i++)
{
if (i != selectedIndex) newPoints[j++] = polygon.points[i];
}
polygon.points = newPoints;
selectedIndex = -1;
polygon.UpdatePolygon();
Event.current.Use();
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f284c763bda1f684d95a2c04ad4d58b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,77 @@
using asap.core;
using cfg;
using GameCore;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
namespace game
{
public class EventScratchTicket2FestPackPanel : MonoBehaviour
{
[SerializeField]
private TMP_Text textTimer, textPriceLeft, textPriceRight, textCountLeft, textCountRight, textDiscount;
[SerializeField] private Button btnClose, btnBuyLeft, btnBuyRight;
private IAPItemList _iapLeft, _iapRight;
private PlayerItemData _playerItemData;
private DateTime _expireTime;
private TimeSpan RemainingTime => _expireTime - ZZTimeHelper.UtcNow();
private int _eventId;
private Pack _packLeft, _packRight;
public void Init(EventBreakNormalPackInfo info)
{
btnClose.onClick.AddListener(OnClickClose);
_eventId = info.EventId;
_packLeft = info.PackLeft;
_packRight = info.PackRight;
_expireTime = info.ExpireTime;
_playerItemData = GContext.container.Resolve<PlayerItemData>();
textTimer.text = ConvertTools.ConvertTime2(RemainingTime);
Observable.Interval(TimeSpan.FromSeconds(1.0f)).Subscribe(_ =>
{
textTimer.text = ConvertTools.ConvertTime2(RemainingTime);
if (RemainingTime.TotalSeconds <= 0) OnClickClose();
}).AddTo(this);
_playerItemData.ResolveIapId(_packLeft.IAPID, out _iapLeft, textPriceLeft);
_playerItemData.ResolveIapId(_packRight.IAPID, out _iapRight, textPriceRight);
btnBuyLeft.onClick.AddListener(() => _ = OnClickBuy(_packLeft.DropID, _iapLeft));
btnBuyRight.onClick.AddListener(() => _ = OnClickBuy(_packRight.DropID, _iapRight));
textCountLeft.text =
((int)_playerItemData.GetItemDataByDropId(_packLeft.DropID)[0].count).ToString();
textCountRight.text =
((int)_playerItemData.GetItemDataByDropId(_packRight.DropID)[0].count).ToString();
textDiscount.text = LocalizationMgr.GetFormatTextValue("UI_FishingShopPanel_2", GetDiscountNumber());
}
private int GetDiscountNumber()
{
float discount = _packRight.Rebate * 100;
return (int)discount;
}
private async System.Threading.Tasks.Task OnClickBuy(int dropId, IAPItemList iapItemList)
{
if (RemainingTime.TotalSeconds <= 0)
return;
bool res = await GContext.container.Resolve<PlayerShopData>().OnBuy(dropId,
new ShopBuyTypeData { type = ShopBuyType.EventPack, ID = _eventId }, iapItemList,
_playerItemData.GetItemDataByDropId(dropId));
if (res)
{
ShootingRangeAct.EventAggregator.Publish(new ShootingRangeAct.EventAmmoBought());
OnClickClose();
}
}
private void OnClickClose()
{
// RedPointManager.Instance.SetRedPointState(EventShootingRangeData.PackRedPointId, false);
UIManager.Instance.DestroyUI(gameObject.name);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c50907e3830c314d9996c8e4146aba8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
using asap.core;
using GameCore;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace game
{
public class EventScratchTicketInfoPopupPanel : BasePanel
{
Button btn_close;
#region UI
private async void OnBtnCloseClickListener()
{
EventScratchTicketDataManager dataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
await UIManager.Instance.ShowUI(dataManager.GetUIPanel());
UIManager.Instance.DestroyUI(dataManager.GetInfoPanel());
}
#endregion
#region
// Start is called before the first frame update
protected override void Start()
{
btn_close = transform.Find("btn_close").GetComponent<Button>();
btn_close.onClick.RemoveAllListeners();
btn_close.onClick.AddListener(OnBtnCloseClickListener);
base.Start();
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5689ae0c325fe264d992b8916b04616b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,917 @@
using asap.core;
using cfg;
using GameCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
namespace game
{
public class EventScratchTicketPanel : BasePanel
{
[Header("奖励设置")]
[SerializeField] private float m_ProgressBarSpeed = 0.5f;
[SerializeField] private float m_PauseTimeAfterProgressBarIsFull = 0.1f;
[SerializeField] private List<EventScratchTicketStampRewardView> m_StampRewardList;
[SerializeField] private GameObject m_RewardFlyPrefab;
[Header("brush设置")]
[SerializeField] private float m_Auto_Brush_Waiting_Time = 0.1f;
[Header("动画效果")]
[SerializeField] private string m_AnimScratchStart = "scratch_start";
[SerializeField] private float m_AnimScratchStartDurationTime = 0.3f;
[SerializeField] private string m_AnimScrachEnd = "scrach_end";
[SerializeField] private float m_AnimScrachEndDurationTime = 0.2f;
[SerializeField] private Animation m_AnimEmptyRewardAnim;
[SerializeField] private string m_AnimEmptyReward = "emoji_show";
[SerializeField] private float m_AnimEmptyRewardDurationTime = 0.5f;
[SerializeField] private string m_AnimMaskShow = "mask_show";
[SerializeField] private string m_AnimMaskDisappear = "mask_disappear";
[SerializeField] private float m_AnimMaskWaitingTime = 0.3f;
[Header("位置")]
[SerializeField] private List<Transform> m_RewardFlyTransformList1 = new List<Transform>();
[SerializeField] private List<Transform> m_RewardFlyTransformList2 = new List<Transform>();
[SerializeField] private List<Transform> m_RewardFlyTransformList3 = new List<Transform>();
[SerializeField] private List<Transform> m_RewardFlyTransformList4 = new List<Transform>();
[SerializeField] private List<Transform> m_RewardFlyTransformList5 = new List<Transform>();
#region
public async void InitGuidance()
{
//var scratchMain = m_DataManager.GetCurrentEventScratchMain();
//GContext.container.Resolve<GuideDataCenter>().InspectTriggerGuide(scratchMain.UIPanel, curPanelName: gameObject.name);
if (m_DataManager.HasSaveKey(EventScratchTicketConfig.key_first_in)) return;
m_DataManager.SaveData(EventScratchTicketConfig.key_first_in, "ok");
await UIManager.Instance.ShowUI(m_DataManager.GetInfoPanel());
}
#endregion
#region
private void StartScratch1()
{
brush_coin2.gameObject.SetActive(true);
FishingScratchTicketAct.Publish(new EventScratchTicketChangeScratchTypeData()
{
ScratchType = EventScratchTicketScratchType.TypeScratch1
});
}
private int m_Scratch5MaxNum = 5;
private int m_Scratch5CumulativeNum = 0;
private void StartScratch5()
{
brush_coin2.gameObject.SetActive(true);
if (m_Scratch5CumulativeNum >= m_Scratch5MaxNum)
{
// 5连刮奖励
FishingScratchTicketAct.Publish(new EventScratchTicketStampRewardFlyData()
{
ScratchType = EventScratchTicketScratchType.TypeScratch5
});
}
else
{
// 更换卡片
m_DataManager.UpdateLuckyValueAndWeight();
FishingScratchTicketAct.Publish(new EventScratchTicketUpdateEventScratchCardData());
FishingScratchTicketAct.Publish(new EventScratchTicketChangeScratchTypeData()
{
ScratchType = EventScratchTicketScratchType.TypeScratch5
});
StartCoroutine(StartAutoBrush());
++m_Scratch5CumulativeNum;
}
}
private IEnumerator StartAutoBrush()
{
yield return new WaitForSeconds(m_Auto_Brush_Waiting_Time);
int count = brush_coin2_anim_list.Count;
int index = UnityEngine.Random.Range(0, count);
string anim = brush_coin2_anim_list[index];
brush_coin2.Play(brush_coin2_anim_list[index]);
Debug.LogWarning("--- 当前五连刮使用动画:" + anim);
}
#endregion
#region & &
private async void GotoChainPack()
{
EventScratchTicketChainPackData chainPackData = m_DataManager.GetChainPackData();
if (chainPackData == null) return;
if (chainPackData.IsChainPackDepleted)
{
// 普通礼包
GameObject go = await UIManager.Instance.ShowUI(m_DataManager.GetPackPanel());
var normalPackPanel = go.GetComponent<EventScratchTicket2FestPackPanel>();
normalPackPanel.Init(m_DataManager.GetNormalPackData());
}
else
{
// 链式礼包
GameObject go = await UIManager.Instance.ShowUI(m_DataManager.GetChainPackPanel());
var chainPackPanel = go.GetComponent<ChainPackPanel>();
chainPackPanel.Init(chainPackData);
}
}
private void CheckForStampReward(EventScratchTicketScratchType scratchType)
{
if (m_DataManager.GetStampRewardNum() > 0)
{
HandleStampRewardList(scratchType);
}
else
{
FishingScratchTicketAct.Publish(new EventScratchTicketPanelPlayEndAnimData()
{
ScratchType = scratchType
});
}
}
private async void HandleStampRewardList(EventScratchTicketScratchType scratchType)
{
if (m_DataManager.GetStampRewardNum() > 0)
{
PlayerItemData playerItemData = GContext.container.Resolve<PlayerItemData>();
EventScratchCard card = m_DataManager.GetFirstStampReward();
if (card != null)
{
ItemData rewardItem = playerItemData.GetItemDataOne(card.DropReward);
m_DataManager.RemoveFirstStampReward();
GameObject go = await UIManager.Instance.ShowUI(m_DataManager.GetRewardPanel());
var rewardPopupPanel = go.GetComponent<EventScratchTicketRewardPopupPanel>();
rewardPopupPanel.Init(rewardItem, card, () =>
{
HandleStampRewardList(scratchType);
});
}
}
else
{
await HandleReward(scratchType);
}
}
#endregion
#region
private IEnumerator ScratchStartAnim(Action action)
{
m_animation.Play(m_AnimScratchStart);
yield return new WaitForSeconds(m_AnimScratchStartDurationTime);
if (action != null)
{
action.Invoke();
}
}
private IEnumerator ScratchEndAnim(EventScratchTicketScratchType scratchType, Action<EventScratchTicketScratchType> action)
{
m_animation.Play(m_AnimScrachEnd);
yield return new WaitForSeconds(m_AnimScrachEndDurationTime);
FishingScratchTicketAct.Publish(new EventScratchTicketChangeScratchTypeData()
{
ScratchType = EventScratchTicketScratchType.TypeInvalid
});
if (action != null)
{
action.Invoke(scratchType);
}
}
private void StopScratch()
{
brush_coin2.gameObject.SetActive(false);
FishingScratchTicketAct.Publish(new EventScratchTicketChangeScratchTypeData()
{
ScratchType = EventScratchTicketScratchType.TypeTemporary
});
}
private List<Transform> GetRewardFlyTransformList(int count)
{
switch (count)
{
case 5:
return m_RewardFlyTransformList5;
case 4:
return m_RewardFlyTransformList4;
case 3:
return m_RewardFlyTransformList3;
case 2:
return m_RewardFlyTransformList2;
case 1:
return m_RewardFlyTransformList1;
default:
return m_RewardFlyTransformList5;
}
}
private async Task PlayRewardFlyAnim(EventScratchTicketStampRewardFlyData data)
{
if (data.ScratchType == EventScratchTicketScratchType.TypeScratch1)
{
await PlayStampRewardFlyAnimInTypeScratch1(data);
await HandleReward(data.ScratchType);
}
else if (data.ScratchType == EventScratchTicketScratchType.TypeScratch5)
{
FishingScratchTicketAct.Publish(new EventScratchTicketStartStampRewardCountUpdateData());
//mask.gameObject.SetActive(true);
FishingScratchTicketAct.Publish(new EventScratchTicketStartMaskData());
var taskList = new List<Task>();
int count = m_DataManager.ScratchStampList.Count;
List<Transform> transformList = GetRewardFlyTransformList(count);
for (int i = 0; i < count; i++)
{
int cardID = m_DataManager.ScratchStampList[i];
EventScratchCard card = m_DataManager.GetEventScratchCard(cardID);
if (card.DropReward > 0)
{
taskList.Add(PlayStampRewardFlyAnimInTypeScratch5(data, card, transformList, i));
}
}
if (taskList.Count > 0)
{
await Task.WhenAll(taskList.ToArray());
}
m_DataManager.ClearScratchStampList();
//mask.gameObject.SetActive(false);
StopMask();
FishingScratchTicketAct.Publish(new EventScratchTicketStopStampRewardCountUpdateData());
await HandleReward(data.ScratchType);
}
}
private async Task HandleReward(EventScratchTicketScratchType scratchType)
{
int count = m_StampRewardList.Count;
var taskArr = new Task<bool>[count];
for (var i = 0; i < count; i++)
{
taskArr[i] = m_StampRewardList[i].CheckReward();
}
await Task.WhenAll(taskArr);
bool flag = false;
foreach (var task in taskArr)
{
if (task.Result)
{
flag = true;
break;
}
}
m_DataManager.SyncData();
if (flag)
{
CheckForStampReward(scratchType);
}
else
{
FishingScratchTicketAct.Publish(new EventScratchTicketPanelPlayEndAnimData()
{
ScratchType = scratchType
});
}
}
private async Task PlayStampRewardFlyAnimInTypeScratch1(EventScratchTicketStampRewardFlyData data)
{
FishingScratchTicketAct.Publish(new EventScratchTicketStartStampRewardCountUpdateData());
//mask.gameObject.SetActive(true);
FishingScratchTicketAct.Publish(new EventScratchTicketStartMaskData());
EventScratchCard scratchCard = m_DataManager.GetFirstScratchStamp();
EventScratchTicketStampRewardView stampRewardView = null;
foreach (var item in m_StampRewardList)
{
if (item.EventScratchQuality == scratchCard.Quality)
{
stampRewardView = item;
break;
}
}
if (stampRewardView == null)
{
Debug.LogError("--- PlayRewardFlyAnimStep 数据错误,找不到对应的 EventScratchTicketStampRewardView");
return;
}
Sprite icon = m_DataManager.SpriteAtlas.GetSprite(scratchCard.Icon);
Vector3 srcPosition = data.SrcPosition;
var targetImg = stampRewardView.GetFirstEmptyImage();
Vector3 destPosition = targetImg.rectTransform.position;
Vector3 localScale = data.LocalScale;
float iconSize = targetImg.rectTransform.rect.width;
int rewardNum = stampRewardView.RewardNum;
var recordData = m_DataManager.AddRecordData();
recordData.TicketID = scratchCard.ID;
recordData.SetScratchType(data.ScratchType);
recordData.TicketFinishID = ((rewardNum % scratchCard.Count) == 0) ? scratchCard.DropReward : 0;
CollectionItemFly collectionItemFly = new CollectionItemFly()
{
icon = m_DataManager.SpriteAtlas.GetSprite(scratchCard.Icon),
numStr = "",
sourcePos = data.SrcPosition,
destPos = destPosition,
scale = data.LocalScale,
isPlayOpen = true,
isPlayClose = true,
isDestinationRewardStash = false,
// isDestinationRewardStash = false,
targetIconSize = iconSize
};
//var rewardFly = m_RewardFlyList[0];
var rewardFly = Instantiate(m_RewardFlyPrefab, m_RewardFlyPrefab.transform.parent).GetComponent<RewardFly>();
rewardFly.gameObject.SetActive(true);
await rewardFly.ShowAsync(collectionItemFly);
Destroy(rewardFly.gameObject);
//mask.gameObject.SetActive(false);
StopMask();
targetImg.gameObject.SetActive(true);
m_DataManager.ClearScratchStampList();
FishingScratchTicketAct.Publish(new EventScratchTicketStopStampRewardCountUpdateData());
}
private async Task PlayStampRewardFlyAnimInTypeScratch5(EventScratchTicketStampRewardFlyData data, EventScratchCard scratchCard, List<Transform> transformList, int index)
{
EventScratchTicketStampRewardView stampRewardView = null;
foreach (var item in m_StampRewardList)
{
if (item.EventScratchQuality == scratchCard.Quality)
{
stampRewardView = item;
break;
}
}
if (stampRewardView == null)
{
Debug.LogError("--- PlayRewardFlyAnimStep 数据错误,找不到对应的 EventScratchTicketStampRewardView");
return;
}
Sprite icon = m_DataManager.SpriteAtlas.GetSprite(scratchCard.Icon);
Vector3 srcPosition = data.SrcPosition;
var targetImg = stampRewardView.GetFirstEmptyImage();
Vector3 destPosition = targetImg.rectTransform.position;
Vector3 localScale = data.LocalScale;
float iconSize = targetImg.rectTransform.rect.width;
var rewardFlyTransform = transformList[index];
int rewardNum = stampRewardView.RewardNum;
var recordData = m_DataManager.AddRecordData();
recordData.TicketID = scratchCard.ID;
recordData.SetScratchType(data.ScratchType);
recordData.TicketFinishID = ((rewardNum % scratchCard.Count) == 0) ? scratchCard.DropReward : 0;
CollectionItemFly collectionItemFly = new CollectionItemFly()
{
icon = m_DataManager.SpriteAtlas.GetSprite(scratchCard.Icon),
numStr = "",
sourcePos = rewardFlyTransform.position,
destPos = destPosition,
scale = rewardFlyTransform.localScale,
isPlayOpen = true,
isPlayClose = true,
isDestinationRewardStash = false,
// isDestinationRewardStash = false,
targetIconSize = iconSize
};
var rewardFly = Instantiate(m_RewardFlyPrefab, m_RewardFlyPrefab.transform.parent).GetComponent<RewardFly>();
rewardFly.gameObject.SetActive(true);
await rewardFly.ShowAsync(collectionItemFly);
Destroy(rewardFly.gameObject);
targetImg.gameObject.SetActive(true);
}
private IEnumerator PlayRewardEmptyAnim(EventScratchTicketRewardEmptyData data)
{
// 播放空奖动画
m_AnimEmptyRewardAnim.gameObject.SetActive(true);
m_AnimEmptyRewardAnim.Play(m_AnimEmptyReward);
yield return new WaitForSeconds(m_AnimEmptyRewardDurationTime);
m_AnimEmptyRewardAnim.gameObject.SetActive(false);
EventScratchCard scratchCard = m_DataManager.GetCurrentEventScratchCard();
var recordData = m_DataManager.AddRecordData();
recordData.TicketID = scratchCard.ID;
recordData.SetScratchType(data.ScratchType);
recordData.TicketFinishID = 0;
FishingScratchTicketAct.Publish(new EventScratchTicketOutData()
{
ScratchType = data.ScratchType
});
//if (data.ScratchType == EventScratchTicketScratchType.TypeScratch1)
//{
// FishingScratchTicketAct.Publish(new EventScratchTicketPanelPlayEndAnimData()
// {
// ScratchType = data.ScratchType
// });
//}
//else if (data.ScratchType == EventScratchTicketScratchType.TypeScratch5)
//{
// FishingScratchTicketAct.Publish(new EventScratchTicketPlayScratchType5());
//}
}
private IEnumerator StartMask()
{
mask.gameObject.SetActive(true);
mask.Play(m_AnimMaskShow);
yield return new WaitForSeconds(m_AnimMaskWaitingTime);
mask.Play(m_AnimMaskDisappear);
}
private void StopMask()
{
// 停止播放动画
mask.gameObject.SetActive(false);
}
#endregion
#region
private void InitEvent()
{
FishingScratchTicketAct.Subscribe<EventScratchTicketTokenUpdateData>(UpdateToken);
FishingScratchTicketAct.Subscribe<EventScratchTicketStampRewardFlyData>(OnStampRewardFlyEvent);
FishingScratchTicketAct.Subscribe<EventScratchTicketPanelPlayEndAnimData>(PlayScratchEndAnim);
FishingScratchTicketAct.Subscribe<EventScratchTicketRewardTaskUpdateData>(UpdateRewardTask);
FishingScratchTicketAct.Subscribe<EventScratchTicketPlayScratchType5>(PlayScratchType5);
FishingScratchTicketAct.Subscribe<EventScratchTicketRewardEmptyData>(OnRewardEmptyEvent);
FishingScratchTicketAct.Subscribe<EventScratchTicketRevealedAllData>(OnScratchCardRevealedAll);
FishingScratchTicketAct.Subscribe<EventScratchTicketStartMaskData>(OnStartMaskEvent);
// 监听关闭奖励面板
GContext.OnEvent<RewardPanelClose>().Subscribe(OnRewardPanelClose).AddTo(FishingScratchTicketAct.Disposables);
}
private void OnStartMaskEvent(EventScratchTicketStartMaskData data)
{
StartCoroutine(StartMask());
}
private void OnScratchCardRevealedAll(EventScratchTicketRevealedAllData data)
{
if (brush_coin2 == null) return;
brush_coin2.Stop();
brush_coin2.gameObject.SetActive(false);
}
private void OnRewardEmptyEvent(EventScratchTicketRewardEmptyData data)
{
this.StartCoroutine(PlayRewardEmptyAnim(data));
}
private void OnRewardPanelClose(RewardPanelClose data)
{
//FishingScratchTicketAct.Publish(new EventScratchTicketPanelPlayEndAnimData());
}
private void PlayScratchType5(EventScratchTicketPlayScratchType5 data)
{
StartScratch5();
}
private void PlayScratchEndAnim(EventScratchTicketPanelPlayEndAnimData data)
{
if (m_DataManager.ScratchTicketData.ConsumedToken > 0)
{
StartCoroutine(ScratchEndAnim(data.ScratchType, CheckTokenReward));
}
else
{
StartCoroutine(ScratchEndAnim(data.ScratchType, null));
}
StopScratch();
}
private void CheckTokenReward(EventScratchTicketScratchType scratchType)
{
// token 消费积分奖励
FishingScratchTicketAct.Publish(new EventScratchTicketRewardTaskUpdateData()
{
ScratchType = scratchType,
Token = m_DataManager.ScratchTicketData.ConsumedToken
});
}
private async void OnStampRewardFlyEvent(EventScratchTicketStampRewardFlyData data)
{
if (data == null) return;
await PlayRewardFlyAnim(data);
}
private void UpdateToken(EventScratchTicketTokenUpdateData data)
{
if (m_DataManager == null || token_text_num == null) return;
int token = m_DataManager.GetToken();
token_text_num.text = "" + token;
}
private async void UpdateRewardTask(EventScratchTicketRewardTaskUpdateData data)
{
if (m_DataManager == null) return;
PlayerItemData playerItemData = GContext.container.Resolve<PlayerItemData>();
EventScratchReward finalReward = m_DataManager.GetEventScratchFinalReward();
var finalDataItem = playerItemData.GetItemDataOne(finalReward.DropReward);
top_reward.SetData(finalDataItem, abbr: true);
if (data == null && m_DataManager.ScratchTicketData.ConsumedToken > 0)
{
data = new EventScratchTicketRewardTaskUpdateData()
{
ScratchType = EventScratchTicketScratchType.TypeInvalid,
Token = m_DataManager.ScratchTicketData.ConsumedToken
};
}
if (data == null)
{
EventScratchReward curReward = m_DataManager.GetEventScratchReward(m_DataManager.ScratchTicketData.EventScratchRewardTaskID);
var curDataItem = playerItemData.GetItemDataOne(curReward.DropReward);
reward.SetData(curDataItem, abbr: true);
img_bar.fillAmount = (float)m_DataManager.ScratchTicketData.RewardTaskConsumedToken / curReward.TokenRequired;
text_progress.text = m_DataManager.ScratchTicketData.RewardTaskConsumedToken + "/" + curReward.TokenRequired;
}
else
{
await StartUpdateProgressBar(data);
}
}
private Queue<EventScratchTicketRewardDisplayUpdateData> GetRewardDisplayUpdateDataQueue(EventScratchTicketRewardTaskUpdateData data)
{
Queue<EventScratchTicketRewardDisplayUpdateData> updateQueue = new Queue<EventScratchTicketRewardDisplayUpdateData>();
int fromToken = m_DataManager.ScratchTicketData.RewardTaskConsumedToken;
int targetToken = fromToken + data.Token;
int taskID = m_DataManager.ScratchTicketData.EventScratchRewardTaskID;
EventScratchReward curScratchReward = m_DataManager.GetEventScratchReward(taskID);
while (targetToken >= curScratchReward.TokenRequired)
{
EventScratchTicketRewardDisplayUpdateData rewardDisplayUpdateData = new EventScratchTicketRewardDisplayUpdateData();
rewardDisplayUpdateData.TaskID = taskID;
rewardDisplayUpdateData.Reward = m_DataManager.GetEventScratchReward(rewardDisplayUpdateData.TaskID);
rewardDisplayUpdateData.FromToken = fromToken;
rewardDisplayUpdateData.TargetToken = curScratchReward.TokenRequired;
rewardDisplayUpdateData.LevelToken = curScratchReward.TokenRequired;
rewardDisplayUpdateData.FromRatio = (float)rewardDisplayUpdateData.FromToken / rewardDisplayUpdateData.LevelToken;
rewardDisplayUpdateData.TargetRatio = (float)rewardDisplayUpdateData.TargetToken / rewardDisplayUpdateData.LevelToken;
updateQueue.Enqueue(rewardDisplayUpdateData);
fromToken = 0;
targetToken -= curScratchReward.TokenRequired;
taskID = curScratchReward.NextTask;
curScratchReward = m_DataManager.GetEventScratchReward(taskID);
}
{
EventScratchTicketRewardDisplayUpdateData rewardDisplayUpdateData = new EventScratchTicketRewardDisplayUpdateData();
rewardDisplayUpdateData.TaskID = taskID;
rewardDisplayUpdateData.Reward = m_DataManager.GetEventScratchReward(rewardDisplayUpdateData.TaskID);
rewardDisplayUpdateData.FromToken = fromToken;
rewardDisplayUpdateData.TargetToken = targetToken;
rewardDisplayUpdateData.LevelToken = curScratchReward.TokenRequired;
rewardDisplayUpdateData.FromRatio = (float)rewardDisplayUpdateData.FromToken / rewardDisplayUpdateData.LevelToken;
rewardDisplayUpdateData.TargetRatio = (float)rewardDisplayUpdateData.TargetToken / rewardDisplayUpdateData.LevelToken;
updateQueue.Enqueue(rewardDisplayUpdateData);
}
return updateQueue;
}
public async Task StartUpdateProgressBar(EventScratchTicketRewardTaskUpdateData data)
{
Queue<EventScratchTicketRewardDisplayUpdateData> updateQueue = GetRewardDisplayUpdateDataQueue(data);
bool syncData = updateQueue.Count > 0;
PlayerItemData playerItemData = GContext.container.Resolve<PlayerItemData>();
EventScratchReward curReward = null;
int finalToken = 0;
while (updateQueue.Count > 0)
{
var item = updateQueue.Dequeue();
int fromToken = item.FromToken;
int targetToken = item.TargetToken;
int levelToken = item.LevelToken;
float fromRatio = item.FromRatio;
float targetRatio = item.TargetRatio;
finalToken = targetToken;
curReward = item.Reward;
var curDataItem = playerItemData.GetItemDataOne(curReward.DropReward);
reward.SetData(curDataItem, abbr: true);
text_progress.text = fromToken + "/" + levelToken;
img_bar.fillAmount = fromRatio;
await Awaiters.NextFrame;
while (fromRatio < targetRatio)
{
fromRatio += m_ProgressBarSpeed * Time.deltaTime;
fromToken = (int)(levelToken * fromRatio);
text_progress.text = fromToken + "/" + levelToken;
img_bar.fillAmount = fromRatio;
await Awaiters.NextFrame;
}
text_progress.text = targetToken + "/" + levelToken;
img_bar.fillAmount = targetRatio;
if (targetToken >= levelToken && curReward.DropReward > 0)
{
await HandleTokenReward(curReward.DropReward);
}
if (fromToken >= 0f)
{
await Awaiters.Seconds(m_PauseTimeAfterProgressBarIsFull);
}
else
{
await Awaiters.NextFrame;
}
}
m_DataManager.RecordStatisticalData();
m_DataManager.ScratchTicketData.EventScratchRewardTaskID = curReward.TaskID;
m_DataManager.ScratchTicketData.ConsumedToken = 0;
m_DataManager.ScratchTicketData.RewardTaskConsumedToken = finalToken;
m_DataManager.SyncData();
m_DataManager.ClearRecordList();
}
private async Task HandleTokenReward(int rewardId)
{
//mask.gameObject.SetActive(true);
ItemData itemData = GContext.container.Resolve<PlayerItemData>().GetItemDataOne(rewardId);
Vector3 srcPosition = reward.transform.position;
//var targetImg = stampRewardView.GetFirstEmptyImage();
Vector3 destPosition = m_BtnPack.transform.position;
float iconSize = m_BtnPack.Icon.rect.width;
CollectionItemFly collectionItemFly = new CollectionItemFly()
{
itemID = itemData.id,
numStr = "",
sourcePos = srcPosition,
destPos = destPosition,
scale = reward.icon.rectTransform.localScale,
isPlayOpen = true,
isPlayClose = true,
isDestinationRewardStash = false,
// isDestinationRewardStash = false,
targetIconSize = iconSize
};
var rewardFly = Instantiate(m_RewardFlyPrefab, m_RewardFlyPrefab.transform.parent).GetComponent<RewardFly>();
rewardFly.gameObject.SetActive(true);
await rewardFly.ShowAsync(collectionItemFly);
Destroy(rewardFly.gameObject);
//mask.gameObject.SetActive(false);
List<ItemData> rewardList = new List<ItemData>();
rewardList.Add(itemData);
// GContext.container.Resolve<PlayerItemData>().AddItem(rewardList);
GContext.Publish(new DeferredRewardStashService.EventStashItems { Items = rewardList });
}
#endregion
#region UI
// animation
private Animation m_animation;
// questionmark
private Button btn_questionmark;
private TMP_Text text_time;
// 关闭按钮
private Button btn_close;
// icon_ticket
private TMP_Text token_text_num;
private Button icon_ticket;
// mask
private Image click_mask;
private Animation mask;
// reward_fly
//private List<RewardFly> m_RewardFlyList = new List<RewardFly>();
// scratch 1 & scratch 5
private Button btn_scratch_1;
private Button btn_scratch_5;
// brush
private Image brush_coin1;
private Animation brush_coin2;
private List<string> brush_coin2_anim_list = new List<string>();
// bar
private Animation anim_bar;
private RewardItemNew top_reward;
private Image img_bar;
private RewardItemNew reward;
private TMP_Text text_progress;
// pack
private DeferredRewardStashButton m_BtnPack;
private void InitUI()
{
// animation
m_animation = transform.GetComponent<Animation>();
// btn_questionmark
btn_questionmark = transform.Find("root/title/btn_questionmark").GetComponent<Button>();
btn_questionmark.onClick.AddListener(OnBtnQuestionmarkClickListener);
text_time = transform.Find("root/title/text_time").GetComponent<TMP_Text>();
text_time.text = LocalizationMgr.GetFormatTextValue("UI_COMMON_end", ConvertTools.ConvertTime2(m_DataManager.RemainingTime));
Observable.Interval(TimeSpan.FromSeconds(1.0f)).Subscribe(_ =>
{
text_time.text = LocalizationMgr.GetFormatTextValue("UI_COMMON_end", ConvertTools.ConvertTime2(m_DataManager.RemainingTime));
}).AddTo(this);
// 关闭按钮
btn_close = transform.Find("btn_close").GetComponent<Button>();
btn_close.onClick.AddListener(OnBtnCloseClickListener);
// icon_ticket
icon_ticket = transform.Find("root/icon_ticket").GetComponent<Button>();
icon_ticket.onClick.AddListener(OnBtnIconTicketClickListener);
token_text_num = icon_ticket.transform.Find("text_num").GetComponent<TMP_Text>();
// mask
click_mask = transform.Find("click_mask").GetComponent<Image>();
click_mask.gameObject.SetActive(false);
mask = transform.Find("mask").GetComponent<Animation>();
mask.gameObject.SetActive(false);
// reward_fly
//for (int i = 1; i < 6; ++i)
//{
// var rewardFly = transform.Find($"RewardFly{i}").GetComponent<RewardFly>();
// rewardFly.gameObject.SetActive(false);
// m_RewardFlyList.Add(rewardFly);
//}
// scratch 1 & scratch 5
btn_scratch_1 = transform.Find("root/btn_scratch_1/btn_green").GetComponent<Button>();
btn_scratch_1.onClick.AddListener(OnBtnScratch1ClickListener);
btn_scratch_5 = transform.Find("root/btn_scratch_5/btn_green").GetComponent<Button>();
btn_scratch_5.onClick.AddListener(OnBtnScratch5ClickListener);
// brush
brush_coin1 = transform.Find("root/coin1").GetComponent<Image>();
brush_coin1.gameObject.SetActive(true);
brush_coin2 = transform.Find("root/coin2").GetComponent<Animation>();
brush_coin2.gameObject.SetActive(false);
brush_coin2_anim_list.Clear();
foreach (AnimationState animation in brush_coin2)
{
brush_coin2_anim_list.Add(animation.name);
}
// bar
anim_bar = transform.Find("root/bar").GetComponent<Animation>();
top_reward = anim_bar.transform.Find("top_reward").GetComponent<RewardItemNew>();
img_bar = anim_bar.transform.Find("bar").GetComponent<Image>();
reward = anim_bar.transform.Find("reward").GetComponent<RewardItemNew>();
text_progress = anim_bar.transform.Find("text_progress").GetComponent<TMP_Text>();
// pack
m_BtnPack = transform.Find("root/btn_pack").GetComponent<DeferredRewardStashButton>();
}
private void OnBtnScratch1ClickListener()
{
// 更换卡片
m_DataManager.GetNextScratchTicketData();
FishingScratchTicketAct.Publish(new EventScratchTicketUpdateEventScratchCardData());
m_DataManager.SyncTempRecordData();
bool flag = m_DataManager.ConsumeTokens(1);
if (flag)
{
StartCoroutine(ScratchStartAnim(StartScratch1));
}
else
{
GotoChainPack();
}
}
private void OnBtnScratch5ClickListener()
{
// 更换卡片
m_DataManager.GetNextScratchTicketData();
FishingScratchTicketAct.Publish(new EventScratchTicketUpdateEventScratchCardData());
m_DataManager.SyncTempRecordData();
m_Scratch5CumulativeNum = 0;
bool flag = m_DataManager.ConsumeTokens(5);
if (flag)
{
StartCoroutine(ScratchStartAnim(StartScratch5));
}
else
{
GotoChainPack();
}
}
private async void OnBtnQuestionmarkClickListener()
{
await UIManager.Instance.ShowUI(m_DataManager.GetInfoPanel());
//UIManager.Instance.HideUI(m_DataManager.GetUIPanel());
}
public void OnBtnCloseClickListener()
{
// 关闭当前Act
GContext.Publish(new UnloadActToNextAct());
}
private void OnBtnIconTicketClickListener()
{
GotoChainPack();
}
public void RefreshData()
{
UpdateToken(null);
UpdateRewardTask(null);
}
#endregion
#region
private EventScratchTicketDataManager m_DataManager;
protected override void Start()
{
base.Start();
m_DataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
InitUI();
InitEvent();
RefreshData();
InitGuidance();
}
protected override void OnDestroy()
{
base.OnDestroy();
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d384948f13c6efa459676a4ded5b3704
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,43 @@
using asap.core;
using cfg;
using GameCore;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
namespace game
{
public class EventScratchTicketRewardPopupPanel : MonoBehaviour
{
[SerializeField] private RewardItemNew reward;
//[SerializeField] private GameObject[] gemBanners;
[SerializeField] private Image banner;
[SerializeField] private Button btnClaim;
private Action _action;
public void Init(ItemData rewardItem, EventScratchCard eventScratchCard, Action claimMark = null)
{
var dataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
// Debug.Log($"[EventBreak] Init!!!!!!!!!!", this);
reward.SetData(rewardItem, abbr: true);
//for (int i = 0; i < gemBanners.Length; i++)
// gemBanners[i].SetActive(i == tunnelIdx);
banner.sprite = dataManager.SpriteAtlas.GetSprite(eventScratchCard.RewardIcon);
btnClaim.onClick.AddListener(OnClaim);
_action = claimMark;
}
private void OnClaim()
{
// Debug.Log($"[EventBreak] Claim!!!!!!!!!!", this);
var dataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
UIManager.Instance.DestroyUI(dataManager.GetRewardPanel());
_action?.Invoke();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 092b9949be49496429c1164759a9dde2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,306 @@
using asap.core;
using cfg;
using GameCore;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
namespace game
{
public class EventScratchTicketStampRewardView : MonoBehaviour
{
[Header("印花设置")]
[SerializeField] private int m_EventScratchQuality = 1;
public int EventScratchQuality { get => m_EventScratchQuality; }
[Header("UI设置")]
[SerializeField] private List<Image> m_GrayStampList = new List<Image>();
[SerializeField] private List<Image> m_LightStampList = new List<Image>();
[Header("奖励设置")]
[SerializeField] private RewardItemNew m_Reward;
[Header("动画设置")]
[SerializeField] private Animation m_Animation;
[SerializeField] private float m_AnimWaitingForFullTime = 0.1f;
[SerializeField] private string m_AnimRewardRefresh = "reward_refresh";
[SerializeField] private float m_AnimRewardRefreshDurationTime = 0.29f;
[SerializeField] private string m_AnimRewardOut = "reward_out";
[SerializeField] private float m_AnimRewardOutDurationTime = 0.37f;
[SerializeField] private string m_AnimRewardFull = "reward_full";
[SerializeField] private float m_AnimRewardFullDurationTime = 0.45f;
#region
private static object o = new object();
public Image GetFirstEmptyImage()
{
lock (o)
{
if (m_IsCounting)
{
m_RewardNum++;
}
if (m_EmptyTargetIndex >= m_LightStampList.Count)
{
m_EmptyTargetIndex = m_LightStampList.Count - 1;
}
}
return m_LightStampList[m_EmptyTargetIndex++];
}
public void ResetLightStampList()
{
foreach (var item in m_LightStampList)
{
item.gameObject.SetActive(false);
}
}
private EventScratchCard m_ScratchCard = null;
public EventScratchCard GetEventScratchCard()
{
return m_ScratchCard;
}
public async Task<bool> CheckReward()
{
if (m_IsFull)
{
m_Animation.Play(m_AnimRewardOut);
await Awaiters.Seconds(m_AnimRewardOutDurationTime);
PlayLightStampFlash();
m_Animation.Play(m_AnimRewardRefresh);
await Awaiters.Seconds(m_AnimRewardRefreshDurationTime);
}
if (m_RewardNum < m_ScratchCard.Count)
{
PlayLightStampFlash();
m_IsFull = false;
return false;
}
PlayLightStampFlash();
m_DataManager.AddStampReward(m_ScratchCard.ID);
await Awaiters.Seconds(m_AnimWaitingForFullTime);
m_Animation.Play(m_AnimRewardFull);
await Awaiters.Seconds(m_AnimRewardFullDurationTime);
ItemData itemData = GContext.container.Resolve<PlayerItemData>().GetItemDataOne(m_ScratchCard.DropReward);
List<ItemData> rewardList = new List<ItemData>();
rewardList.Add(itemData);
// GContext.container.Resolve<PlayerItemData>().AddItem(rewardList);
GContext.Publish(new DeferredRewardStashService.EventStashItems { Items = rewardList });
ResetRewardNum();
m_IsFull = true;
return true;
}
public void ResetRewardNum()
{
m_RewardNum -= m_ScratchCard.Count;
m_EmptyFromIndex = 0;
m_EmptyTargetIndex = m_RewardNum;
}
public void SyncStampData()
{
int num = 0;
foreach (var item in m_LightStampList)
{
if (item.gameObject.activeSelf)
{
num++;
}
}
if (m_DataManager.ScratchTicketData.StampRewardDict.ContainsKey(m_EventScratchQuality))
{
var data = m_DataManager.ScratchTicketData.StampRewardDict[m_EventScratchQuality];
data.EventScratchCardID = m_ScratchCard.ID;
data.Count = num;
}
else
{
m_DataManager.ScratchTicketData.StampRewardDict[m_EventScratchQuality] = new EventScratchTicketOwnedStampRewardData()
{
EventScratchCardID = m_ScratchCard.ID,
Count = num
};
}
}
#endregion
#region
private void PlayLightStampFlash()
{
int count = m_LightStampList.Count;
for (int i = 0; i < count; ++i)
{
var item = m_LightStampList[i];
if (i < m_EmptyTargetIndex)
{
item.gameObject.SetActive(true);
}
else
{
item.gameObject.SetActive(false);
}
}
SyncStampData();
}
#endregion
#region
private void InitEvent()
{
FishingScratchTicketAct.Subscribe<EventScratchTicketStampRewardUpdateData>(UpdateStampReward);
FishingScratchTicketAct.Subscribe<EventScratchTicketStartStampRewardCountUpdateData>(StartStampRewardCount);
FishingScratchTicketAct.Subscribe<EventScratchTicketStopStampRewardCountUpdateData>(StopStampRewardCount);
}
private bool m_IsFull = false;
private int m_EmptyFromIndex, m_EmptyTargetIndex = 0, m_RewardNum = 0;
public int RewardNum { get => m_RewardNum; }
private bool m_IsCounting = false;
private void StartStampRewardCount(EventScratchTicketStartStampRewardCountUpdateData data)
{
int count = m_LightStampList.Count;
m_EmptyTargetIndex = 0;
m_EmptyFromIndex = 0;
for (int i = 0; i < count; ++i)
{
if (!m_LightStampList[i].gameObject.activeInHierarchy)
{
m_EmptyFromIndex = i;
m_EmptyTargetIndex = i;
break;
}
}
m_RewardNum = m_EmptyTargetIndex;
m_IsCounting = true;
m_IsFull = false;
}
private void StopStampRewardCount(EventScratchTicketStopStampRewardCountUpdateData data)
{
m_IsCounting = false;
}
private void UpdateStampReward(EventScratchTicketStampRewardUpdateData data)
{
if (m_DataManager == null || m_DataManager.ScratchTicketData == null) return;
if (m_DataManager.ScratchTicketData.StampRewardDict != null)
{
if (m_DataManager.ScratchTicketData.StampRewardDict.ContainsKey(m_EventScratchQuality))
{
var stampReward = m_DataManager.ScratchTicketData.StampRewardDict[m_EventScratchQuality];
int num = stampReward.Count;
int count = m_LightStampList.Count;
for (int i = 0; i < count; i++)
{
if (i < num)
{
if (!m_LightStampList[i].gameObject.activeInHierarchy)
{
m_LightStampList[i].gameObject.SetActive(true);
}
}
else
{
if (m_LightStampList[i].gameObject.activeInHierarchy)
{
m_LightStampList[i].gameObject.SetActive(false);
}
}
}
}
}
}
#endregion
#region UI相关
private void InitUI()
{
InitStampReward();
}
private void InitStampReward()
{
if (m_DataManager == null || m_DataManager.ScratchTicketData == null) return;
EventScratchMain eventScratchMain = m_DataManager.GetCurrentEventScratchMain();
foreach (var cardID in eventScratchMain.CardList)
{
EventScratchCard card = m_DataManager.GetEventScratchCard(cardID);
if (card != null && card.Quality == m_EventScratchQuality)
{
m_ScratchCard = card;
break;
}
}
if (m_ScratchCard != null)
{
foreach (var item in m_GrayStampList)
{
item.sprite = m_DataManager.SpriteAtlas.GetSprite(m_ScratchCard.Icon2);
}
foreach(var item in m_LightStampList)
{
item.sprite = m_DataManager.SpriteAtlas.GetSprite(m_ScratchCard.Icon);
}
}
PlayerItemData playerItemData = GContext.container.Resolve<PlayerItemData>();
var dataItem = playerItemData.GetItemDataOne(m_ScratchCard.DropReward);
m_Reward.SetData(dataItem, abbr: true);
foreach (var item in m_GrayStampList)
{
item.gameObject.SetActive(true);
}
foreach (var item in m_LightStampList)
{
item.gameObject.SetActive(false);
}
}
private void RefreshData()
{
if (m_DataManager == null || m_DataManager.ScratchTicketData == null) return;
UpdateStampReward(null);
}
#endregion
#region
private EventScratchTicketDataManager m_DataManager;
// Start is called before the first frame update
void Start()
{
m_DataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
InitUI();
InitEvent();
RefreshData();
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e3ef1d1d1f7d7e419e61c6402178495
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
using asap.core;
using DG.Tweening;
using UniRx;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Game;
namespace game
{
public class EventScratchTicketStashButtonFxCtrl : MonoBehaviour
{
[SerializeField] private DeferredRewardStashButton rewardStashButton;
[SerializeField] private GameObject rewardFly;
[SerializeField] private float jiandaRewardShowDuration = 2.0f;
private EventScratchTicketDataManager m_DataManager;
private void Start()
{
m_DataManager = GContext.container.Resolve<EventScratchTicketDataManager>();
//EventBreakAct.EventAggregator.GetEvent<EventBreakBlockBreak>().Subscribe(OnBlockBreak).AddTo(this);
}
private async void MakeRewardFly(EventBreakBlockBreak e)
{
try
{
var fly = Instantiate(rewardFly, transform).GetComponent<RewardItemNew>();
fly.SetRewardPopupData(e.Item);
fly.transform.position = e.BreakPos;
fly.gameObject.SetActive(true);
if (EventBreakAct.Ctx.IsItemFishCard(e.Item))
{
// Debug.Log($"[EventBreak] FishCard: From {rewardFly.transform.position} to {transform.position}");
_ = PlayFishCardBundleAudio();
fly.GetComponent<Animation>().Play("reward_common_open");
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(jiandaRewardShowDuration));
fly.GetComponent<Animation>().Play("reward_common_close");
await System.Threading.Tasks.Task.Delay(24 * 1000 / 60);
fly.GetComponent<CanvasGroup>().alpha = 1;
await Awaiters.NextFrame;
await DOTween.To(() => fly.transform.position,
value => fly.transform.position = value, transform.position, 1.1f)
.AsyncWaitForCompletion();
rewardStashButton.PlayReceiveAnimationWithDelay(0f);
EventBreakAct.EventAggregator.Publish(new EventBreakBlockInput(EEventBreakBlockInputOperation.Unblock));
Destroy(fly.gameObject);
}
else
{
fly.GetComponent<Animation>().Play("reward_common_open");
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(jiandaRewardShowDuration));
fly.GetComponent<Animation>().Play("reward_common_close");
await System.Threading.Tasks.Task.Delay(16 * 1000 / 60);
rewardStashButton.PlayReceiveAnimationWithDelay(1f);
await Awaiters.NextFrame;
await fly.ParticleAttractor();
// await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(1.1f));
EventBreakAct.EventAggregator.Publish(new EventBreakBlockInput(EEventBreakBlockInputOperation.Unblock));
Destroy(fly.gameObject);
}
}
catch (Exception ex)
{
Debug.Log($"[EventBreak] BreakBlockError: {ex.Message}\n{ex.StackTrace}");
}
}
private async System.Threading.Tasks.Task PlayFishCardBundleAudio()
{
GContext.Publish(new EventUISound("audio_ui_break_rewardfly"));
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(0.25f));
GContext.Publish(new EventUISound("audio_ui_break_rewardget"));
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ce915ed8442747d41ba2505b41804027
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6e7ce83232753434eac4e1f050a51e3f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d76a92f177c3b424aa14c040bfd5b8f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
//}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad3f7edb405dd0a479a0fb223cc7ede7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 64dbd9ff05166e44bbf1f72c86c717c5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View 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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2690d82f025dba34d90f948f4b59367b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 19aae918d5a1af940819cfc885737797
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,79 @@
Shader "Bamboo/ScratchCard/Brush"
{
Properties
{
_MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[PerRendererData] _OffsetScale ("Offset (xy) and Scale (zw)", Float) = (0, 0, 0, 0)
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
Lighting Off
ZWrite Off
BlendOp RevSub
Blend Zero One, One One
Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
};
sampler2D _MainTex;
fixed4 _Color;
float4 _ClipRect;
float4 _MainTex_ST;
float4 _OffsetScale;
v2f vert(appdata_t v)
{
v2f OUT;
OUT.worldPosition = (v.vertex + float4(_OffsetScale.xy, 0, 0));
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex) * _OffsetScale.zw;
OUT.color = v.color * _Color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
half4 color = tex2D(_MainTex, IN.texcoord) * IN.color;
return color;
}
ENDCG
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 73cfbd2d24f74f242bbeff8af1301850
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant: