FruitBehavior.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. using MathNet.Numerics;
  2. using o0.Wave.RealTime.Old;
  3. using ShatterToolkit;
  4. using ShatterToolkit.Helpers;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. using UnityEngine.UI;
  8. public enum FruitType
  9. {
  10. Normal,
  11. Bomb,
  12. FrozenBanana,
  13. ComboPomegranate,
  14. RainbowApple
  15. }
  16. public class FruitBehavior : MonoBehaviour
  17. {
  18. public const float ArrivingDist = 5.0f;
  19. [SerializeField] public Material IceMat_NoTex = null;
  20. [SerializeField] public Material IceMat_Tex = null;
  21. private List<List<Material>> MatBeforeFrost = new List<List<Material>>();
  22. private float Trajectory_coef_a; // y = ax^2 + bx + c
  23. private float Trajectory_coef_b; // y = ax^2 + bx + c
  24. private float Trajectory_coef_c; // y = ax^2 + bx + c
  25. private Vector3 Original_position;
  26. private Vector3 Target_position;
  27. private float ExistingTime = 0f;
  28. private float TrajectoryTime = 0f;
  29. private float TrajectoryLifetime = 0f;
  30. public bool bMoveAlongTrajectory = true;
  31. private Vector3 SpinAxis;
  32. private float SpinSpeed;
  33. private FruitType Type;
  34. private GamingManager _gamingManager;
  35. private Material PostSplitMat;
  36. private GameObject JuiceSplash;
  37. public Sprite JuiceStain;
  38. public delegate void ArriveDelegate(FruitBehavior fb);
  39. public delegate void OnHitDelegete(FruitBehavior fb, Vector3 hit_p, bool bCritical);
  40. public event ArriveDelegate OnArrive;
  41. public event OnHitDelegete OnHitEvent;
  42. private GameObject MeshParent;
  43. public FruitType GetFruitType()
  44. {
  45. return Type;
  46. }
  47. // Which meshes should be shattered
  48. private List<GameObject> ToShatter = new List<GameObject>();
  49. void Awake()
  50. {
  51. }
  52. private void Start()
  53. {
  54. }
  55. // Update is called once per frame
  56. void Update()
  57. {
  58. if (!_gamingManager.IsGamePaused())
  59. {
  60. ExistingTime += Time.deltaTime;
  61. if (transform.position.z < ArrivingDist)
  62. {
  63. OnArrive.Invoke(this);
  64. }
  65. if (Type == FruitType.ComboPomegranate || Type == FruitType.RainbowApple || Type == FruitType.FrozenBanana)
  66. {
  67. MeshRenderer[] renderers = GetComponentsInChildren<MeshRenderer>();
  68. foreach (var renderer in renderers)
  69. {
  70. Material[] mats = renderer.materials;
  71. foreach (var mat in mats)
  72. {
  73. float sin_x = ExistingTime * Mathf.PI * 2f;
  74. float sin_y = Mathf.Sin(sin_x);
  75. float value = (sin_y + 1f) * 0.5f * 0.65f;
  76. Color flicker = new Color(value, value, value);
  77. mat.SetColor("_EmissionColor", flicker);
  78. }
  79. }
  80. }
  81. }
  82. // Moves along trajectory, if not in combo pomegranate time
  83. if (bMoveAlongTrajectory)
  84. {
  85. TrajectoryTime += Time.deltaTime;
  86. float parabola_x = Mathf.Lerp(Original_position.z, Target_position.z, TrajectoryTime / TrajectoryLifetime);
  87. float parabola_y = Trajectory_coef_a * parabola_x * parabola_x + Trajectory_coef_b * parabola_x + Trajectory_coef_c;
  88. float pos_x = Mathf.Lerp(Original_position.x, Target_position.x, TrajectoryTime / TrajectoryLifetime);
  89. gameObject.transform.position = new Vector3(pos_x, parabola_y, parabola_x);
  90. // Random spinning
  91. transform.Rotate(SpinAxis, Time.deltaTime * SpinSpeed);
  92. }
  93. }
  94. public void Init(FruitType ty, GamingManager manager, Vector3 spawnLocation, Vector3 targetLocation, float timeToArraive)
  95. {
  96. _gamingManager = manager;
  97. Type = ty;
  98. Original_position = spawnLocation;
  99. Target_position = targetLocation;
  100. GamingValues.CalcTrajectoryEquationCoef(spawnLocation, targetLocation, out Trajectory_coef_a, out Trajectory_coef_b, out Trajectory_coef_c);
  101. TrajectoryLifetime = timeToArraive;
  102. GameObject fruit = _gamingManager.gameObject.GetComponent<FruitTypeList>().GetFruit(ty, true, out PostSplitMat, out JuiceSplash, out JuiceStain);
  103. MeshParent = Instantiate(fruit, gameObject.transform);
  104. //SphereCollider sphr_collider = meshParent.GetComponent<SphereCollider>();
  105. //if (sphr_collider)
  106. //{
  107. // SphereCollider _collider = gameObject.AddComponent<SphereCollider>();
  108. // _collider.isTrigger = true;
  109. // _collider.radius = sphr_collider.radius;
  110. //}
  111. Rigidbody _body = gameObject.AddComponent<Rigidbody>();
  112. _body.isKinematic = true;
  113. _body.useGravity = false;
  114. //Destroy(GetComponent<Collider>());
  115. // Find out which meshes will participate in shattering
  116. for (int i = 0; i < MeshParent.transform.childCount; i++)
  117. {
  118. GameObject go = MeshParent.transform.GetChild(i).gameObject;
  119. if (go.CompareTag("ShatterIncluded"))
  120. {
  121. ShatterTool st = go.AddComponent<ShatterTool>();
  122. PieceRemover pr = go.AddComponent<PieceRemover>();
  123. st.GenerationLimit = 2;
  124. pr.startAtGeneration = 2;
  125. pr.timeDelay = 1f;
  126. st.SendPostSplitMessage = true;
  127. go.AddComponent<TargetUvMapper>();
  128. ToShatter.Add(go);
  129. }
  130. // Backup the origin mats of the fruit, used to recover from forst
  131. MeshRenderer renderer = go.GetComponent<MeshRenderer>();
  132. MatBeforeFrost.Add(new List<Material>());
  133. foreach (var mat in renderer.materials)
  134. {
  135. MatBeforeFrost[i].Add(mat);
  136. }
  137. }
  138. // If this is a ComboPomegarante, add a specialized behavior component
  139. if (Type == FruitType.ComboPomegranate)
  140. {
  141. gameObject.AddComponent<ComboPomegaranteBehavior>().Init(_gamingManager);
  142. }
  143. // Get a random rotation axis and speed
  144. SpinAxis = Random.rotation * Vector3.forward;
  145. SpinSpeed = Random.Range(90f, 180f);
  146. }
  147. private void OnTriggerEnter(Collider other)
  148. {
  149. // If is hit by an arrow
  150. ArrowBehavior arrow = other.gameObject.GetComponent<ArrowBehavior>();
  151. if (arrow)
  152. {
  153. arrow.HitAFruit();
  154. float fruit_dist = gameObject.transform.position.magnitude;
  155. Vector3 point_along_arrow_dir = (arrow.transform.position.normalized * fruit_dist);
  156. if ((point_along_arrow_dir - gameObject.transform.position).magnitude <= 1f)
  157. {
  158. OnHitEvent.Invoke(this, other.ClosestPoint(gameObject.transform.position), true);
  159. }
  160. else
  161. {
  162. OnHitEvent.Invoke(this, other.ClosestPoint(gameObject.transform.position), false);
  163. }
  164. return;
  165. }
  166. // If is hit by a fullscreen clearing bubble
  167. FullscreenClearBubbleBehavior bubble = other.gameObject.GetComponent<FullscreenClearBubbleBehavior>();
  168. if (bubble)
  169. {
  170. OnHitEvent.Invoke(this, gameObject.transform.position, false);
  171. return;
  172. }
  173. }
  174. // Play smashing effect, including shattering the mesh and instantiate an smashing audio which will be delay-destroyed
  175. public void SmashEffect()
  176. {
  177. foreach (var go in ToShatter)
  178. {
  179. Rigidbody rb = go.AddComponent<Rigidbody>();
  180. rb.mass = 1.0f; // add rigidbody right before shatter this mesh, then it will be destroyed along with the gameobject
  181. rb.angularDrag = 5f;
  182. PostSplitBehaviour psb = go.AddComponent<PostSplitBehaviour>();
  183. psb.PostSplitMat = PostSplitMat;
  184. psb.ExplosionPosition = gameObject.transform.position;
  185. go.SendMessage("Shatter", gameObject.transform.position);
  186. }
  187. GameObject fruitJuice = Instantiate(JuiceSplash, gameObject.transform.position, Quaternion.identity);
  188. AudioSource audio = fruitJuice.AddComponent<AudioSource>();
  189. audio.clip = _gamingManager.GetAudioManager().GetRandomSound((Type == FruitType.Bomb) ? SoundCategory.BombExplode : SoundCategory.FruitSmash);
  190. audio.Play();
  191. GamingManager.DelayDestroy(_gamingManager, fruitJuice, (Type == FruitType.Bomb) ? 3f : 1.5f);
  192. Destroy(gameObject);
  193. }
  194. public void Frost()
  195. {
  196. Debug.Log("Start Frost");
  197. for (int i = 0; i < MeshParent.transform.childCount; i++)
  198. {
  199. GameObject go = MeshParent.transform.GetChild(i).gameObject;
  200. MeshRenderer renderer = go.GetComponent<MeshRenderer>();
  201. Material[] iced_mats = new Material[renderer.materials.Length];
  202. for (int j = 0; j < renderer.materials.Length; j++)
  203. {
  204. Color originColor = renderer.materials[j].color;
  205. if (renderer.materials[j].mainTexture == null)
  206. {
  207. iced_mats[j] = new Material(IceMat_Tex);
  208. }
  209. else
  210. {
  211. iced_mats[j] = new Material(IceMat_NoTex);
  212. iced_mats[j].SetColor("_MainCol", originColor);
  213. }
  214. }
  215. renderer.materials = iced_mats;
  216. }
  217. }
  218. public void UnFrost()
  219. {
  220. for (int i = 0; i < MeshParent.transform.childCount; i++)
  221. {
  222. GameObject go = MeshParent.transform.GetChild(i).gameObject;
  223. MeshRenderer renderer = go.GetComponent<MeshRenderer>();
  224. Material[] new_mats = new Material[renderer.materials.Length];
  225. for (int j = 0; j < renderer.materials.Length; j++)
  226. {
  227. new_mats[j] = MatBeforeFrost[i][j];
  228. }
  229. renderer.materials = new_mats;
  230. }
  231. }
  232. }