Paper.cs 14 KB

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