363 lines
12 KiB
C#
363 lines
12 KiB
C#
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<Animator> 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<Transform> originPostionTrans;
|
|
[Tooltip("绳子目标点")]
|
|
[SerializeField]
|
|
private List<Transform> 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<GameObject> notFlickerObjs;
|
|
[Header("奖励")]
|
|
[SerializeField]
|
|
private List<Transform> rewardFlyOriginTrans;
|
|
|
|
[Header("爆炸")]
|
|
[SerializeField]
|
|
private List<GameObject> 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<GameObject> _notFlickerObjs;
|
|
private List<Material> _materials = new List<Material>();
|
|
private Collider[] hitColliders;
|
|
private Material instanceMaterial;
|
|
private Vector3 sphereOriginPos;
|
|
private IObjectPoolService _objectPoolService;
|
|
private IObjectPool _sceneEffectPool;
|
|
private IObjectPool _pinataEffectPool;
|
|
public override async Task<bool> StartAsync()
|
|
{
|
|
if (enableAllRigidbodyAddForce)
|
|
_rigidbodys = this.transform.GetComponentsInChildren<Rigidbody>();
|
|
|
|
if (forceMode == ForceModeType.SphereForce)
|
|
{
|
|
sphereOriginPos = sphereTrans.position;
|
|
}
|
|
|
|
_notFlickerObjs = notFlickerObjs?.ToHashSet() ?? new HashSet<GameObject>();
|
|
|
|
var meshRenders = this.GetComponentsInChildren<SkinnedMeshRenderer>();
|
|
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<IObjectPoolService>();
|
|
if (clickSceneEffectPrefab != null)
|
|
_sceneEffectPool = _objectPoolService.CreatePool(clickSceneEffectPrefab, 1);
|
|
if (clickPinataEffectPrefab != null)
|
|
_pinataEffectPool = _objectPoolService.CreatePool(clickPinataEffectPrefab, 1);
|
|
|
|
var packMain = GContext.container.Resolve<EventPinataPackData>()?.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<PinataEffectClickScene>();
|
|
_objectPoolService.DestroyPool<PinataEffectClickPinata>();
|
|
if(bombEffect!=null)
|
|
Destroy(bombEffect);
|
|
}
|
|
}
|
|
|