Advertisement
Guest User

Codea - Particle Engine

a guest
Dec 26th, 2016
236
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.94 KB | None | 0 0
  1. ParticleSim = class()
  2.  
  3. function ParticleSim:init()
  4.     self.particles = {}
  5.     self.types = {}
  6.     self.pEllipses = {}
  7.     self.spawnerTypes = {
  8.     "touch_began",
  9.     "touch_move",
  10.     "touch_ended",
  11.     "loop_random_pos",
  12.     "loop_set_pos",
  13.     "chance_random_pos",
  14.     "chance_set_pos"
  15.     }
  16.     self.behaviorTypes = {
  17.     "timeout",
  18.     "chance_timeout",
  19.     "spawn_particle",
  20.     "chance_spawn_particle",
  21.     "loop_spawn_particle",
  22.     "wander",
  23.     "move_straight",
  24.     "gravity",
  25.     "timeout_radius",
  26.     "loop_change_direction",
  27.     "chance_change_direction",
  28.     "init_velocity"
  29.     }
  30.     self.timer = 0
  31.     self.remove = {}
  32. end
  33.  
  34. function ParticleSim:newType(name)
  35.     if self.types[name] == nil then
  36.         self.types[name] = {
  37.         ["drawLayers"] = {},
  38.         ["spawners"] = {},
  39.         ["slowdown"] = 0.9,
  40.         ["behaviors"] = {
  41.         ["default"] = {},
  42.         ["spawn"] = {},
  43.         ["duplicate"] = {},
  44.         ["despawn"] = {}
  45.         }
  46.         }
  47.     end
  48. end
  49.  
  50. function ParticleSim:setSlowdown(t, s)
  51.     self:newType(t)
  52.     self.types[t]["slowdown"] = s
  53. end
  54.  
  55. function ParticleSim:addDrawLayer(name, col, size, layer, cVariation, sVariation)
  56.     self:newType(name)
  57.     local cv = 0
  58.     if cVariation ~= nil then
  59.         cv = cVariation
  60.     end
  61.     local sv = 0
  62.     if sVariation ~= nil then
  63.         sv = sVariation
  64.     end
  65.     table.insert(self.types[name]["drawLayers"], {col, size, layer, cv, sv})
  66. end
  67.  
  68. function ParticleSim:addSpawner(name, spawner, params)
  69.     self:newType(name)
  70.     local isValid = false
  71.     for k, v in pairs(self.spawnerTypes) do
  72.         if v == spawner then
  73.             isValid = true
  74.         end
  75.     end
  76.     if isValid then
  77.         table.insert(self.types[name]["spawners"], {[spawner] = params})
  78.     end
  79. end
  80.  
  81. function ParticleSim:addBehavior(name, behavior, params, trigger)
  82.     self:newType(name)
  83.     local isValid = false
  84.     for k, v in pairs(self.behaviorTypes) do
  85.         if v == behavior then
  86.             isValid = true
  87.         end
  88.     end
  89.     local t
  90.     if trigger ~= "spawn" and trigger ~= "duplicate" and trigger ~= "despawn" then
  91.         t = "default"
  92.     else
  93.         t = trigger
  94.     end
  95.     if isValid then
  96.         table.insert(self.types[name]["behaviors"][t], {[behavior] = params})
  97.     end
  98. end
  99.  
  100. function ParticleSim:doSpawners()
  101.     for t, d in pairs(self.types) do
  102.         for bn, tb in pairs(d["spawners"]) do
  103.             -- Touch began
  104.             if tb["touch_began"] ~= nil then
  105.                 if CurrentTouch.state == BEGAN then
  106.                     self:addParticle(t, CurrentTouch.x, CurrentTouch.y, 0, 0)
  107.                 end
  108.             end
  109.             -- Touch moved
  110.             if tb["touch_move"] ~= nil then
  111.                 if CurrentTouch.state == MOVING then
  112.                     self:addParticle(t, CurrentTouch.x, CurrentTouch.y, 0, 0)
  113.                 end
  114.             end
  115.             -- Touch ended
  116.             if tb["touch_ended"] ~= nil then
  117.                 if CurrentTouch.state == ENDED then
  118.                     self:addParticle(t, CurrentTouch.x, CurrentTouch.y, 0, 0)
  119.                 end
  120.             end
  121.             -- Loop at random postion
  122.             if tb["loop_random_pos"] ~= nil then
  123.                 if tb["loop_random_pos"]["time"] == nil then
  124.                     tb["loop_random_pos"]["time"] = 20
  125.                 end
  126.                 if self.timer % tb["loop_random_pos"]["time"] == 0 then
  127.                     self:addParticle(t, math.random(0, WIDTH), math.random(0, HEIGHT), 0, 0)
  128.                 end
  129.             end
  130.             -- Loop at set postion
  131.             if tb["loop_set_pos"] ~= nil then
  132.                 if tb["loop_set_pos"]["time"] == nil then
  133.                     tb["loop_set_pos"]["time"] = 20
  134.                 end
  135.                 if tb["loop_set_pos"]["x"] == nil then
  136.                     tb["loop_set_pos"]["x"] = WIDTH / 2
  137.                 end
  138.                 if tb["loop_set_pos"]["y"] == nil then
  139.                     tb["loop_set_pos"]["y"] = HEIGHT / 2
  140.                 end
  141.                 if self.timer % tb["loop_set_pos"]["time"] == 0 then
  142.                     self:addParticle(t, tb["loop_set_pos"]["x"], tb["loop_set_pos"]["y"], 0, 0)
  143.                 end
  144.             end
  145.             -- Random chance at random postion
  146.             if tb["chance_random_pos"] ~= nil then
  147.                 if tb["chance_random_pos"]["chance"] == nil then
  148.                     tb["chance_random_pos"]["chance"] = 15
  149.                 end
  150.                 if math.random(1, tb["chance_random_pos"]["chance"]) == 1 then
  151.                     self:addParticle(t, math.random(0, WIDTH), math.random(0, HEIGHT), 0, 0)
  152.                 end
  153.             end
  154.             -- Random chance at set postion
  155.             if tb["chance_set_pos"] ~= nil then
  156.                 if tb["chance_set_pos"]["chance"] == nil then
  157.                     tb["chance_set_pos"]["chance"] = 15
  158.                 end
  159.                 if tb["chance_set_pos"]["x"] == nil then
  160.                     tb["chance_set_pos"]["x"] = WIDTH / 2
  161.                 end
  162.                 if tb["chance_set_pos"]["y"] == nil then
  163.                     tb["chance_set_pos"]["y"] = HEIGHT / 2
  164.                 end
  165.                 if math.random(1, tb["chance_set_pos"]["chance"]) == 1 then
  166.                     self:addParticle(t, tb["chance_set_pos"]["x"], tb["chance_set_pos"]["y"], 0, 0)
  167.                 end
  168.             end
  169.         end
  170.     end
  171. end
  172.  
  173. function ParticleSim:addParticle(t, x, y, xv, yv)
  174.     local isValid = false
  175.     for k, v in pairs(self.types) do
  176.         if k == t then
  177.             isValid = true
  178.         end
  179.     end
  180.     if isValid then
  181.         local va = {}
  182.         for k, v in pairs(self.types[t]["drawLayers"]) do
  183.             local c = v[4]
  184.             local s = v[5]
  185.             table.insert(va, {math.random(-s, s), math.random(-c, c), math.random(-c, c), math.random(-c, c), math.random(-c, c)})
  186.         end
  187.         table.insert(self.particles, {
  188.         ["type"] = t,
  189.         ["pos"] = vec2(x, y),
  190.         ["vel"] = vec2(xv, yv),
  191.         ["data"] = self:copyTWithRandomizers(self.types[t]),
  192.         ["var"] = self:copyT(va)
  193.         })
  194.     end
  195. end
  196.  
  197. function ParticleSim:getPEllipses()
  198.     for _, p in pairs(self.particles) do
  199.         local pes = p["data"]["drawLayers"]
  200.         for k, pe in pairs(pes) do
  201.             local c = color(pe[1].r, pe[1].g, pe[1].b, pe[1].a)
  202.             c.r = c.r + p["var"][k][2]
  203.             c.g = c.g + p["var"][k][3]
  204.             c.b = c.b + p["var"][k][4]
  205.             c.a = c.a + p["var"][k][5]
  206.             self:addPEllipse(p["pos"], c, pe[2] + p["var"][k][1], pe[3])
  207.         end
  208.     end
  209. end
  210.  
  211. function ParticleSim:addPEllipse(pos, col, size, layer)
  212.     if self.pEllipses[layer] == nil then
  213.         self.pEllipses[layer] = {}
  214.     end
  215.     table.insert(self.pEllipses[layer], {pos, col, size})
  216. end
  217.  
  218. function ParticleSim:drawPEllipses()
  219.     self.pEllipses = {}
  220.     self:getPEllipses()
  221.     if self.pEllipses ~= {} then
  222.         local min = 9999
  223.         while min < 1000000000000 do
  224.             min = 1000000000000
  225.             for k, v in pairs(self.pEllipses) do
  226.                 if k < min then
  227.                     min = k
  228.                 end
  229.             end
  230.             if self.pEllipses[min] ~= nil then
  231.                 for _, v in pairs(self.pEllipses[min]) do
  232.                     pushStyle()
  233.                     fill(v[2])
  234.                     noStroke()
  235.                     ellipse(v[1].x, v[1].y, v[3], v[3])
  236.                     popStyle()
  237.                 end
  238.             end
  239.             self.pEllipses[min] = nil
  240.         end
  241.     end
  242. end
  243.  
  244. function ParticleSim:pBehavior(i, t, tri)
  245.     local d = self.particles[i]
  246.     for bn, tb in pairs(self.particles[i]["data"]["behaviors"][t]) do
  247.         if tri then
  248.             if d["spawnTimer"] == nil then
  249.                 d["spawnTimer"] = 0
  250.             else
  251.                 d["spawnTimer"] = d["spawnTimer"] + 1
  252.             end
  253.             if d["spawnTimer"] <= 1 then
  254.                 if tri then
  255.                     self:pBehavior(i, "spawn", false)
  256.                 end
  257.             end
  258.         end
  259.         -- Delete particles after a set amount of time
  260.         if tb["timeout"] ~= nil then
  261.             if tb["timeout"]["currentTime"] == nil then
  262.                 tb["timeout"]["currentTime"] = 0
  263.             else
  264.                 tb["timeout"]["currentTime"] = tb["timeout"]["currentTime"] + 1
  265.             end
  266.             if tb["timeout"]["time"] == nil then
  267.                 tb["timeout"]["time"] = 120
  268.             end
  269.             if tb["timeout"]["currentTime"] == tb["timeout"]["time"] then
  270.                 table.insert(self.remove, i)
  271.                 if tri then
  272.                     self:pBehavior(i, "despawn", false)
  273.                 end
  274.             end
  275.         end
  276.         -- Delete particles at random each frame
  277.         if tb["chance_timeout"] ~= nil then
  278.             if tb["chance_timeout"]["chance"] == nil then
  279.                 tb["chance_timeout"]["chance"] = 100
  280.             end
  281.             if math.random(1, tb["chance_timeout"]["chance"]) == 1 then
  282.                 table.insert(self.remove, i)
  283.                 if tri then
  284.                     self:pBehavior(i, "despawn", false)
  285.                 end
  286.             end
  287.         end
  288.         -- Spawn particles from other particles
  289.         if tb["spawn_particle"] ~= nil then
  290.             if tb["spawn_particle"]["type"] == nil then
  291.                 tb["spawn_particle"]["type"] = d["type"]
  292.             end
  293.             if tb["spawn_particle"]["time"] == nil then
  294.                 tb["spawn_particle"]["time"] = 100
  295.             end
  296.             if tb["spawn_particle"]["currentTime"] == nil then
  297.                 tb["spawn_particle"]["currentTime"] = 0
  298.             else
  299.                 tb["spawn_particle"]["currentTime"] = tb["spawn_particle"]["currentTime"] + 1
  300.             end
  301.             if tb["spawn_particle"]["amount"] == nil then
  302.                 tb["spawn_particle"]["amount"] = 1
  303.             end
  304.             if tb["spawn_particle"]["currentTime"] == tb["spawn_particle"]["time"] then
  305.                 for i = 1, tb["spawn_particle"]["amount"] do
  306.                     self:addParticle(tb["spawn_particle"]["type"], d["pos"].x, d["pos"].y, d["vel"].x, d["vel"].y)
  307.                 end
  308.                 if tri then
  309.                     self:pBehavior(i, "duplicate", false)
  310.                 end
  311.             end
  312.         end
  313.         -- Spawn particles from other particles with a chance
  314.         if tb["chance_spawn_particle"] ~= nil then
  315.             if tb["chance_spawn_particle"]["type"] == nil then
  316.                 tb["chance_spawn_particle"]["type"] = d["type"]
  317.             end
  318.             if tb["chance_spawn_particle"]["chance"] == nil then
  319.                 tb["chance_spawn_particle"]["chance"] = 50
  320.             end
  321.             if tb["chance_spawn_particle"]["amount"] == nil then
  322.                 tb["chance_spawn_particle"]["amount"] = 1
  323.             end
  324.             if math.random(1, tb["chance_spawn_particle"]["chance"]) == 1 then
  325.                 for i = 1, tb["chance_spawn_particle"]["amount"] do
  326.                     self:addParticle(tb["chance_spawn_particle"]["type"], d["pos"].x, d["pos"].y, d["vel"].x, d["vel"].y)
  327.                 end
  328.                 if tri then
  329.                     self:pBehavior(i, "duplicate", false)
  330.                 end
  331.             end
  332.         end
  333.         -- Spawn particles from other particles on an interval
  334.         if tb["loop_spawn_particle"] ~= nil then
  335.             if tb["loop_spawn_particle"]["type"] == nil then
  336.                 tb["loop_spawn_particle"]["type"] = d["type"]
  337.             end
  338.             if tb["loop_spawn_particle"]["time"] == nil then
  339.                 tb["loop_spawn_particle"]["time"] = 50
  340.             end
  341.             if tb["loop_spawn_particle"]["currentTime"] == nil then
  342.                 tb["loop_spawn_particle"]["currentTime"] = 1
  343.             else
  344.                 tb["loop_spawn_particle"]["currentTime"] = tb["loop_spawn_particle"]["currentTime"] + 1
  345.             end
  346.             if tb["loop_spawn_particle"]["amount"] == nil then
  347.                 tb["loop_spawn_particle"]["amount"] = 1
  348.             end
  349.             if tb["loop_spawn_particle"]["currentTime"] % tb["loop_spawn_particle"]["time"] == 0 then
  350.                 for i = 1, tb["loop_spawn_particle"]["amount"] do
  351.                     self:addParticle(tb["loop_spawn_particle"]["type"], d["pos"].x, d["pos"].y, d["vel"].x, d["vel"].y)
  352.                 end
  353.                 if tri then
  354.                     self:pBehavior(i, "duplicate", false)
  355.                 end
  356.             end
  357.         end
  358.         -- Move around randomly
  359.         if tb["wander"] ~= nil then
  360.             if tb["wander"]["amount"] == nil then
  361.                 tb["wander"]["amount"] = 2
  362.             end
  363.             local move = vec2(tb["wander"]["amount"], 0)
  364.             move = move:rotate(math.rad(math.random(0, 359)))
  365.             d["vel"] = d["vel"] + move
  366.         end
  367.         -- Move in a straight line
  368.         if tb["move_straight"] ~= nil then
  369.             if tb["move_straight"]["dir"] == nil then
  370.                 tb["move_straight"]["dir"] = 90
  371.             end
  372.             if tb["move_straight"]["speed"] == nil then
  373.                 tb["move_straight"]["speed"] = 2
  374.             end
  375.             local move = vec2(tb["move_straight"]["speed"], 0)
  376.             move = move:rotate(math.rad(tb["move_straight"]["dir"]))
  377.             d["vel"] = d["vel"] + move
  378.         end
  379.         -- Apply gravity
  380.         if tb["gravity"] ~= nil then
  381.             if tb["gravity"]["x"] == nil then
  382.                 tb["gravity"]["x"] = 0
  383.             end
  384.             if tb["gravity"]["y"] == nil then
  385.                 tb["gravity"]["y"] = -0.07
  386.             end
  387.             if tb["gravity"]["xv"] == nil then
  388.                 tb["gravity"]["xv"] = 0
  389.             else
  390.                 tb["gravity"]["xv"] = tb["gravity"]["xv"] + tb["gravity"]["x"]
  391.             end
  392.             if tb["gravity"]["yv"] == nil then
  393.                 tb["gravity"]["yv"] = 0
  394.             else
  395.                 tb["gravity"]["yv"] = tb["gravity"]["yv"] + tb["gravity"]["y"]
  396.             end
  397.             d["vel"] = d["vel"] + vec2(tb["gravity"]["xv"], tb["gravity"]["yv"])
  398.         end
  399.         -- Delete a particle if it goes too far from the center of the screen
  400.         if tb["timeout_radius"] ~= nil then
  401.             if tb["timeout_radius"]["radius"] == nil then
  402.                 tb["timeout_radius"]["radius"] = 750
  403.             end
  404.             if vec2(WIDTH / 2, HEIGHT / 2):dist(d["pos"]) > tb["timeout_radius"]["radius"] then
  405.                 table.insert(self.remove, i)
  406.                 if tri then
  407.                     self:pBehavior(i, "despawn", false)
  408.                 end
  409.             end
  410.         end
  411.         -- Have a particle change direction periodically
  412.         if tb["loop_change_direction"] ~= nil then
  413.             if tb["loop_change_direction"]["time"] == nil then
  414.                 tb["loop_change_direction"]["time"] = 30
  415.             end
  416.             if tb["loop_change_direction"]["currentTime"] == nil then
  417.                 tb["loop_change_direction"]["currentTime"] = 1
  418.             else
  419.                 tb["loop_change_direction"]["currentTime"] = tb["loop_change_direction"]["currentTime"] + 1
  420.             end
  421.             if tb["loop_change_direction"]["direction"] == nil then
  422.                 tb["loop_change_direction"]["direction"] = math.random(0, 359)
  423.             end
  424.             if tb["loop_change_direction"]["speed"] == nil then
  425.                 tb["loop_change_direction"]["speed"] = 0.5
  426.             end
  427.             if tb["loop_change_direction"]["currentTime"] % tb["loop_change_direction"]["time"] == 0 then
  428.                 tb["loop_change_direction"]["direction"] = math.random(0, 359)
  429.             end
  430.             local move = vec2(tb["loop_change_direction"]["speed"], 0)
  431.             move = move:rotate(math.rad(tb["loop_change_direction"]["direction"]))
  432.             d["vel"] = d["vel"] + move
  433.         end
  434.         -- Have a particle chance direction with a chance
  435.         if tb["chance_change_direction"] ~= nil then
  436.             if tb["chance_change_direction"]["chance"] == nil then
  437.                 tb["chance_change_direction"]["chance"] = 30
  438.             end
  439.             if tb["chance_change_direction"]["speed"] == nil then
  440.                 tb["chance_change_direction"]["speed"] = 0.5
  441.             end
  442.             if tb["chance_change_direction"]["direction"] == nil then
  443.                 tb["chance_change_direction"]["direction"] = math.random(0, 359)
  444.             end
  445.             if math.random(1, tb["chance_change_direction"]["chance"]) == 1 then
  446.                 tb["chance_change_direction"]["direction"] = math.random(0, 359)
  447.             end
  448.             local move = vec2(tb["chance_change_direction"]["speed"], 0)
  449.             move = move:rotate(math.rad(tb["chance_change_direction"]["direction"]))
  450.             d["vel"] = d["vel"] + move
  451.         end
  452.            
  453.         if tb["init_velocity"] ~= nil then
  454.             if tb["init_velocity"]["x"] == nil then
  455.                 tb["init_velocity"]["x"] = 0
  456.             end
  457.             if tb["init_velocity"]["y"] == nil then
  458.                 tb["init_velocity"]["y"] = 10
  459.             end
  460.             if tb["init_velocity"]["time"] == nil then
  461.                 tb["init_velocity"]["time"] = 0
  462.             else
  463.                 tb["init_velocity"]["time"] = tb["init_velocity"]["time"] + 1
  464.             end
  465.             if tb["init_velocity"]["time"] == 0 then
  466.                 d["vel"] = vec2(tb["init_velocity"]["x"], tb["init_velocity"]["y"])
  467.             end
  468.         end
  469.     end
  470.        
  471.     -- Do movement
  472.     d["vel"] = d["vel"] * self.types[d["type"]]["slowdown"]
  473.     d["pos"] = d["pos"] + d["vel"]
  474. end
  475.  
  476. function ParticleSim:doBehaviors()
  477.     self.remove = {}
  478.     for t, d in pairs(self.particles) do
  479.         self:pBehavior(t, "default", true)
  480.     end
  481.    
  482.     for k, v in pairs(self.remove) do
  483.         self.particles[v] = nil
  484.     end
  485. end
  486.  
  487. function ParticleSim:draw()
  488.     self.timer = self.timer + 1
  489.     self:doBehaviors()
  490.     self:doSpawners()
  491.     self:drawPEllipses()
  492. end
  493.  
  494. function ParticleSim:copyT(t)
  495.     local ret = {}
  496.    
  497.     for k, v in pairs(t) do
  498.         if type(v) == "table" then
  499.             ret[k] = self:copyT(v)
  500.         else
  501.             ret[k] = v
  502.         end
  503.     end
  504.    
  505.     return ret
  506. end
  507.  
  508. function ParticleSim:copyTWithRandomizers(t)
  509.     local ret = {}
  510.    
  511.     for k, v in pairs(t) do
  512.         if type(v) == "table" then
  513.             if #v == 2 and type(v[1]) == "number" and type(v[2]) == "number" then
  514.                 local mi, ma
  515.                 if v[1] > v[2] then
  516.                     mi = v[2]
  517.                     ma = v[1]
  518.                 else
  519.                     mi = v[1]
  520.                     ma = v[2]
  521.                 end
  522.                 ret[k] = math.random(mi * 1000, ma * 1000) / 1000
  523.             else
  524.                 ret[k] = self:copyTWithRandomizers(v)
  525.             end
  526.         else
  527.             ret[k] = v
  528.         end
  529.     end
  530.    
  531.     return ret
  532. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement