Paper.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using _Packages.PaperFoldAsset.Paper_Fold.Scripts;
  6. using _Packages.PaperFoldAsset.Paper_Fold.Scripts.RegexCombinationBuilder;
  7. using UnityEngine;
  8. using JetSystems;
  9. using Eiko.YaSDK;
  10. using Testing;
  11. public class Paper : MonoBehaviour
  12. {
  13. [HideInInspector] public PossibleCombinationBuilder Builder;
  14. [HideInInspector] public RegexCombinationAnalyzer RegexAnalyzer;
  15. public delegate void OnPaperStateChanged();
  16. public OnPaperStateChanged onPaperStateChanged;
  17. public delegate void OnPaperEvolving();
  18. public OnPaperEvolving onPaperEvolving;
  19. public delegate void OnPaperShowEffect();
  20. public OnPaperShowEffect onPaperShowEffect;
  21. public delegate void PaperStartFold();
  22. public PaperStartFold paperStartFold;
  23. public delegate void PaperStartUnfold();
  24. public PaperStartUnfold paperStartUnfold;
  25. [Header(" Settings ")]
  26. [SerializeField] private bool _test;
  27. [SerializeField] private bool _decalPaper;
  28. public Transform foldingsParent;
  29. private readonly List<Folding> _foldedFolding = new List<Folding>();
  30. private Folding[] _folding;
  31. private bool _canFold = true;
  32. [SerializeField] private Texture2D paperTexture;
  33. [SerializeField] private PaperEffect effect;
  34. [Header(" Rendering ")]
  35. [SerializeField] private MeshRenderer paperBackRenderer;
  36. [SerializeField] private MeshRenderer paperFrontRenderer;
  37. Folding currentFolding;
  38. [Header(" Mesh Manipulation ")] MeshFilter backFilter;
  39. private MeshFilter _frontFilter;
  40. [SerializeField] private float verticesElevationStep;
  41. [SerializeField] private float foldingDuration;
  42. [Header(" Solution ")]
  43. public PossibleCombination[] possibleCombinations;
  44. public IEnumerable<Folding> Folding => foldingsParent.Cast<Transform>().Select(x => x.GetComponent<Folding>());
  45. private Action levelCompleteCallBack;
  46. private void Awake()
  47. {
  48. backFilter = paperBackRenderer.GetComponent<MeshFilter>();
  49. _frontFilter = paperFrontRenderer.GetComponent<MeshFilter>();
  50. // Анимация появления
  51. float toPositionZ = transform.position.z;
  52. Vector3 startPosition = transform.position;
  53. startPosition.z = 10;
  54. transform.position = startPosition;
  55. LoadingState.IsLoading = true;
  56. transform.LeanMoveZ(toPositionZ, 1f)
  57. .setOnComplete(() => LoadingState.IsLoading = false);
  58. }
  59. public void setPaperCallBack(Action levelCompleteCallBackTemp)
  60. {
  61. levelCompleteCallBack = levelCompleteCallBackTemp;
  62. }
  63. // Start is called before the first frame update
  64. void Start()
  65. {
  66. #if UNITY_EDITOR
  67. if(!FindObjectOfType<DecalMaster>())
  68. #endif
  69. paperFrontRenderer.material.mainTexture = paperTexture;
  70. _folding = GetFoldings();
  71. }
  72. public void TryFold(Folding tappedFolding)
  73. {
  74. if (!_canFold) return;
  75. _canFold = false;
  76. currentFolding = tappedFolding;
  77. if (!tappedFolding.IsFolded())
  78. {
  79. _foldedFolding.Add(currentFolding);
  80. Fold();
  81. }
  82. else
  83. {
  84. // It is folded, unfold it
  85. StartCoroutine(UnfoldingProcedureCoroutine());
  86. }
  87. }
  88. private void Fold()
  89. {
  90. // We need to get the vertices that need to be folded first
  91. // These are the ones inside the folding's tapping zone
  92. StartCoroutine(FoldCoroutine(true));
  93. //StartCoroutine("FoldingCoroutine");
  94. currentFolding.SetFoldedState(true);
  95. Taptic.Light();
  96. onPaperEvolving?.Invoke();
  97. }
  98. private int[] GetVerticesToMove(MeshFilter filter, Folding folding)
  99. {
  100. List<int> verticesInsideTappingZone = new List<int>();
  101. Vector3[] vertices = filter.mesh.vertices;
  102. Plane foldingPlane = folding.GetFoldingPlane();
  103. for (int i = 0; i < vertices.Length; i++)
  104. {
  105. Vector3 vertexWorldPos = filter.transform.TransformPoint(vertices[i]);
  106. if (foldingPlane.GetSide(vertexWorldPos))
  107. verticesInsideTappingZone.Add(i);
  108. }
  109. return verticesInsideTappingZone.ToArray();
  110. }
  111. private bool IsInsideTappingZone(Vector3 vertexLocalPos, BoxCollider tappingZone)
  112. {
  113. Vector3 vertexWorldPos = paperBackRenderer.transform.position + vertexLocalPos;
  114. return tappingZone.bounds.Contains(vertexWorldPos);
  115. }
  116. private Vector3 GetRotatedPoint(Vector3 point, float angle, RotationAxis rotationAxis)
  117. {
  118. Vector3 pivot = rotationAxis.position;
  119. Quaternion q = Quaternion.AngleAxis(angle, rotationAxis.AsVector());
  120. return q * (point - pivot) + pivot;
  121. }
  122. private void Unfold()
  123. {
  124. StartCoroutine(FoldCoroutine(false));
  125. currentFolding.SetFoldedState(false);
  126. currentFolding.ClearFoldedVertices();
  127. }
  128. public void StartUnfolding()
  129. {
  130. if (!_canFold) return;
  131. _canFold = false;
  132. StartCoroutine(UnfoldingProcedureCoroutine());
  133. }
  134. IEnumerator UnfoldingProcedureCoroutine()
  135. {
  136. // 1. Check if there is any folding before this one
  137. for (int i = _foldedFolding.Count - 1; i >= 0; i--)
  138. {
  139. Folding folding = _foldedFolding[i];
  140. if (folding == currentFolding)
  141. {
  142. //Unfold();
  143. Taptic.Light();
  144. onPaperEvolving?.Invoke();
  145. yield return StartCoroutine(FoldCoroutine(false));
  146. currentFolding.SetFoldedState(false);
  147. currentFolding.ClearFoldedVertices();
  148. _foldedFolding.Remove(currentFolding);
  149. break;
  150. }
  151. else
  152. {
  153. currentFolding = folding;
  154. Taptic.Light();
  155. onPaperEvolving?.Invoke();
  156. yield return StartCoroutine(FoldCoroutine(false));
  157. currentFolding.SetFoldedState(false);
  158. currentFolding.ClearFoldedVertices();
  159. _foldedFolding.Remove(currentFolding);
  160. }
  161. }
  162. _canFold = true;
  163. onPaperStateChanged?.Invoke();
  164. yield return null;
  165. }
  166. IEnumerator FoldCoroutine(bool folding)
  167. {
  168. if (folding)
  169. paperStartFold?.Invoke();
  170. else
  171. paperStartUnfold?.Invoke();
  172. int[] backVerticesToMove = folding
  173. ? GetVerticesToMove(backFilter, currentFolding)
  174. : currentFolding.GetBackFoldedVerticesIndices();
  175. int[] frontVerticesToMove = folding
  176. ? GetVerticesToMove(_frontFilter, currentFolding)
  177. : currentFolding.GetFrontFoldedVerticesIndices();
  178. if (folding)
  179. {
  180. currentFolding.SetBackFoldedVerticesIndices(backVerticesToMove);
  181. currentFolding.SetFrontFoldedVerticesIndices(frontVerticesToMove);
  182. }
  183. Vector3[] initialBackVertices = backFilter.mesh.vertices;
  184. Vector3[] backVertices = backFilter.mesh.vertices;
  185. Vector3[] initialFrontVertices = _frontFilter.mesh.vertices;
  186. Vector3[] frontVertices = _frontFilter.mesh.vertices;
  187. if (folding)
  188. {
  189. for (int i = 0; i < frontVerticesToMove.Length; i++)
  190. initialFrontVertices[frontVerticesToMove[i]].y -= verticesElevationStep * (1 + _foldedFolding.Count);
  191. }
  192. float angleMultiplier = folding ? 1 : -1;
  193. float targetAngle = currentFolding.GetRotationAngle() * angleMultiplier;
  194. float timer = 0;
  195. while (timer <= foldingDuration + Time.deltaTime)
  196. {
  197. float angle = Mathf.Clamp01((timer / foldingDuration)) * targetAngle;
  198. for (int i = 0; i < backVerticesToMove.Length; i++)
  199. backVertices[backVerticesToMove[i]] =
  200. GetRotatedLocalVertex(initialBackVertices[backVerticesToMove[i]], angle);
  201. for (int i = 0; i < frontVerticesToMove.Length; i++)
  202. frontVertices[frontVerticesToMove[i]] =
  203. GetRotatedLocalVertex(initialFrontVertices[frontVerticesToMove[i]], angle);
  204. if (!folding)
  205. {
  206. for (int i = 0; i < frontVerticesToMove.Length; i++)
  207. frontVertices[frontVerticesToMove[i]].y += verticesElevationStep * (1 + _foldedFolding.Count);
  208. }
  209. backFilter.mesh.vertices = backVertices;
  210. _frontFilter.mesh.vertices = frontVertices;
  211. timer += Time.deltaTime;
  212. yield return null;
  213. }
  214. for (int i = 0; i < backVerticesToMove.Length; i++)
  215. backVertices[backVerticesToMove[i]] =
  216. GetRotatedLocalVertex(initialBackVertices[backVerticesToMove[i]], targetAngle);
  217. for (int i = 0; i < frontVerticesToMove.Length; i++)
  218. frontVertices[frontVerticesToMove[i]] =
  219. GetRotatedLocalVertex(initialFrontVertices[frontVerticesToMove[i]], targetAngle);
  220. if (!folding)
  221. {
  222. for (int i = 0; i < frontVerticesToMove.Length; i++)
  223. frontVertices[frontVerticesToMove[i]].y += verticesElevationStep * (1 + _foldedFolding.Count);
  224. }
  225. backFilter.mesh.vertices = backVertices;
  226. _frontFilter.mesh.vertices = frontVertices;
  227. _frontFilter.GetComponent<MeshCollider>().sharedMesh = _frontFilter.mesh;
  228. if (folding)
  229. _canFold = true;
  230. if (AvailableFoldingsEnded() && folding)
  231. {
  232. yield return new WaitForSeconds(0.1f);
  233. CheckForLevelComplete();
  234. }
  235. onPaperStateChanged?.Invoke();
  236. }
  237. private void CheckForLevelComplete()
  238. {
  239. WriteTestingInfo();
  240. if (Builder != null && Builder.Used && Builder.IsCorrect(_foldedFolding))
  241. {
  242. StartCoroutine(SetLevelComplete());
  243. return;
  244. }
  245. if (RegexAnalyzer != null && RegexAnalyzer.IsCorrect(_foldedFolding))
  246. {
  247. StartCoroutine(SetLevelComplete());
  248. return;
  249. }
  250. for (int i = 0; i < possibleCombinations.Length; i++)
  251. {
  252. if (MatchPossibleCombination(possibleCombinations[i]))
  253. {
  254. StartCoroutine(SetLevelComplete());
  255. return;
  256. }
  257. }
  258. StartCoroutine(SetWrongFoldPaper());
  259. }
  260. private void WriteTestingInfo()
  261. {
  262. var message = _foldedFolding
  263. .Select(x => x.name)
  264. .Aggregate((report, element) => report + "|" + element);
  265. LastCombinationViewer.Write(name + ":" + message);
  266. }
  267. private bool MatchPossibleCombination(PossibleCombination foldingsCombination)
  268. {
  269. if (_foldedFolding.Count != foldingsCombination.GetFoldings().Length)
  270. return false;
  271. for (int i = 0; i < _foldedFolding.Count; i++)
  272. if (_foldedFolding[i] != foldingsCombination.GetFoldings()[i])
  273. return false;
  274. return true;
  275. }
  276. private IEnumerator SetLevelComplete()
  277. {
  278. Debug.Log("Level Complete");
  279. if (_decalPaper || _test)
  280. yield break;
  281. _canFold = false;
  282. if (YandexSDK.instance != null)
  283. {
  284. YandexSDK.instance.ShowInterstitial();
  285. }
  286. LeanTween.moveZ(gameObject, -20f, 0.7f).setEaseInBack().setOnComplete(() => { });
  287. if (effect.StickerEffect != null)
  288. {
  289. StickerEffect stickerEffect = Instantiate(effect.StickerEffect);
  290. stickerEffect.CachedTransform.position = transform.position;
  291. stickerEffect.CachedSpriteRenderer.flipX = effect.FlipX;
  292. stickerEffect.CachedSpriteRenderer.flipY = effect.FlipY;
  293. onPaperShowEffect?.Invoke();
  294. yield return stickerEffect.ShowEffect(effect.SpriteImage, effect.SpriteSize, effect.SpriteRotate);
  295. yield return new WaitForSeconds(0.5f);
  296. Destroy(stickerEffect.gameObject);
  297. }
  298. UIManager.setLevelCompleteDelegate?.Invoke();
  299. levelCompleteCallBack?.Invoke();
  300. yield break;
  301. }
  302. private IEnumerator SetWrongFoldPaper()
  303. {
  304. bool animationComplete = false;
  305. Debug.Log("Wrong!");
  306. LeanTween.moveLocalX(gameObject, transform.position.x + 0.1f, 0.1f).setEaseShake().setOnComplete(() =>
  307. {
  308. LeanTween.moveLocalX(gameObject, transform.position.x - 0.1f, 0.1f).setEaseShake()
  309. .setOnComplete(() => { animationComplete = true; });
  310. });
  311. yield return new WaitUntil(() => animationComplete);
  312. animationComplete = false;
  313. if (_decalPaper || _test)
  314. yield break;
  315. UnfoldAllFoldings();
  316. if (YandexSDK.instance != null)
  317. YandexSDK.instance.ShowInterstitial();
  318. UIManager.wrongPaperFolded?.Invoke();
  319. yield break;
  320. }
  321. private Vector3 GetRotatedLocalVertex(Vector3 localVertexToMove, float angle)
  322. {
  323. Vector3 vertexWorldPos = paperBackRenderer.transform.TransformPoint(localVertexToMove);
  324. Vector3 rotatedWorldVertex = GetRotatedPoint(vertexWorldPos, angle, currentFolding.GetRotationAxis());
  325. Vector3 rotatedLocalVertex = paperBackRenderer.transform.InverseTransformPoint(rotatedWorldVertex);
  326. return rotatedLocalVertex;
  327. }
  328. public Folding[] GetFoldings(bool includeInactive = true)
  329. {
  330. return foldingsParent.GetComponentsInChildren<Folding>(includeInactive);
  331. }
  332. public MeshRenderer GetFrontRenderer()
  333. {
  334. return paperFrontRenderer;
  335. }
  336. public bool AvailableFoldingsEnded()
  337. {
  338. return _foldedFolding.Count >= _folding.Length;
  339. }
  340. public void UnfoldAllFoldings()
  341. {
  342. if (_foldedFolding.Count <= 0 || !_canFold)
  343. return;
  344. currentFolding = _foldedFolding[0];
  345. _canFold = false;
  346. StartCoroutine(UnfoldingProcedureCoroutine());
  347. }
  348. private void OnDisable()
  349. {
  350. levelCompleteCallBack = null;
  351. }
  352. }
  353. [System.Serializable]
  354. public struct PossibleCombination
  355. {
  356. [SerializeField] private Folding[] foldings;
  357. public Folding[] GetFoldings()
  358. {
  359. return foldings;
  360. }
  361. }
  362. [System.Serializable]
  363. public struct PaperEffect
  364. {
  365. [SerializeField] private StickerEffect _stickerEffect;
  366. [SerializeField] private Sprite _spriteImage;
  367. [SerializeField] private Vector3 _spriteSize;
  368. [SerializeField] private Quaternion _spriteRotate;
  369. [SerializeField] private bool _flipX;
  370. [SerializeField] private bool _flipY;
  371. public StickerEffect StickerEffect => _stickerEffect;
  372. public Sprite SpriteImage => _spriteImage;
  373. public Vector3 SpriteSize => _spriteSize;
  374. public Quaternion SpriteRotate => _spriteRotate;
  375. public bool FlipX => _flipX;
  376. public bool FlipY => _flipY;
  377. }