fireworks.script 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. local colors = {"red", "green", "blue"} -- list of existing fireworks colors
  2. local instances = {} -- list of active fireworks instances
  3. local _tension = 0.9 -- emulation of air tension. More value leads to faster deceleration
  4. local _gravity = 980 -- gravity, measuring in mm/sq.s.
  5. local function start_fireworks(trail_id, bang_id, start_pos, speed, time, gravity, tension)
  6. go.set_position(start_pos, trail_id)
  7. particlefx.play(trail_id)
  8. local m = {
  9. update = function(self, dt)
  10. if self.time > 0 then
  11. local prev_pos = vmath.vector3(self.start_pos)
  12. self.start_pos.x = self.start_pos.x + self.speed.x*dt
  13. self.start_pos.y = self.start_pos.y + self.speed.y*dt
  14. local triangle = vmath.vector3(prev_pos.x - start_pos.x, prev_pos.y - start_pos.y, 0)
  15. local angle = math.atan2(triangle.y, triangle.x)
  16. self.speed.x = self.speed.x - self.speed.x * self.tension*dt
  17. self.speed.y = self.speed.y - self.speed.y * self.tension*dt - self.gravity*dt
  18. go.set_position(self.start_pos, self.trail)
  19. go.set_rotation(vmath.quat_rotation_z(angle+math.pi/2), self.trail)
  20. if self.time > 0 then
  21. go.set_scale(self.time, self.trail)
  22. end
  23. elseif self.time <= 0 and not self.is_stopped then
  24. self.is_stopped = true
  25. particlefx.stop(self.trail, { clear = true })
  26. go.set_position(self.start_pos, self.bang)
  27. particlefx.play(self.bang)
  28. elseif self.time <= -1.5 and self.bang then
  29. go.delete(self.bang)
  30. self.bang = nil
  31. end
  32. self.time = self.time - dt
  33. end,
  34. start_pos = start_pos,
  35. time = time,
  36. speed = speed,
  37. gravity = gravity or _gravity,
  38. tension = tension or _tension,
  39. trail = trail_id,
  40. bang = bang_id
  41. }
  42. return m
  43. end
  44. local function single_shot()
  45. if #instances > 5 then
  46. return
  47. end
  48. local color = colors[math.random(1, #colors)]
  49. local splat = factory.create("#"..color.."_splat_factory")
  50. local trail = factory.create("#"..color.."_trail_factory")
  51. local strength = 1000+math.random()*600 -- scalar value of speed
  52. local angle = (-0.2+math.random()*0.4)*math.pi -- angle beetween central vertical line and trail
  53. local pos = vmath.vector3(360-math.sin(angle)*350, 0, 0)
  54. local speed = vmath.vector3(strength*math.sin(angle), strength*math.cos(angle), 0)
  55. table.insert(instances,
  56. start_fireworks(trail, splat,
  57. pos, speed,
  58. 1.2+math.random()*0.5
  59. )
  60. )
  61. end
  62. function init(self)
  63. single_shot()
  64. timer.delay(3, true, single_shot)
  65. msg.post(".", "acquire_input_focus")
  66. end
  67. function update(self, dt)
  68. for i, val in ipairs(instances) do
  69. if not val.bang then
  70. table.remove(instances, i)
  71. else
  72. val:update(dt)
  73. end
  74. end
  75. end
  76. function on_input(self, action_id, action)
  77. if action_id == hash("mouse_button_left") and action.pressed then
  78. single_shot()
  79. end
  80. end