FruitBehavior.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. //枪设备下设置碰撞层和tag
  95. string tagToSet = "Fruit";
  96. string layerToSet = "Target1";
  97. public void Init(FruitType ty, GamingManager manager, Vector3 spawnLocation, Vector3 targetLocation, float timeToArraive)
  98. {
  99. _gamingManager = manager;
  100. Type = ty;
  101. Original_position = spawnLocation;
  102. Target_position = targetLocation;
  103. GamingValues.CalcTrajectoryEquationCoef(spawnLocation, targetLocation, out Trajectory_coef_a, out Trajectory_coef_b, out Trajectory_coef_c);
  104. TrajectoryLifetime = timeToArraive;
  105. GameObject fruit = _gamingManager.gameObject.GetComponent<FruitTypeList>().GetFruit(ty, true, out PostSplitMat, out JuiceSplash, out JuiceStain);
  106. MeshParent = Instantiate(fruit, gameObject.transform);
  107. //SphereCollider sphr_collider = meshParent.GetComponent<SphereCollider>();
  108. //if (sphr_collider)
  109. //{
  110. // SphereCollider _collider = gameObject.AddComponent<SphereCollider>();
  111. // _collider.isTrigger = true;
  112. // _collider.radius = sphr_collider.radius;
  113. //}
  114. if (GlobalData.MyDeviceMode == DeviceMode.Gun) {
  115. gameObject.tag = tagToSet;
  116. gameObject.layer = LayerMask.NameToLayer(layerToSet);
  117. MeshParent.tag = tagToSet;
  118. MeshParent.layer = LayerMask.NameToLayer(layerToSet);
  119. }
  120. Rigidbody _body = gameObject.AddComponent<Rigidbody>();
  121. _body.isKinematic = true;
  122. _body.useGravity = false;
  123. //Destroy(GetComponent<Collider>());
  124. // Find out which meshes will participate in shattering
  125. for (int i = 0; i < MeshParent.transform.childCount; i++)
  126. {
  127. GameObject go = MeshParent.transform.GetChild(i).gameObject;
  128. if (go.CompareTag("ShatterIncluded"))
  129. {
  130. if (GlobalData.MyDeviceMode == DeviceMode.Gun) {
  131. go.tag = tagToSet;
  132. go.layer = LayerMask.NameToLayer(layerToSet);
  133. }
  134. ShatterTool st = go.AddComponent<ShatterTool>();
  135. PieceRemover pr = go.AddComponent<PieceRemover>();
  136. st.GenerationLimit = 2;
  137. pr.startAtGeneration = 2;
  138. pr.timeDelay = 1f;
  139. st.SendPostSplitMessage = true;
  140. go.AddComponent<TargetUvMapper>();
  141. ToShatter.Add(go);
  142. }
  143. // Backup the origin mats of the fruit, used to recover from forst
  144. MeshRenderer renderer = go.GetComponent<MeshRenderer>();
  145. MatBeforeFrost.Add(new List<Material>());
  146. foreach (var mat in renderer.materials)
  147. {
  148. MatBeforeFrost[i].Add(mat);
  149. }
  150. }
  151. // If this is a ComboPomegarante, add a specialized behavior component
  152. if (Type == FruitType.ComboPomegranate)
  153. {
  154. gameObject.AddComponent<ComboPomegaranteBehavior>().Init(_gamingManager);
  155. }
  156. // Get a random rotation axis and speed
  157. SpinAxis = Random.rotation * Vector3.forward;
  158. SpinSpeed = Random.Range(90f, 180f);
  159. }
  160. private void OnTriggerEnter(Collider other)
  161. {
  162. //水果爆炸不拦截
  163. // If is hit by a fullscreen clearing bubble
  164. FullscreenClearBubbleBehavior bubble = other.gameObject.GetComponent<FullscreenClearBubbleBehavior>();
  165. if (bubble)
  166. {
  167. OnHitEvent.Invoke(this, gameObject.transform.position, false);
  168. return;
  169. }
  170. //拦截子弹碰撞
  171. if (GlobalData.MyDeviceMode == DeviceMode.Gun) return;
  172. // If is hit by an arrow
  173. ArrowBehavior arrow = other.gameObject.GetComponent<ArrowBehavior>();
  174. if (arrow)
  175. {
  176. arrow.HitAFruit();
  177. float fruit_dist = gameObject.transform.position.magnitude;
  178. Vector3 point_along_arrow_dir = (arrow.transform.position.normalized * fruit_dist);
  179. if ((point_along_arrow_dir - gameObject.transform.position).magnitude <= 1f)
  180. {
  181. OnHitEvent.Invoke(this, other.ClosestPoint(gameObject.transform.position), true);
  182. }
  183. else
  184. {
  185. OnHitEvent.Invoke(this, other.ClosestPoint(gameObject.transform.position), false);
  186. }
  187. return;
  188. }
  189. }
  190. public void OnHitCollision(Collider other, ArrowBehavior shootObj)
  191. {
  192. // If is hit by an arrow
  193. if (shootObj)
  194. {
  195. shootObj.HitAFruit();
  196. float fruit_dist = gameObject.transform.position.magnitude;
  197. Vector3 point_along_arrow_dir = (shootObj.transform.position.normalized * fruit_dist);
  198. if ((point_along_arrow_dir - gameObject.transform.position).magnitude <= 1f)
  199. {
  200. OnHitEvent.Invoke(this, other.ClosestPoint(gameObject.transform.position), true);
  201. }
  202. else
  203. {
  204. OnHitEvent.Invoke(this, other.ClosestPoint(gameObject.transform.position), false);
  205. }
  206. return;
  207. }
  208. // If is hit by a fullscreen clearing bubble
  209. FullscreenClearBubbleBehavior bubble = other.gameObject.GetComponent<FullscreenClearBubbleBehavior>();
  210. if (bubble)
  211. {
  212. OnHitEvent.Invoke(this, gameObject.transform.position, false);
  213. return;
  214. }
  215. }
  216. // Play smashing effect, including shattering the mesh and instantiate an smashing audio which will be delay-destroyed
  217. public void SmashEffect()
  218. {
  219. foreach (var go in ToShatter)
  220. {
  221. Rigidbody rb = go.AddComponent<Rigidbody>();
  222. rb.mass = 1.0f; // add rigidbody right before shatter this mesh, then it will be destroyed along with the gameobject
  223. rb.angularDrag = 5f;
  224. PostSplitBehaviour psb = go.AddComponent<PostSplitBehaviour>();
  225. psb.PostSplitMat = PostSplitMat;
  226. psb.ExplosionPosition = gameObject.transform.position;
  227. go.SendMessage("Shatter", gameObject.transform.position);
  228. }
  229. GameObject fruitJuice = Instantiate(JuiceSplash, gameObject.transform.position, Quaternion.identity);
  230. AudioSource audio = fruitJuice.AddComponent<AudioSource>();
  231. audio.clip = _gamingManager.GetAudioManager().GetRandomSound((Type == FruitType.Bomb) ? SoundCategory.BombExplode : SoundCategory.FruitSmash);
  232. if (UserSettings.ins.openEffect) audio.Play();
  233. GamingManager.DelayDestroy(_gamingManager, fruitJuice, (Type == FruitType.Bomb) ? 3f : 1.5f);
  234. Destroy(gameObject);
  235. }
  236. public void Frost()
  237. {
  238. Debug.Log("Start Frost");
  239. for (int i = 0; i < MeshParent.transform.childCount; i++)
  240. {
  241. GameObject go = MeshParent.transform.GetChild(i).gameObject;
  242. MeshRenderer renderer = go.GetComponent<MeshRenderer>();
  243. Material[] iced_mats = new Material[renderer.materials.Length];
  244. for (int j = 0; j < renderer.materials.Length; j++)
  245. {
  246. Color originColor = renderer.materials[j].color;
  247. if (renderer.materials[j].mainTexture == null)
  248. {
  249. iced_mats[j] = new Material(IceMat_Tex);
  250. }
  251. else
  252. {
  253. iced_mats[j] = new Material(IceMat_NoTex);
  254. iced_mats[j].SetColor("_MainCol", originColor);
  255. }
  256. }
  257. renderer.materials = iced_mats;
  258. }
  259. }
  260. public void UnFrost()
  261. {
  262. for (int i = 0; i < MeshParent.transform.childCount; i++)
  263. {
  264. GameObject go = MeshParent.transform.GetChild(i).gameObject;
  265. MeshRenderer renderer = go.GetComponent<MeshRenderer>();
  266. Material[] new_mats = new Material[renderer.materials.Length];
  267. for (int j = 0; j < renderer.materials.Length; j++)
  268. {
  269. new_mats[j] = MatBeforeFrost[i][j];
  270. }
  271. renderer.materials = new_mats;
  272. }
  273. }
  274. }