boatwatereffects.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. enum EBoatSpeed
  2. {
  3. UNSET,
  4. SLOWEST,
  5. SLOW,
  6. MEDIUM,
  7. FAST
  8. }
  9. class EffectBoatWaterFront : EffectBoatWaterBase
  10. {
  11. protected const int EMITORS_FAST = 9; // emitors below this ID only play when fast enough
  12. void EffectBoatWaterFront()
  13. {
  14. m_EmitorCount = 13;
  15. m_SpeedSlow = 5;
  16. m_SpeedMedium = 20;
  17. m_SpeedFast = 40;
  18. SetParticleState( ParticleList.BOAT_WATER_FRONT );
  19. }
  20. override protected void UpdateSpeedState(Particle ptc, float speed)
  21. {
  22. EBoatSpeed speedStatePast = m_SpeedState;
  23. if (speed > m_SpeedFast)
  24. m_SpeedState = EBoatSpeed.FAST;
  25. else if (speed > m_SpeedMedium)
  26. m_SpeedState = EBoatSpeed.MEDIUM;
  27. else if (speed > m_SpeedSlow)
  28. m_SpeedState = EBoatSpeed.SLOW;
  29. else
  30. m_SpeedState = EBoatSpeed.SLOWEST;
  31. if (m_SpeedState == speedStatePast)
  32. return;
  33. for (int i = 0; i < m_EmitorCount; i++)
  34. {
  35. if (i == 5 || i == 6)
  36. {
  37. if (m_SpeedState <= EBoatSpeed.MEDIUM) // fast drops
  38. EnableEmitor(ptc, i, false);
  39. else
  40. EnableEmitor(ptc, i, true);
  41. }
  42. else if (i == 9 || i == 10) // slow drops
  43. {
  44. if (m_SpeedState != EBoatSpeed.MEDIUM)
  45. EnableEmitor(ptc, i, false);
  46. else
  47. EnableEmitor(ptc, i, true);
  48. }
  49. else if (i < 5 || i == 7 || i == 8) // rest of front ptc
  50. {
  51. if (m_SpeedState <= EBoatSpeed.SLOW)
  52. EnableEmitor(ptc, i, false);
  53. else
  54. EnableEmitor(ptc, i, true);
  55. }
  56. }
  57. }
  58. override void Update(float timeSlice = 0)
  59. {
  60. if (m_Boat.GetCurrentGear() == 0)
  61. {
  62. if (IsPlaying())
  63. {
  64. GetParticle().SetParticleParam(EmitorParam.BIRTH_RATE, 0);
  65. GetParticle().SetParticleParam(EmitorParam.BIRTH_RATE_RND, 0);
  66. Stop();
  67. }
  68. return;
  69. }
  70. super.Update(timeSlice);
  71. Particle ptc = GetParticle();
  72. float lerp1, lerp2;
  73. vector velocity = dBodyGetVelocityAt(m_Boat, m_Boat.CoordToParent(GetLocalPosition()));
  74. float speed = velocity.Normalize() * 3.6; // to km/h
  75. UpdateSpeedState(ptc, speed);
  76. UpdatePosToSeaLevel(timeSlice, -0.2);
  77. lerp1 = Math.InverseLerp(0, m_SpeedFast, speed);
  78. lerp2 = Math.InverseLerp(m_SpeedMedium - 5, m_SpeedFast + 10, speed);
  79. for (int i = 0; i < m_EmitorCount; i++)
  80. {
  81. if (i == 11 || i == 12) // waves
  82. {
  83. ptc.SetParameter(i, EmitorParam.VELOCITY, ptc.GetParameterOriginal(i, EmitorParam.VELOCITY) * lerp1);
  84. }
  85. else if (i < 5 || i == 7 || i == 8) // splashes
  86. {
  87. if (m_SpeedState > EBoatSpeed.SLOW)
  88. {
  89. if (GetGame().GetWaterDepth(m_Boat.CoordToParent(m_MemPointPos)) < -0.1) // when the front of the boat is above water, disable the emitor
  90. EnableEmitor(ptc, i, false);
  91. else
  92. EnableEmitor(ptc, i, true);
  93. ptc.SetParameter(i, EmitorParam.SIZE, ptc.GetParameterOriginal(i, EmitorParam.SIZE) * lerp2);
  94. }
  95. }
  96. }
  97. }
  98. }
  99. class EffectBoatWaterBack : EffectBoatWaterBase
  100. {
  101. protected const int EMITORS_FAST = 5; // emitors below this ID only play when fast enough
  102. void EffectBoatWaterBack()
  103. {
  104. m_EmitorCount = 10;
  105. m_SpeedSlow = 25;
  106. m_SpeedMedium = 50;
  107. m_SpeedFast = 150;
  108. SetParticleState( ParticleList.BOAT_WATER_BACK );
  109. }
  110. override protected void UpdateSpeedState(Particle ptc, float speed)
  111. {
  112. EBoatSpeed speedStatePast = m_SpeedState;
  113. if (speed > m_SpeedFast)
  114. m_SpeedState = EBoatSpeed.FAST;
  115. else if (speed > m_SpeedMedium)
  116. m_SpeedState = EBoatSpeed.MEDIUM;
  117. else if (speed > m_SpeedSlow)
  118. m_SpeedState = EBoatSpeed.SLOW;
  119. else
  120. m_SpeedState = EBoatSpeed.SLOWEST;
  121. if (m_SpeedState == speedStatePast)
  122. return;
  123. for (int i = 0; i < m_EmitorCount; i++)
  124. {
  125. if (i < EMITORS_FAST) // big splash
  126. {
  127. if (m_SpeedState <= EBoatSpeed.SLOW)
  128. EnableEmitor(ptc, i, false);
  129. else
  130. EnableEmitor(ptc, i, true);
  131. }
  132. if (i >= EMITORS_FAST && i != 9)
  133. {
  134. if (m_SpeedState == EBoatSpeed.SLOWEST)
  135. EnableEmitor(ptc, i, false);
  136. else
  137. EnableEmitor(ptc, i, true);
  138. }
  139. }
  140. }
  141. override void Update(float timeSlice = 0)
  142. {
  143. if (m_Boat.GetCurrentGear() == 0)
  144. {
  145. if (IsPlaying())
  146. {
  147. GetParticle().SetParticleParam(EmitorParam.BIRTH_RATE, 0);
  148. GetParticle().SetParticleParam(EmitorParam.BIRTH_RATE_RND, 0);
  149. Stop();
  150. };
  151. return;
  152. }
  153. super.Update(timeSlice);
  154. Particle ptc = GetParticle();
  155. float speed = m_Boat.PropellerGetAngularVelocity();
  156. UpdateSpeedState(ptc, speed);
  157. float lerp = Math.InverseLerp(0, m_SpeedFast, speed);
  158. for (int i = 0; i < m_EmitorCount; i++)
  159. {
  160. if (i < EMITORS_FAST && m_SpeedState > EBoatSpeed.SLOW)
  161. {
  162. ptc.SetParameter(i, EmitorParam.SIZE, ptc.GetParameterOriginal(i, EmitorParam.SIZE) * lerp);
  163. ptc.SetParameter(i, EmitorParam.BIRTH_RATE, ptc.GetParameterOriginal(i, EmitorParam.BIRTH_RATE) * lerp);
  164. }
  165. }
  166. }
  167. }
  168. class EffectBoatWaterSide : EffectBoatWaterBase
  169. {
  170. protected const int EMITORS_FAST = 3; // emitors below this ID only play when fast enough
  171. void EffectBoatWaterSide()
  172. {
  173. m_EmitorCount = 5;
  174. m_SpeedSlow = 5;
  175. m_SpeedMedium = 20;
  176. m_SpeedFast = 40;
  177. SetParticleState( ParticleList.BOAT_WATER_SIDE );
  178. }
  179. override protected void UpdateSpeedState(Particle ptc, float speed)
  180. {
  181. EBoatSpeed speedStatePast = m_SpeedState;
  182. if (speed > m_SpeedFast)
  183. m_SpeedState = EBoatSpeed.FAST;
  184. else if (speed > m_SpeedMedium)
  185. m_SpeedState = EBoatSpeed.MEDIUM;
  186. else if (speed > m_SpeedSlow)
  187. m_SpeedState = EBoatSpeed.SLOW;
  188. else
  189. m_SpeedState = EBoatSpeed.SLOWEST;
  190. if (m_SpeedState == speedStatePast)
  191. return;
  192. for (int i = 0; i < m_EmitorCount; i++)
  193. {
  194. if (i < EMITORS_FAST) // splashes
  195. {
  196. if (m_SpeedState <= EBoatSpeed.SLOW)
  197. EnableEmitor(ptc, i, false);
  198. else
  199. EnableEmitor(ptc, i, true);
  200. }
  201. }
  202. }
  203. override void Update(float timeSlice = 0)
  204. {
  205. super.Update(timeSlice);
  206. Particle ptc = GetParticle();
  207. vector velocity = dBodyGetVelocityAt(m_Boat, m_Boat.CoordToParent(GetLocalPosition()));
  208. float speed = velocity.Normalize() * 3.6; // to km/h
  209. UpdateSpeedState(ptc, speed);
  210. UpdatePosToSeaLevel(timeSlice, -0.2);
  211. float lerp = Math.InverseLerp(0, m_SpeedFast, speed);
  212. for (int i = 0; i < m_EmitorCount; i++)
  213. {
  214. if (i < EMITORS_FAST) // splashes
  215. {
  216. if (m_SpeedState > EBoatSpeed.SLOW)
  217. ptc.SetParameter(i, EmitorParam.SIZE, ptc.GetParameterOriginal(i, EmitorParam.SIZE) * lerp);
  218. }
  219. else // waves
  220. {
  221. ptc.SetParameter(i, EmitorParam.SIZE, ptc.GetParameterOriginal(i, EmitorParam.SIZE) * lerp);
  222. ptc.SetParameter(i, EmitorParam.VELOCITY, ptc.GetParameterOriginal(i, EmitorParam.VELOCITY) * lerp);
  223. }
  224. }
  225. }
  226. }
  227. class EffectBoatWaterBase : EffectParticle
  228. {
  229. const float POS_UPDATE_THROTTLE = 0.2; // seconds, controls how often can boat update somewhat expensive particle local reposition
  230. protected int m_EmitorCount;
  231. protected int m_SpeedSlow;
  232. protected int m_SpeedMedium;
  233. protected int m_SpeedFast;
  234. protected float m_PosUpdateTimer;
  235. protected EBoatSpeed m_SpeedState;
  236. protected BoatScript m_Boat;
  237. protected vector m_MemPointPos;
  238. override void AttachTo(Object obj, vector local_pos = "0 0 0", vector local_ori = "0 0 0", bool force_rotation_to_world = false)
  239. {
  240. m_Boat = BoatScript.Cast(obj);
  241. m_MemPointPos = local_pos;
  242. super.AttachTo(obj, local_pos, local_ori, force_rotation_to_world);
  243. }
  244. void SetParticleState(int state)
  245. {
  246. bool was_playing = IsPlaying();
  247. Stop();
  248. SetParticleID(state);
  249. if (was_playing)
  250. {
  251. Start(); // resume effect
  252. }
  253. }
  254. protected void EnableEmitor(Particle ptc, int id, bool enable)
  255. {
  256. if (enable)
  257. {
  258. ptc.SetParameter(id, EmitorParam.BIRTH_RATE, ptc.GetParameterOriginal(id, EmitorParam.BIRTH_RATE));
  259. ptc.SetParameter(id, EmitorParam.BIRTH_RATE_RND, ptc.GetParameterOriginal(id, EmitorParam.BIRTH_RATE_RND));
  260. }
  261. else
  262. {
  263. ptc.SetParameter(id, EmitorParam.BIRTH_RATE, 0);
  264. ptc.SetParameter(id, EmitorParam.BIRTH_RATE_RND, 0);
  265. }
  266. }
  267. // Update on state change
  268. protected void UpdateSpeedState(Particle ptc, float speed)
  269. {}
  270. // Update runs every frame
  271. void Update(float timeSlice = 0)
  272. {
  273. if (!IsPlaying())
  274. {
  275. m_SpeedState = EBoatSpeed.UNSET; // reinit
  276. Start();
  277. }
  278. };
  279. // Adjust position to sea level
  280. protected void UpdatePosToSeaLevel(float timeSlice = 0, float surfaceOffset = 0)
  281. {
  282. m_PosUpdateTimer += timeSlice;
  283. if (m_PosUpdateTimer > POS_UPDATE_THROTTLE)
  284. {
  285. m_PosUpdateTimer = 0;
  286. vector posAdjusted = m_Boat.CoordToParent(m_MemPointPos);
  287. posAdjusted[1] = GetGame().SurfaceGetSeaLevel() + surfaceOffset;
  288. posAdjusted = m_Boat.CoordToLocal(posAdjusted);
  289. SetCurrentLocalPosition(posAdjusted);
  290. }
  291. }
  292. }