using asap.core; using Game; using GameCore; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AddressableAssets; namespace game { public class PinballFiringPin : MonoBehaviour { [SerializeField] private Collider2D m_Collider2D; [SerializeField] private PinballPellet m_PelletBase; private EventPinballDataManager m_DataManager; private PinballPellet m_Pellet; private void CreateNewPellet() { if (m_PelletBase.gameObject.activeSelf == true) { m_PelletBase.gameObject.SetActive(false); } if (m_Pellet != null) { GameObject tmp = m_Pellet.gameObject; tmp.SetActive(false); GameObject.Destroy(tmp); m_Pellet = null; } GameObject gameObject = Instantiate(m_PelletBase.gameObject, m_PelletBase.transform.position, m_PelletBase.transform.rotation, m_PelletBase.transform.parent); m_Pellet = gameObject.GetComponent(); m_Pellet.gameObject.SetActive(true); m_Pellet.InitPellet(m_RecordTimes); FishingPinballAct.Publish(new EventPinballSetDummyPelletData() { Pellet = m_Pellet }); } #region 声音相关 [Header("声音设置")] [SerializeField] private AudioClip m_FiringPinPullAudioClip; [SerializeField] private AssetReferenceT m_FiringPinSpringAudioClip; private Sound m_FiringPinPullSound; public void PlayPullSound() { if (m_FiringPinPullSound != null) { m_FiringPinPullSound.audioSource.Play(); } } public void PlaySpringSound() { if (m_FiringPinPullSound != null) { m_FiringPinPullSound.audioSource.Stop(); } GContext.Publish(new AssetReferenceAudioClip(m_FiringPinSpringAudioClip, time: 0f)); } #endregion #region 撞针操作 [Header("开关设置")] [SerializeField] private Transform m_InitialTransform; [SerializeField] private Transform m_FarthestTransform; [SerializeField] private float m_ReturnSpeed = 50f; // 回弹速度 [SerializeField] private float m_DeferTime = 0.1f; [SerializeField] private float m_ProtectedRatio = 0.1f; //#if UNITY_EDITOR [Header("物理设置/模拟数据设置")] [SerializeField] private float m_MinForce = 7f; [SerializeField] private float m_ForceStep = 0.0001f; //#endif private float m_MaxDragDistance = 0f; // 最大拖动距离 private float m_MaxDragDistancePositive = 0f; // 最大拖动距离 private Vector3 m_InitialPosition; // 初始位置 private Vector3 m_FarthestPosition; // 最远位置 private bool isDragging = false; // 拖动状态 private float m_LastTouchDownTime = -1f; private Camera mainCamera; // 主摄像机 private void OnMouseDown() { isDragging = true; m_LastTouchDownTime = Time.time; PlayPullSound(); } private void OnMouseDrag() { if (!isDragging) return; // 将屏幕坐标转为世界坐标 Vector3 touchPos = mainCamera.ScreenToWorldPoint(Input.mousePosition); touchPos.x = m_InitialPosition.x; touchPos.z = m_InitialPosition.z; // 保持Z轴不变 // 计算允许移动的位置 Vector3 targetPos = m_InitialPosition; float deltaY = Mathf.Clamp( touchPos.y - m_InitialPosition.y, m_MaxDragDistance, 0f ); targetPos.y = m_InitialPosition.y + deltaY; transform.position = targetPos; float ratio = GetDragRatio(); FishingPinballAct.Publish(new EventPinballEnergyArrowData() { Energy = ratio }); FishingPinballAct.Publish(new EventPinballSpringUpdateData() { Ratio = 1.0f - ratio }); } private void OnMouseUp() { if (isDragging == false) { FishingPinballAct.Publish(new EventPinballEnergyArrowRestoreData()); return; } isDragging = false; StartCoroutine(BounceBack()); } public float GetDragRatio() { Vector3 startPos = transform.position; float deadzone = m_MaxDragDistancePositive * m_ProtectedRatio; float distance = Mathf.Abs(startPos.y - m_InitialPosition.y) - deadzone; if (distance <= 0f) return 0f; float totalDistance = m_MaxDragDistancePositive - deadzone; if (totalDistance <= 0f) return 0f; return distance / totalDistance; } private void ShowChainPack() { if (GContext.container.Resolve().ChainPackWithProgressMigrationData.IsChainPackDepleted) { ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_103")); } GContext.container.Resolve().ChainPackWithProgressMigrationData.ShowChainPack(); } IEnumerator BounceBack() { float elapsed = 0f; Vector3 startPos = transform.position; float ratio = GetDragRatio(); while (elapsed < 1f) { elapsed += m_ReturnSpeed * Time.deltaTime; // 使用缓动函数实现弹性 transform.position = Vector3.Lerp( startPos, m_InitialPosition, Mathf.SmoothStep(0, 1, elapsed) ); float tmpRatio = GetDragRatio(); FishingPinballAct.Publish(new EventPinballSpringUpdateData() { Ratio = 1.0f - tmpRatio }); yield return null; } float tmpLastTouchDownTime = m_LastTouchDownTime; m_LastTouchDownTime = -1f; if (ratio <= 0f) { FishingPinballAct.Publish(new EventPinballEnergyArrowRestoreData()); yield break; } if (tmpLastTouchDownTime < 0f) { FishingPinballAct.Publish(new EventPinballEnergyArrowRestoreData()); yield break; } if (Time.time - tmpLastTouchDownTime < m_DeferTime) { FishingPinballAct.Publish(new EventPinballEnergyArrowRestoreData()); yield break; } PlaySpringSound(); if (m_IsPelletRunning) { yield break; } var dataManager = GContext.container.Resolve(); //dataManager.InitGameRound(); if (!dataManager.ConsumeTemporaryTokensDefault()) { FishingPinballAct.Publish(new EventPinballEnergyArrowRestoreData()); ShowChainPack(); yield break; } if (m_DataManager != null) { m_DataManager.IsSimulatorMode = m_IsSimulatorMode; } //CreateNewPellet(); //float force = Mathf.Lerp(m_MinForce, m_MaxForce, ratio); float force = dataManager.GetRandomForce(ratio); m_Pellet.LaunchPellet(force, m_RecordTimes); FishingPinballAct.Publish(new EventPinballEnergyArrowRestoreData()); //#if AGG // using (var e = GEvent.GameEvent("event_pinball")) // { // e.AddContent("force", force) // .AddContent("item_consume", m_DataManager.TemporaryConsumedToken); // } //#endif } bool IsTouchingSwitch(Vector2 screenPos) { RaycastHit2D hit = Physics2D.Raycast( mainCamera.ScreenToWorldPoint(screenPos), Vector2.zero ); return hit.collider != null && hit.collider.gameObject == gameObject; } #endregion #region 运行模式相关(模拟数据模式/正常玩家模式) [SerializeField] private bool m_IsSimulatorMode = false; [SerializeField] private bool m_IsProcessingSimulatedData = false; private int m_RecordTimes = 0; #endregion #region 事件相关 private void InitEvent() { FishingPinballAct.Subscribe(ResetPelletInFiringPin); FishingPinballAct.Subscribe(LaunchPelletInFiringPin); FishingPinballAct.Subscribe(ResumePellet); FishingPinballAct.Subscribe(OnLaunchPelletDataEvent); } public void ResumePellet(EventPinballResumePelletData data) { CreateNewPellet(); float force = m_MinForce + m_ForceStep * m_RecordTimes; m_Pellet.ResumePellet(force, m_RecordTimes); if (m_IsProcessingSimulatedData) { m_RecordTimes++; } } public void OnLaunchPelletDataEvent(EventPinballLaunchPelletData data) { if (data == null) return; if (m_Pellet != null) { m_Pellet.LaunchPellet(data.Force, m_RecordTimes); } } private bool m_IsPelletRunning = false; public void LaunchPelletInFiringPin(EventPinballLaunchPelletStatusData data) { m_IsPelletRunning = true; } public void ResetPelletInFiringPin(EventPinballResetPelletStatusData data) { m_IsPelletRunning = false; } #endregion #region 生命周期 // Start is called before the first frame update void Start() { m_DataManager = GContext.container.Resolve(); m_InitialPosition = m_InitialTransform.position; m_FarthestPosition = m_FarthestTransform.position; m_MaxDragDistance = m_FarthestTransform.position.y - m_InitialPosition.y; m_MaxDragDistancePositive = Mathf.Abs(m_MaxDragDistance); mainCamera = Camera.main; m_LastTouchDownTime = -1f; m_FiringPinPullSound = GContext.container.Resolve().GetNewUISound(m_FiringPinPullAudioClip); m_IsSimulatorMode = false; m_IsPelletRunning = false; InitEvent(); CreateNewPellet(); } // Update is called once per frame void Update() { if (m_Collider2D == null) return; bool isTriggered = false, isDown = false, isDrag = false, isUp = false; Vector2 screenPosition = Vector2.zero; #if UNITY_EDITOR if (Input.GetKeyUp(KeyCode.F1)) { if (m_DataManager != null) { m_DataManager.IsSimulatorMode = m_IsSimulatorMode; } //CreateNewPellet(); m_Pellet.InitPellet(m_RecordTimes); //m_Pellet.ResetPellet(); m_Pellet.SetState(EventPinballState.Prepare); m_Pellet.LaunchPellet(m_MinForce, m_RecordTimes); return; } else if (Input.GetKeyUp(KeyCode.F2)) { FishingPinballAct.Publish(new EventPinballResumePelletData()); return; } isDown = Input.GetMouseButtonDown(0); isDrag = Input.GetMouseButton(0); isUp = Input.GetMouseButtonUp(0); screenPosition = Input.mousePosition; isTriggered = isDown || isDrag || isUp; #elif UNITY_IOS || UNITY_ANDROID isTriggered = Input.touchCount > 0; if (isTriggered) { Touch touch = Input.GetTouch(0); screenPosition = touch.position; switch (touch.phase) { case TouchPhase.Began: { isDown = true; } break; case TouchPhase.Moved: { isDrag = true; } break; case TouchPhase.Ended: { isUp = true; } break; } } #endif if (isTriggered && IsTouchingSwitch(screenPosition)) { if (isDown) { OnMouseDown(); } else if (isUp) { OnMouseUp(); } else if (isDrag) { OnMouseDrag(); } } else { OnMouseUp(); } } #endregion } }