return function(feesh, dt, food, headerbuttons, money) for fi, n in ipairs(feesh) do bench.startBenchmark('update_fish_eases') for _, e in ipairs(n.eases) do e.a = e.a + dt * e.speed end for i, e in ipairs(n.eases) do if e.a > 1 then local sumx = 0 local sumy = 0 for i2, e2 in ipairs(n.eases) do if i ~= i2 then sumx = sumx + mix(e2.fromx, e2.x, FISH_EASE(math.min(e2.a, 1))) sumy = sumy + mix(e2.fromy, e2.y, FISH_EASE(math.min(e2.a, 1))) end end sumx = sumx + e.x sumy = sumy + e.y n.x = sumx / #n.eases n.y = sumy / #n.eases e.fromx = e.x e.fromy = e.y e.a = e.a - 1 local angle = math.random(-FISH_ANGLE, FISH_ANGLE) local str = math.random(70, 200)/200/4 angle = mix(angle, math.deg(math.atan2((0.5 + math.sin(love.timer.getTime()/10 + fi) * 0.2) - n.y, 0)), 0.1) -- slightly head towards the middle, to prevent getting stuck at the bottom or top local followingObj = (n.shortestfood and food[n.shortestfood] and n.size ~= 4) or (n.shortestfood and feesh[n.shortestfood] and n.size == 4) if n.eattimer <= 0 and not n.dead then -- needs to follow something local mx, my if n.eattimer <= 0 then if n.size == 4 then -- carnivore if n.shortestfood and feesh[n.shortestfood] then local f = feesh[n.shortestfood] mx, my = f.x, f.y elseif frame % FISH_FOOD_CHECK_FREQ == 0 then local minfood = 0 local mindist = 9e9 for i,f in ipairs(feesh) do if f.size == 0 then local dist = math.sqrt(math.pow(math.abs(f.render.x - n.render.x), 2) + math.pow(math.abs(f.render.y - n.render.y), 2)) if dist < mindist then mindist = dist minfood = i end end end if minfood ~= 0 then n.shortestfood = minfood end end else if n.shortestfood and food[n.shortestfood] then local f = food[n.shortestfood] mx, my = f.x, f.y elseif frame % FISH_FOOD_CHECK_FREQ == 0 then local minfood = 0 local mindist = 9e9 for i,f in ipairs(food) do local dist = math.sqrt(math.pow(math.abs(f.x - n.render.x), 2) + math.pow(math.abs(f.y - n.render.y), 2)) if dist < mindist then mindist = dist minfood = i end end if minfood ~= 0 then n.shortestfood = minfood end end end end if mx and my then angle = math.deg(math.atan2(my - n.y, mx - n.x)) + math.random(-FISH_FOLLOW_RANDOM, FISH_FOLLOW_RANDOM) str = math.random(70, 200)/200/8 end end local x = math.cos(math.rad(angle)) * str local y = math.sin(math.rad(angle)) * str if not (followingObj or n.dead) then x = x * math.sign(n.render.x - n.render.prevx) end e.x = n.x + x e.y = n.y + y e.x = 1 - math.abs(e.x%2-1) e.y = 1 - math.abs(e.y%2-1) local fheight = (HEADER_HEIGHT * love.graphics.getWidth()/640)/love.graphics.getHeight() if e.y < fheight then e.y = e.y + (fheight - e.y) * 2 end e.speed = 1 / (math.sqrt(math.pow(math.abs(e.x - e.fromx), 2) + math.pow(math.abs(e.y - e.fromy), 2))/2) / 15 if n.eattimer < FISH_FOOD_HUNGRY or followingObj then e.speed = e.speed * 1.3 if n.size == 4 then e.speed = e.speed * 1.1 end end if n.dead then e.speed = e.speed * 0.2 end end end bench.stopBenchmark('update_fish_eases') bench.startBenchmark('update_fish_position') n.x = clamp(n.x, 0, 1) n.y = clamp(n.y, 0, 0.5) n.lifetime = n.lifetime + dt n.eattimer = n.eattimer - dt n.moneytimer = n.moneytimer - dt if n.moneytimer < 0 and not n.dead then n.moneytimer = n.moneytimer + math.random() * 5 + 5 if n.size > 0 then local type = 2 if n.size == 1 then type = 1 end if n.size == 3 then type = 3 end if n.size == 4 then type = 4 end if n.star then type = 3 end table.insert(money, constr.money(n.render.x, n.render.y, type)) end end local sumx = 0 local sumy = 0 for _, e2 in ipairs(n.eases) do sumx = sumx + mix(e2.fromx, e2.x, FISH_EASE(e2.a)) sumy = sumy + mix(e2.fromy, e2.y, FISH_EASE(e2.a)) end n.render.prevx = n.render.x n.render.prevy = n.render.y n.render.x = sumx / #n.eases n.render.y = sumy / #n.eases n.render.x = clamp(n.render.x, 0.05, 0.95) n.render.y = clamp(n.render.y, 0.1, 0.85) bench.stopBenchmark('update_fish_position') bench.startBenchmark('update_fish_colission') if n.size == 4 then if n.shortestfood and feesh[n.shortestfood] and frame % FISH_COLISSION_CHECK_FREQ == 0 and not n.dead then local f = feesh[n.shortestfood] local dist = math.abs(n.render.x - f.render.x) + math.abs(n.render.y - f.render.y) if dist < FOOD_HITBOX then playSound('chomp', 1, 1 + math.random() * 0.1 - 0.05) table.remove(feesh, n.shortestfood) n.eattimer = FISH_FOOD_3_COOLDOWN n.render.eattimer = 0 n.shortestfood = -1 end end else if n.shortestfood and food[n.shortestfood] and frame % FISH_COLISSION_CHECK_FREQ == 0 and not n.dead then local f = food[n.shortestfood] local dist = math.abs(n.render.x - f.x) + math.abs(n.render.y - f.y) if dist < FOOD_HITBOX then playSound('slurp', 1, 1 + math.random() * 0.1 - 0.05) table.remove(food, n.shortestfood) local cooldowns = {FISH_FOOD_1_COOLDOWN, FISH_FOOD_2_COOLDOWN, FISH_FOOD_3_COOLDOWN} n.eattimer = cooldowns[f.type] or FISH_FOOD_3_COOLDOWN n.render.eattimer = 0 n.shortestfood = -1 if f.type == 4 then -- star potion if n.size == 2 or n.size == 3 then n.star = true else n.eattimer = FISH_FOOD_DEAD playSound('explode') end else if n.lifetime > FISH_AGE_MEDIUM and n.size == 0 then n.size = 1 playSound('grow') if not headerbuttons[1].open and not headerbuttons[1].closed then headerbuttons[1].open = true headerbuttons[1].openanim = 0 end end if n.lifetime > FISH_AGE_BIG and n.size == 1 then n.size = 2 playSound('grow') if not headerbuttons[2].open and not headerbuttons[2].closed then headerbuttons[2].open = true headerbuttons[2].openanim = 0 end if not headerbuttons[3].open and not headerbuttons[3].closed then headerbuttons[3].open = true headerbuttons[3].openanim = 0 end if not headerbuttons[4].open and not headerbuttons[4].closed then headerbuttons[4].open = true headerbuttons[4].openanim = 0 end end if n.lifetime > FISH_AGE_KING and n.size == 2 then n.size = 3 playSound('grow') end end end end end bench.stopBenchmark('update_fish_colission') bench.startBenchmark('update_fish_render') if frame % FISH_RENDER_FREQ == 0 then local dt = dt * FISH_RENDER_FREQ local iter = FISH_RENDER_ITERS local iteroff = FISH_RENDER_ITEROFF local xspeed = {} local yspeed = {} local angle = {} local sumxiter = {} local sumyiter = {} for i = 1, iter do local off = i * iteroff local sumx2 = 0 local sumy2 = 0 for _, e2 in ipairs(n.eases) do sumx2 = sumx2 + mix(e2.fromx, e2.x, FISH_EASE(e2.a + off)) sumy2 = sumy2 + mix(e2.fromy, e2.y, FISH_EASE(e2.a + off)) end table.insert(xspeed, (sumx2 - (sumxiter[i - 1] or sumx)) / #n.eases) table.insert(yspeed, (sumy2 - (sumyiter[i - 1] or sumy)) / #n.eases) table.insert(angle, math.atan2(sumy2 - (sumyiter[i - 1] or sumy), sumx2 - (sumxiter[i - 1] or sumx))) table.insert(sumxiter, sumx2) table.insert(sumyiter, sumy2) end n.render.xspeed = sum(xspeed) n.render.yspeed = sum(yspeed) n.render.angle = sum(angle) end n.render.turn = n.render.turn + dt * math.sign(n.render.x - n.render.prevx) * 2 n.render.turn = clamp(n.render.turn, 0, 1) if n.render.turn == 0 or n.render.turn == 1 then n.render.swim = (n.render.swim + dt * (math.abs(n.render.xspeed) * 250 + 0.5)) % 1 else n.render.swim = 0 end n.render.eattimer = n.render.eattimer + dt * 3 if n.render.eattimer < 1 then n.render.swim = 0 end if not n.dead then n.render.turndir = math.sign(n.render.x - n.render.prevx) end local m = n.eattimer < FISH_FOOD_HUNGRY and 1 or -1 n.render.hungry = clamp(n.render.hungry + dt * m * 3, 0, 1) bench.stopBenchmark('update_fish_render') if n.eattimer <= FISH_FOOD_DEAD and not n.dead then playSound('die') end if n.eattimer <= FISH_FOOD_DEAD then n.dead = true local timeSinceDead = math.abs(n.eattimer - FISH_FOOD_DEAD) n.render.y = n.render.y + timeSinceDead/5 * math.min(timeSinceDead, 1) n.render.y = clamp(n.render.y, 0, 0.85) if n.render.y == 0.85 then n.render.deathanim = n.render.deathanim + dt if n.render.deathanim > 1 then table.remove(feesh, fi) end end end end end