using asap.core; using asap.core.common; using Assets.Scripts.UI.PinataPack; using DG.Tweening; using Game; using GameCore; using RootMotion; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using UnityEngine; public class PinataPackAct : AGameAct { public enum ForceModeType { None = 0, ComplexForce = 1, SimpleForce = 2, SphereForce = 3 } [Header("点击动画")] [SerializeField] private List hitAnimators; [Header("点击屏幕特效")] [SerializeField] private PinataEffectClickScene clickSceneEffectPrefab; [Header("点击Pinata特效")] [SerializeField] private PinataEffectClickPinata clickPinataEffectPrefab; [Header("力的模式")] [SerializeField]// 1-复杂力 2-简单力 3-球体力 private ForceModeType forceMode = ForceModeType.SphereForce; [SerializeField] private bool enableAllRigidbodyAddForce = false; [ShowIf("enableAllRigidbodyAddForce", false)] [SerializeField] private Rigidbody[] _rigidbodys; [SerializeField] [Tooltip("绳子起始点")] private List originPostionTrans; [Tooltip("绳子目标点")] [SerializeField] private List targetPostionTrans; [ShowIf("forceMode", ForceModeType.ComplexForce)] [SerializeField] private float complexForce = 50f; [ShowIf("forceMode", ForceModeType.ComplexForce)] [SerializeField] private float detectionRadius = 2f; [ShowIf("forceMode", ForceModeType.SimpleForce)] [SerializeField] private Vector3 simpleForceV3; [ShowIf("forceMode", ForceModeType.SphereForce)] [SerializeField] private Transform sphereTrans; [ShowIf("forceMode", ForceModeType.SphereForce)] [SerializeField] private Transform targetTrans; [ShowIf("forceMode", ForceModeType.SphereForce)] [SerializeField] [Tooltip("移动花费时间")] private float sphereMoveTime = 0.5f; [Header("闪白")] [SerializeField] private float flickerTime = 2f; [SerializeField] public List notFlickerObjs; [Header("奖励")] [SerializeField] private List rewardFlyOriginTrans; [Header("爆炸")] [SerializeField] private List needHideOnBomb; [SerializeField] private Transform bombOriginPosTrans; [SerializeField] private float bombForce=1f; [SerializeField] private float bombDelayTime = 1f; [SerializeField] private float bombEndDelayTime = 0.2f; [SerializeField] private GameObject bombEffectPrefab; [SerializeField] private Transform moveRope; private HashSet _notFlickerObjs; private List _materials = new List(); private Collider[] hitColliders; private Material instanceMaterial; private Vector3 sphereOriginPos; private IObjectPoolService _objectPoolService; private IObjectPool _sceneEffectPool; private IObjectPool _pinataEffectPool; public override async Task StartAsync() { if (enableAllRigidbodyAddForce) _rigidbodys = this.transform.GetComponentsInChildren(); if (forceMode == ForceModeType.SphereForce) { sphereOriginPos = sphereTrans.position; } _notFlickerObjs = notFlickerObjs?.ToHashSet() ?? new HashSet(); var meshRenders = this.GetComponentsInChildren(); foreach (var meshRender in meshRenders) { if (notFlickerObjs.Contains(meshRender.gameObject)) { var originalMaterial = meshRender.sharedMaterial; instanceMaterial = new Material(originalMaterial); meshRender.material = instanceMaterial; instanceMaterial = null; continue; } _materials.AddRange(meshRender.sharedMaterials); } _objectPoolService = GContext.container.Resolve(); if (clickSceneEffectPrefab != null) _sceneEffectPool = _objectPoolService.CreatePool(clickSceneEffectPrefab, 1); if (clickPinataEffectPrefab != null) _pinataEffectPool = _objectPoolService.CreatePool(clickPinataEffectPrefab, 1); var packMain = GContext.container.Resolve()?.EventPinataPackMain; var uiTypes = UITypes.GetUIType(packMain?.GamePanel ?? nameof(PinataPack_PonySettlementPanel)); await UIManager.Instance.ShowUILoad(uiTypes); return await base.StartAsync(); } public async Task MoveRope() { var duration = 0.5f; if(moveRope!=null) moveRope.DOMoveY(0.5f, duration).SetEase(Ease.OutSine); await new WaitForSeconds(duration); } #region 点击 public void ClickPony(int clickCount) { if (_rigidbodys == null) return; for (int i = 0; i < _rigidbodys.Length; i++) { var rigidbody = _rigidbodys[i]; if (rigidbody == null) continue; // 使用OverlapSphere检测周围表面 if (forceMode == ForceModeType.ComplexForce) { Vector3 forceV3 = GetSurfaceNormalWithOverlap(rigidbody) * complexForce; rigidbody.AddForce(forceV3, ForceMode.Impulse); } else if (forceMode == ForceModeType.SimpleForce) { rigidbody.AddForce(simpleForceV3, ForceMode.Impulse); } else { sphereTrans.DOMoveZ(targetTrans.position.z, sphereMoveTime) .OnComplete(() => sphereTrans.position = sphereOriginPos); } } var index = clickCount < 4 ? clickCount + 1 : clickCount % 2 == 0 ? 3 : 4; foreach (var animator in hitAnimators) { #if UNITY_EDITOR Debug.Log($"jsd ClickPony Hit0{index}"); #endif animator.Play($"Hit0{index}", 0, 0f); } _ = ShowFlicker(); } private async Task ShowFlicker() { SetFlickerState(true); await new WaitForSeconds(flickerTime); SetFlickerState(false); } private void SetFlickerState(bool isFlicker) { foreach (var material in _materials) { if (isFlicker) material.EnableKeyword("_EMISSION"); else material.DisableKeyword("_EMISSION"); } } // 使用OverlapSphere检测周围表面 private Vector3 GetSurfaceNormalWithOverlap(Rigidbody rb) { if (_rigidbodys == null) return default; if (hitColliders == null) hitColliders = new Collider[_rigidbodys?.Length ?? 1 * 2]; else Array.Clear(hitColliders, 0, hitColliders.Length); Physics.OverlapSphereNonAlloc(rb.position, detectionRadius, hitColliders); Vector3 averageNormal = Vector3.zero; int count = 0; foreach (var hitCollider in hitColliders) { if (hitCollider == null) continue; if (hitCollider.attachedRigidbody == rb) continue; Vector3 direction = (hitCollider.ClosestPoint(rb.position) - rb.position).normalized; RaycastHit hit; if (Physics.Raycast(rb.position, direction, out hit, detectionRadius * 2)) { averageNormal += hit.normal; count++; #if UNITY_EDITOR Debug.DrawRay(hit.point, hit.normal * 2, Color.yellow, 2f); #endif } } if (count > 0) { return (averageNormal / count).normalized; } // 如果没有检测到任何表面,使用默认值 return Vector3.up; } #endregion #region 奖励 public async Task PlayClickEffect(Vector3 clickPostion) { if (_sceneEffectPool == null) return; var pinataEffect = _sceneEffectPool.SpawnObject() as PinataEffectClickScene; Debug.DrawLine(transform.position, clickPostion, Color.red, 2f); pinataEffect.transform.position = clickPostion; float time = 0f; foreach (var effect in pinataEffect.GetParticleSystems()) { if (effect.gameObject.name == "1") continue; time = Mathf.Max(time, effect.main.duration); } await new WaitForSeconds(time); _sceneEffectPool.DespawnObject(pinataEffect, time); } public async Task PlayClickPinataEffect() { if (_pinataEffectPool == null) return; var pinataEffect = _pinataEffectPool.SpawnObject() as PinataEffectClickPinata; float time = 0f; foreach (var effect in pinataEffect.GetParticleSystems()) { if (effect.gameObject.name == "1") continue; time = Mathf.Max(time, effect.main.duration); } await new WaitForSeconds(time); _pinataEffectPool.DespawnObject(pinataEffect); } public void GetRewardOriginPos(out Vector3 rewardFlyOriginPos1, out Vector3 rewardFlyOriginPos2) { if (rewardFlyOriginTrans.Count >= 2) { rewardFlyOriginPos1 = rewardFlyOriginTrans[0].position; rewardFlyOriginPos2 = rewardFlyOriginTrans[1].position; } else rewardFlyOriginPos2 = rewardFlyOriginPos1 = Vector3.zero; } #endregion #region 爆炸 private GameObject bombEffect; public async Task BombPony() { if (bombEffectPrefab != null) { bombEffect = GameObject.Instantiate(bombEffectPrefab, bombOriginPosTrans.position, Quaternion.identity); bombEffect?.SetActive(true); } await new WaitForSeconds(bombDelayTime); GContext.Publish(new EventUISound($"audio_ui_eventpinatapony_break")); foreach (var obj in needHideOnBomb) { if (obj != null) obj.SetActive(false); } if (_rigidbodys == null) return; for (int i = _rigidbodys.Length - 1; i >= 0; i--) { var rigidbody = _rigidbodys[i]; if (rigidbody == null) continue; if (rigidbody.TryGetComponent(out Joint joint)) joint.breakForce = 0; rigidbody.AddExplosionForce(bombForce, bombOriginPosTrans.position, 200f,100, ForceMode.Impulse); } await Awaiters.Seconds(bombEndDelayTime); } #endregion #if UNITY_EDITOR // 可视化检测范围 private void OnDrawGizmosSelected() { Gizmos.color = Color.cyan; if (_rigidbodys == null) return; foreach (var rb in _rigidbodys) { if (rb == null) return; Gizmos.DrawWireSphere(rb.position, detectionRadius); if (bombOriginPosTrans == null) return; Gizmos.DrawLine(rb.position, bombOriginPosTrans.position); } } #endif private void FixedUpdate() { if (targetPostionTrans == null || targetPostionTrans.Count <= 0) return; if (originPostionTrans == null || originPostionTrans.Count <= 0) return; for (int i = 0; i < originPostionTrans.Count && i < targetPostionTrans.Count; i++) { var originTrans = originPostionTrans[i]; var targetTrans = targetPostionTrans[i]; if (originTrans == null || targetTrans == null) continue; targetTrans.position = originTrans.position; } } protected override void OnDestroy() { Debug.Log($"Exit AnimalPackAct"); _materials.Clear(); _notFlickerObjs.Clear(); _materials = null; _notFlickerObjs = null; _objectPoolService.DestroyPool(); _objectPoolService.DestroyPool(); if(bombEffect!=null) Destroy(bombEffect); } }