Paper.cs 15 KB

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