using asap.core; using Game; using GameCore; using System.Collections; using System.Collections.Generic; using System.IO; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; namespace game { [RequireComponent(typeof(Rigidbody2D))] public class PinballPellet : MonoBehaviour { [Header("物理设置")] public float Gravity = 9.81f; public Rigidbody2D m_Rigidbody2D; [Header("操作设置")] [SerializeField] private List m_BonusList = new List(); [SerializeField] private List m_ExitList = new List(); #region 声音相关 [Header("声音设置")] [SerializeField] private List> m_BonusSoundList = new List>(); [SerializeField] private AssetReferenceT m_CollisionSound; [SerializeField] private List m_CollisionSoundBlacklist = new List(); private int m_BonusSoundIndex = 0; public void PlayBonusSound() { int count = m_BonusSoundList.Count; if (m_BonusSoundIndex >= 0 && m_BonusSoundIndex < count) { AssetReferenceT bonusSound = m_BonusSoundList[m_BonusSoundIndex]; GContext.Publish(new AssetReferenceAudioClip(bonusSound, time: 0f)); } m_BonusSoundIndex++; } public void PlayCollisionSound() { GContext.Publish(new AssetReferenceAudioClip(m_CollisionSound, time: 0f)); } #endregion #region 分数 public void AddScore(PinballScoringWidgetBase scoringWidget, ContactPoint2D contactPoint, bool isCumulativeResponseNumber = true) { if (scoringWidget == null) return; if (isCumulativeResponseNumber) { GetDataManager().CumulativeResponseNumber++; } // 弹出文本 string tip = scoringWidget.GetTip(); EventPinballBonusType bonusType = scoringWidget.BonusType; int number = scoringWidget.Number; FloatingText floatingText = null; if (bonusType == EventPinballBonusType.TypeScore) { floatingText = FloatingTextPool.Instance.GetFloatingScoreText(); GetDataManager().AddTemporaryScore(number); floatingText.Initialize(tip, contactPoint.point); } else if (bonusType == EventPinballBonusType.TypeMultiple) { //floatingText = FloatingTextPool.Instance.GetFloatingMultipleText(); GetDataManager().MultiplyTemporaryScore(number); //floatingText.Initialize(tip, contactPoint.point); } //m_PelletTrackInfo.RoutePointList. //string routes = string.Join("-", m_PelletTrackInfo.RoutePointList); //Debug.LogError("--- 类型:" + bonusType + ", times:" + m_RecordTimes + ", name:" + scoringWidget.gameObject.name + ", 增加分数:" + number + ", 当前分数:" + m_Score + ", tip:" + tip + ", count:" + m_PelletTrackInfo.RoutePointList.Count + ", routes:"+ routes); } #endregion #region 状态数据 private EventPinballDataManager m_DataManager; public EventPinballDataManager GetDataManager() { if (m_DataManager == null) { m_DataManager = GContext.container.Resolve(); } return m_DataManager; } private EventPinballState m_State = EventPinballState.Prepare; public void SetState(EventPinballState state) { if (m_State != state) { m_State = state; } } public void SetBonusListToInvalid() { foreach (var item in m_BonusList) { item.SetInvalidMaterial(); } } public void ResetBonusListToValid() { foreach (var item in m_BonusList) { item.ResetValidMaterial(); } } public void ResetExitListToValid() { foreach (var item in m_ExitList) { item.ResetValidMaterial(); } } #endregion //#if UNITY_EDITOR #region CSV记录 [Header("数据存储设置")] [SerializeField] private float m_MaxTime = 15f; [SerializeField] private List m_WhiteNamePrefixList = new List(); [SerializeField] private bool m_IsProcessingSimulatedData = false; [SerializeField] private bool m_IsSaveTrackInfoData = false; private int m_RecordTimes = 0; private PinballPelletTrackInfo m_PelletTrackInfo = new PinballPelletTrackInfo(); private float m_Force = 10f; private float m_CumulativeTime = 0f; private static readonly object trackInfoLock = new object(); public void ClearPelletTrackInfo(int recordTimes) { if (!m_IsSaveTrackInfoData) return; if (m_Rigidbody2D == null) return; m_PelletTrackInfo.ID = recordTimes; m_PelletTrackInfo.Name = this.gameObject.name; m_PelletTrackInfo.Force = m_Force; m_PelletTrackInfo.Gravity = Gravity; m_PelletTrackInfo.Clear(); } public void SavePelletTrackInfo() { if (!m_IsSaveTrackInfoData) return; m_PelletTrackInfo.Score = GetDataManager().TemporaryScore; SavePelletTrackInfoToCsv(EventPinballConfig.CSVFileName); } public void RecordTrackInfo(List list, EventPinballTrackType trackType, Collision2D collision) { if (!m_IsSaveTrackInfoData) return; lock (trackInfoLock) { if (m_Rigidbody2D == null || list == null) return; var trackNode = new PinballPelletTrackNode() { TrackType = trackType, ContactName = collision.gameObject.name, MaterialName = collision.rigidbody?.sharedMaterial?.name }; m_PelletTrackInfo.TrackNodeList.Add(trackNode); foreach (var item in list) { TrackNodeContactPoint2D contactPoint2D = new TrackNodeContactPoint2D() { Velocity = item.relativeVelocity, Position = item.point }; trackNode.ContactPoint2DList.Add(contactPoint2D); } } } public void RecordEnter(Collision2D collision, List contactPointList) { if (!m_IsSaveTrackInfoData) return; if (m_Rigidbody2D == null || collision == null) return; if (CheckNeedRecord(collision)) { m_PelletTrackInfo.RoutePointList.Add(collision.gameObject.name); } RecordTrackInfo(contactPointList, EventPinballTrackType.TypeEnter, collision); } public void RecordExit(Collision2D collision) { if (!m_IsSaveTrackInfoData) return; if (m_Rigidbody2D == null || collision == null) return; List list = new List(); collision.GetContacts(list); RecordTrackInfo(list, EventPinballTrackType.TypeExit, collision); } public bool CheckNeedRecord(Collision2D collision) { if (collision == null) return false; foreach (var item in m_WhiteNamePrefixList) { if (collision.gameObject.name.StartsWith(item)) { return true; } } return false; } public IEnumerator PrepareToSavePelletTrackInfo(float force, int recordTimes) { //StaticBall(); yield return new WaitForSeconds(0.2f); //m_PelletTrackInfo.Score = GetDataManager().TemporaryScore; //SavePelletTrackInfo(); //StaticBall(); yield return new WaitForSeconds(1f); //StaticBall(); yield return new WaitForSeconds(2f); ResetPellet(); SetState(EventPinballState.Prepare); FishingPinballAct.Publish(new EventPinballResetPelletStatusData()); //float force = m_MinForce + m_ForceStep * m_RecordTimes; LaunchPellet(force, recordTimes); } #endregion //#endif #region 轨迹记录 private List m_PelletTrackInfoList = new List(); public void ClearPelletTrackInfoList() { if (!m_IsSaveTrackInfoData) return; foreach (var item in m_PelletTrackInfoList) { item.Clear(); } m_PelletTrackInfoList.Clear(); } public void AddPelletTrackInfo(PinballPelletTrackInfo pelletTrackInfo) { if (!m_IsSaveTrackInfoData) return; m_PelletTrackInfoList.Add(pelletTrackInfo); } public string GetPelletTrackInfoCsvHeader() { List list = new List(); list.Add("id"); list.Add("Name"); list.Add("Force"); list.Add("Count"); list.Add("Multiple"); list.Add("Score"); list.Add("TrackInfo"); string header = string.Join(",", list); return header; } public void CreatePelletTrackInfoCsv(string filename) { if (!m_IsSaveTrackInfoData) return; string filapath = GetDataManager().GetSaveFilepath(filename); Debug.LogWarning("--- filepath:" + filapath); if (!File.Exists(filapath)) { List list = new List(); list.Add(GetPelletTrackInfoCsvHeader()); PinballUtils.ExportToCSV(list, filapath); } } public void SavePelletTrackInfoToCsv(string filename) { if (!m_IsSaveTrackInfoData) return; string filapath = GetDataManager().GetSaveFilepath(filename); Debug.LogWarning("--- filepath:" + filapath); List list = new List(); foreach (var trackInfo in m_PelletTrackInfoList) { list.Add(trackInfo.ToString()); } PinballUtils.ExportToCSV(list, filapath); } #endregion #region 操作相关 private bool m_ReadyToLaunch = false; public void PrepareToResetPellet() { //StaticBall(); //yield return new WaitForSeconds(2f); ResetPellet(); SetState(EventPinballState.Prepare); FishingPinballAct.Publish(new EventPinballResetPelletStatusData()); } public void LaunchPellet(float force, int recordTimes) { if (m_State != EventPinballState.Prepare) return; SetState(EventPinballState.Running); m_CumulativeTime = 0f; //#if UNITY_EDITOR m_Force = force; GetDataManager().PinballData.Force = force; ClearPelletTrackInfo(recordTimes); ClearPelletTrackInfoList(); AddPelletTrackInfo(this.m_PelletTrackInfo); //m_RecordTimes++; //#endif //Debug.LogWarning("--- LaunchPellet force:" + force + ", m_Force:" + m_Force); Physics2D.gravity = new Vector2(0f, -Mathf.Abs(Gravity)); //var dir = new Vector2(0f, 1f); //m_Rigidbody2D.AddForce(dir * force, ForceMode2D.Impulse); m_ReadyToLaunch = true; FishingPinballAct.Publish(new EventPinballLaunchPelletStatusData()); } public void ResetPellet() { GetDataManager().GetNextPinballData(); FishingPinballAct.Publish(new EventPinballSwitcherOpen()); FishingPinballAct.Publish(new EventPinballStopArrowBreathAnimData()); FishingPinballAct.Publish(new EventPinballHideWidgetMultipleEffectData()); FishingPinballAct.Publish(new EventPinballHideCircularRotationalAnim()); FishingPinballAct.Publish(new EventPinballBasicScoreShowData()); GetDataManager().InitGameRound(); m_BonusSoundIndex = 0; ResetBonusListToValid(); ResetExitListToValid(); ShowRenderer(); //StaticBall(); //this.transform.position = m_OriginalPosition; //this.transform.rotation = m_OriginalQuaternion; FishingPinballAct.Publish(new EventPinballResetMagnification()); } public void CheckIfTriggeredBonusOver() { if (!GetDataManager().IsAddScoreValid()) { FishingPinballAct.Publish(new EventPinballShowWidgetScoreEffect2Data()); FishingPinballAct.Publish(new EventPinballPlayArrowBreathAnimData()); FishingPinballAct.Publish(new EventPinballShowCircularRotationalAnim()); FishingPinballAct.Publish(new EventPinballBasicScoreHideData()); } } public bool HavePelletTriggeredBonus(Collision2D collision, List contactPointList, bool isAddScore) { if (collision == null || contactPointList == null || contactPointList.Count < 1) return false; if (this.m_State == EventPinballState.Running) { ContactPoint2D contactPoint = contactPointList[0]; foreach (var item in m_BonusList) { if (item.gameObject == collision.gameObject) { GetDataManager().AccumulatedTriggerCount++; if (isAddScore) { (item as PinballScoringWidgetScore)?.ShowEffect1(); AddScore(item, contactPoint); FishingPinballAct.Publish(new EventPinballShowPopupData() { Scores = GetDataManager().TemporaryScore, BonusType = item.BonusType, IsMultipleMax = false }); CheckIfTriggeredBonusOver(); PlayBonusSound(); } //else //{ // FishingPinballAct.Publish(new EventPinballShowWidgetScoreEffect2Data()); //} return true; } } } return false; } public void CheckIfMultipleMax(int multiple) { if (multiple == EventPinballConfig.MultipleMax) { GetDataManager().IsMultipleMax = true; FishingPinballAct.Publish(new EventPinballPlayLightOnAnimData()); } else { GetDataManager().IsMultipleMax = false; } } public void HavePelletTriggeredExit(Collision2D collision, List contactPointList) { if (collision == null || contactPointList == null || contactPointList.Count < 1) return; if (this.m_State == EventPinballState.Running) { ContactPoint2D contactPoint = contactPointList[0]; foreach (var item in m_ExitList) { if (item.gameObject == collision.gameObject) { GetDataManager().PinballData.Multiple = item.Number; (item as PinballScoringWidgetMultiple)?.ShowEffect(); (item as PinballScoringWidgetMultiple)?.PlaySound(); AddScore(item, contactPoint, false); SetState(EventPinballState.Ended); CheckIfMultipleMax(item.Number); //#if UNITY_EDITOR m_PelletTrackInfo.Multiple = item.Number; SavePelletTrackInfo(); //#endif FishingPinballAct.Publish(new EventPinballHideCircularRotationalAnim()); FishingPinballAct.Publish(new EventPinballShowMultipleTextData() { BonusType = item.BonusType, Position = contactPoint.point, Tips = item.GetTip(), Scores = GetDataManager().TemporaryScore, IsMultipleMax = item.Number == EventPinballConfig.MultipleMax }); HideRenderer(); //StaticBall(); //#if AGG // using (var e = GEvent.GameEvent("event_pinball_result")) // { // e.AddContent("count", GetDataManager().AccumulatedTriggerCount) // .AddContent("Multiple", item.Number) // .AddContent("point_count", GetDataManager().TemporaryScore); // } //#endif //TerminatePellet(item.Number == EventPinballConfig.MultipleMax); return; } } } } //public void StaticBall() //{ // m_Rigidbody2D.bodyType = RigidbodyType2D.Kinematic; // m_Rigidbody2D.isKinematic = true; // m_Rigidbody2D.Sleep(); // // 重置运动状态 // m_Rigidbody2D.velocity = Vector2.zero; // m_Rigidbody2D.angularVelocity = 0f; // // 重置约束 // m_Rigidbody2D.freezeRotation = false; // 解除旋转锁定 // m_Rigidbody2D.constraints = RigidbodyConstraints2D.None; // 解除所有约束 // // 重置碰撞检测 // m_Rigidbody2D.simulated = true; // 确保启用物理模拟 // m_Rigidbody2D.interpolation = RigidbodyInterpolation2D.None; // 重置插值 // // 重置休眠状态 // m_Rigidbody2D.WakeUp(); // 强制唤醒刚体 // this.transform.position = m_OriginalPosition; // this.transform.rotation = m_OriginalQuaternion; //} public void ResumePellet(float force, int recordTimes) { //StaticBall(); //this.transform.position = m_OriginalPosition; //this.transform.rotation = m_OriginalQuaternion; if (m_IsProcessingSimulatedData) { this.StartCoroutine(PrepareToSavePelletTrackInfo(force, recordTimes)); } else { //this.StartCoroutine(PrepareToResetPellet()); PrepareToResetPellet(); } } #endregion #region Collider2D protected virtual void OnCollisionEnter2D(Collision2D collision) { List contactPointList = new List(); collision.GetContacts(contactPointList); //#if UNITY_EDITOR RecordEnter(collision, contactPointList); //#endif bool isTriggered = HavePelletTriggeredBonus(collision, contactPointList, GetDataManager().IsAddScoreValid()); if (!isTriggered) { bool isInBlacklist = false; foreach (var item in m_CollisionSoundBlacklist) { if (collision.gameObject == item) { isInBlacklist = true; break; } } if (!isInBlacklist) { PlayCollisionSound(); } } HavePelletTriggeredExit(collision, contactPointList); } protected virtual void OnCollisionExit2D(Collision2D collision) { //#if UNITY_EDITOR RecordExit(collision); //#endif if (!GetDataManager().IsAddScoreValid()) { SetBonusListToInvalid(); } } #endregion #region 显示 [SerializeField] private SpriteRenderer m_SpriteRenderer; [SerializeField] private GameObject m_Trail; public void HideRenderer() { if (m_SpriteRenderer != null) { m_SpriteRenderer.enabled = false; } if (m_Trail != null) { m_Trail.SetActive(false); } } public void ShowRenderer() { if (m_SpriteRenderer != null) { m_SpriteRenderer.enabled = true; } if (m_Trail != null) { m_Trail.SetActive(true); } } #endregion #region 事件相关 public void InitEvent() { //FishingPinballAct.Subscribe(ResumePellet); //FishingPinballAct.Subscribe(OnLaunchPelletDataEvent); } //public void OnLaunchPelletDataEvent(EventPinballLaunchPelletData data) //{ // if (data == null) return; // LaunchPellet(data.Force); //} #endregion #region 生命周期 private Vector3 m_OriginalPosition; private Quaternion m_OriginalQuaternion; // Start is called before the first frame update public void InitPellet(int recordTimes) { m_OriginalPosition = transform.position; m_OriginalQuaternion = transform.rotation; m_ReadyToLaunch = false; InitEvent(); //#if UNITY_EDITOR ClearPelletTrackInfo(recordTimes); CreatePelletTrackInfoCsv(EventPinballConfig.CSVFileName); //#endif SetState(EventPinballState.Prepare); ResetPellet(); //GetDataManager().InitGameRound(); //m_Text.text = GContext.container.Resolve().GetSaveFilepath(EventPinballConfig.CSVFileName); } // Update is called once per frame void Update() { //#if UNITY_EDITOR if (m_State == EventPinballState.Running) { if (m_Rigidbody2D.IsSleeping()) { m_CumulativeTime += Time.deltaTime; } else { m_CumulativeTime = 0; } if (m_CumulativeTime > 0.1f) { GetDataManager().ReturnConsumedToken(); ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_104")); HideRenderer(); //StaticBall(); SetState(EventPinballState.Ended); FishingPinballAct.Publish(new EventPinballResumePelletData()); } } //#endif } private void FixedUpdate() { if (m_ReadyToLaunch) { m_Rigidbody2D.bodyType = RigidbodyType2D.Dynamic; m_Rigidbody2D.isKinematic = false; var dir = new Vector2(0f, 1f); m_Rigidbody2D.AddForce(dir * m_Force, ForceMode2D.Impulse); m_ReadyToLaunch = false; } } #endregion } }