Files
2026-05-26 16:15:54 +08:00

691 lines
24 KiB
C#

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<PinballScoringWidgetBase> m_BonusList = new List<PinballScoringWidgetBase>();
[SerializeField] private List<PinballScoringWidgetBase> m_ExitList = new List<PinballScoringWidgetBase>();
#region
[Header("声音设置")]
[SerializeField] private List<AssetReferenceT<AudioClip>> m_BonusSoundList = new List<AssetReferenceT<AudioClip>>();
[SerializeField] private AssetReferenceT<AudioClip> m_CollisionSound;
[SerializeField] private List<GameObject> m_CollisionSoundBlacklist = new List<GameObject>();
private int m_BonusSoundIndex = 0;
public void PlayBonusSound()
{
int count = m_BonusSoundList.Count;
if (m_BonusSoundIndex >= 0 && m_BonusSoundIndex < count)
{
AssetReferenceT<AudioClip> 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<EventPinballDataManager>();
}
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<string> m_WhiteNamePrefixList = new List<string>();
[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<ContactPoint2D> 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<ContactPoint2D> 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<ContactPoint2D> list = new List<ContactPoint2D>();
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<PinballPelletTrackInfo> m_PelletTrackInfoList = new List<PinballPelletTrackInfo>();
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<string> list = new List<string>();
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<string> list = new List<string>();
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<string> list = new List<string>();
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<ContactPoint2D> 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<EventPinballPlayLightOnAnimData>(new EventPinballPlayLightOnAnimData());
}
else
{
GetDataManager().IsMultipleMax = false;
}
}
public void HavePelletTriggeredExit(Collision2D collision, List<ContactPoint2D> 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<ContactPoint2D> contactPointList = new List<ContactPoint2D>();
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<EventPinballResumePelletData>(ResumePellet);
//FishingPinballAct.Subscribe<EventPinballLaunchPelletData>(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<EventPinballDataManager>().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
}
}