Compare commits
No commits in common. "436d5f0301abe88742d2ef6576ccc1d01bf2c85c" and "2744423cdadd10dea6e5252711aebfc3227da0cd" have entirely different histories.
436d5f0301
...
2744423cda
|
@ -1,5 +1,3 @@
|
|||
# notsanequarium
|
||||
|
||||
a remake/remaster of insaniquarium, the game published by popcap in 2004
|
||||
|
||||
launch like any other love2d game
|
Before Width: | Height: | Size: 500 KiB |
Before Width: | Height: | Size: 728 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 6 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 411 B |
Before Width: | Height: | Size: 430 B |
Before Width: | Height: | Size: 434 B |
Before Width: | Height: | Size: 628 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.2 KiB |
13
conf.lua
|
@ -1,13 +0,0 @@
|
|||
function love.conf(t)
|
||||
t.version = "11.1"
|
||||
t.release = false
|
||||
t.window.title = 'notsanequarium'
|
||||
t.window.resizable = true
|
||||
t.window.vsync = false
|
||||
t.window.minwidth = 640
|
||||
t.window.minheight = 480
|
||||
t.window.width = 640
|
||||
t.window.height = 480
|
||||
|
||||
-- t.window.msaa = 2
|
||||
end
|
28
const.lua
|
@ -1,28 +0,0 @@
|
|||
ease = require 'lib.ease'
|
||||
|
||||
FISH_SPLINE_QUALITY = 5 -- bigger number = more lag, smaller number = more noise
|
||||
FISH_RENDER_ITERS = 4 -- a bigger number allows for more smoother flipper movement and rotation, but is significantly laggier
|
||||
FISH_RENDER_ITEROFF = 0.025 -- should be 1/iters*0.1, lower numbers will make movement snappier and higher numbers will make it smoother but glitchier
|
||||
|
||||
FISH_RENDER_FREQ = 4 -- only update the quality renders once every x frames
|
||||
FISH_COLISSION_CHECK_FREQ = 2 -- how often to update the colission
|
||||
FISH_EASE = ease.inOutSine -- ease used for fish movement
|
||||
|
||||
FISH_ANGLE = 30 -- bigger angle allows for fish to swim further down/up at once
|
||||
FISH_FOLLOW_RANDOM = 10
|
||||
|
||||
FISH_FOOD_COOLDOWN = 10
|
||||
FISH_FOOD_HUNGRY = -5
|
||||
FISH_FOOD_DEAD = -15
|
||||
|
||||
FISH_AGE_MEDIUM = 25 -- the age, in seconds, needed for a guppy to become a medium guppy
|
||||
FISH_AGE_BIG = 65 -- see above, but for big
|
||||
|
||||
FISH_SIZE = 6 -- how many large guppies can you fit on the screen
|
||||
|
||||
FOOTER_HEIGHT = 68
|
||||
|
||||
FOOD_HITBOX = 0.05
|
||||
|
||||
DEBUG_FISH_PATH_SUBDIVISIONS = 50
|
||||
DEBUG_FISH_PREDICT_AMOUNT = 0.5
|
|
@ -1,60 +0,0 @@
|
|||
require 'const'
|
||||
|
||||
local self = {}
|
||||
|
||||
function self.fish(x, y)
|
||||
local fish = {
|
||||
x = x,
|
||||
y = y,
|
||||
size = 0, -- 0 for small, 1 for medium, 2 for big, 3 for king
|
||||
eattimer = 0 + math.random() * 2, -- starts out hungry, with a 2s delay
|
||||
|
||||
lifetime = 0,
|
||||
|
||||
eases = {
|
||||
|
||||
},
|
||||
render = {
|
||||
x = 0,
|
||||
y = 0,
|
||||
prevx = 0,
|
||||
prevy = 0,
|
||||
turn = 0,
|
||||
swim = 0,
|
||||
angle = 0,
|
||||
xspeed = 0,
|
||||
yspeed = 0,
|
||||
eattimer = 1,
|
||||
hungry = 0,
|
||||
}
|
||||
}
|
||||
|
||||
for i = 1, FISH_SPLINE_QUALITY do
|
||||
table.insert(fish.eases, { -- we insert a fake ease that ends instantly and just hope the update loop replaces it with a valid, random one
|
||||
x = x,
|
||||
y = y,
|
||||
fromx = x,
|
||||
fromy = y,
|
||||
a = 1,
|
||||
speed = 1
|
||||
})
|
||||
end
|
||||
|
||||
return fish
|
||||
end
|
||||
|
||||
function self.food(x, y, type)
|
||||
local food = {
|
||||
x = x,
|
||||
y = y,
|
||||
speed = 0.2,
|
||||
time = math.random(),
|
||||
deathtimer = 0,
|
||||
type = 1,
|
||||
goal = 0 -- assigns 0 as the fish so that hopefully the update loop replaces it with a valid, random one
|
||||
}
|
||||
|
||||
return food
|
||||
end
|
||||
|
||||
return self
|
|
@ -1,84 +0,0 @@
|
|||
local assets = {}
|
||||
|
||||
function assets.clear()
|
||||
print("ℹ️ clearing assets")
|
||||
|
||||
sprites = {}
|
||||
sound_path = {}
|
||||
music_path = {}
|
||||
end
|
||||
|
||||
function assets.load(base)
|
||||
print("ℹ️ loading " .. base)
|
||||
|
||||
assets.addSprites(base)
|
||||
print("✓ added sprites")
|
||||
|
||||
assets.addAudio(base)
|
||||
print("✓ added audio")
|
||||
end
|
||||
|
||||
function assets.addSprites(base, d)
|
||||
local dir = base.."/sprites"
|
||||
if d then
|
||||
dir = dir .. "/" .. d
|
||||
end
|
||||
local files = love.filesystem.getDirectoryItems(dir)
|
||||
for _,file in ipairs(files) do
|
||||
if string.sub(file, -4) == ".png" then
|
||||
local spritename = string.sub(file, 1, -5)
|
||||
local sprite = love.graphics.newImage(dir .. "/" .. file)
|
||||
if d then
|
||||
spritename = d .. "/" .. spritename
|
||||
end
|
||||
sprites[spritename] = sprite
|
||||
--print(colr.cyan("ℹ️ added sprite "..spritename))
|
||||
elseif love.filesystem.getInfo(dir .. "/" .. file).type == "directory" then
|
||||
--print(colr.cyan("ℹ️ found sprite dir: " .. file))
|
||||
local newdir = file
|
||||
if d then
|
||||
newdir = d .. "/" .. newdir
|
||||
end
|
||||
assets.addSprites(base, newdir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function assets.addAudio(base, d, type)
|
||||
local dir = base.."/audio"
|
||||
if d then
|
||||
dir = dir .. "/" .. d
|
||||
end
|
||||
local files = love.filesystem.getDirectoryItems(dir)
|
||||
for _,file in ipairs(files) do
|
||||
if love.filesystem.getInfo(dir .. "/" .. file).type == "directory" then
|
||||
local newdir = file
|
||||
if d then
|
||||
newdir = d .. "/" .. newdir
|
||||
end
|
||||
assets.addAudio(base, newdir, type or file)
|
||||
else
|
||||
local audioname = file
|
||||
if file:ends(".wav") then audioname = file:sub(1, -5) end
|
||||
if file:ends(".mp3") then audioname = file:sub(1, -5) end
|
||||
if file:ends(".ogg") then audioname = file:sub(1, -5) end
|
||||
if file:ends(".flac") then audioname = file:sub(1, -5) end
|
||||
if file:ends(".xm") then audioname = file:sub(1, -4) end
|
||||
--[[if d then
|
||||
audioname = d .. "/" .. audioname
|
||||
end]]
|
||||
if type == "sfx" then
|
||||
sound_path[audioname] = dir .. "/" .. file
|
||||
|
||||
if sounds and sounds[audioname] then
|
||||
registerSound(audioname, sounds[audioname].volume)
|
||||
end
|
||||
elseif type == "bgm" then
|
||||
music_path[audioname] = dir .. "/" .. file
|
||||
end
|
||||
--print("ℹ️ audio "..audioname.." added")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return assets
|
|
@ -1,88 +0,0 @@
|
|||
local this = {}
|
||||
|
||||
local updateLimit = 50
|
||||
|
||||
local benchmarkingThings = {}
|
||||
|
||||
local latestBenchmark = {}
|
||||
local doneBench = {}
|
||||
|
||||
local function shrt(num)
|
||||
return math.floor(num * 10000) / 10000
|
||||
end
|
||||
|
||||
this.update = function()
|
||||
doneBench = {}
|
||||
end
|
||||
|
||||
this.startBenchmark = function(name)
|
||||
latestBenchmark[name] = love.timer.getTime()
|
||||
end
|
||||
|
||||
this.stopBenchmark = function(name)
|
||||
if not benchmarkingThings[name] then benchmarkingThings[name] = {} end
|
||||
|
||||
if doneBench[name] then
|
||||
local tbl = benchmarkingThings[name]
|
||||
tbl[#tbl] = tbl[#tbl] + love.timer.getTime() - latestBenchmark[name]
|
||||
else
|
||||
table.insert(benchmarkingThings[name], love.timer.getTime() - latestBenchmark[name])
|
||||
end
|
||||
|
||||
doneBench[name] = true
|
||||
if #benchmarkingThings[name] > updateLimit then table.remove(benchmarkingThings[name], 1) end
|
||||
end
|
||||
|
||||
this.getAverage = function(name)
|
||||
local things
|
||||
if name then
|
||||
things = benchmarkingThings[name]
|
||||
else
|
||||
things = {}
|
||||
for key in pairs(this.benchmarks) do
|
||||
for _,n in ipairs(benchmarkingThings[key]) do
|
||||
table.insert(things, n)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local total = 0
|
||||
for _,n in ipairs(things) do
|
||||
total = total + n
|
||||
end
|
||||
|
||||
return total / #things
|
||||
end
|
||||
|
||||
this.renderBenchmark = function()
|
||||
local font = love.graphics.getFont()
|
||||
local result = ''
|
||||
local rowNum = 0
|
||||
|
||||
local averages = {}
|
||||
local max = 0
|
||||
|
||||
for n,_ in pairs(this.benchmarks) do
|
||||
local average = this.getAverage(n)
|
||||
max = math.max(average, max)
|
||||
averages[n] = average
|
||||
end
|
||||
for n,_ in pairs(this.benchmarks) do
|
||||
local average = averages[n]
|
||||
result = result .. '\n' .. shrt(average) .. 'ms' .. ' ' .. n
|
||||
rowNum = rowNum + 1
|
||||
|
||||
local yoff = rowNum * font:getHeight()
|
||||
|
||||
love.graphics.setColor(1, 1, 1, 0.7)
|
||||
|
||||
love.graphics.rectangle('fill', 0, yoff, average * 1/max * love.graphics.getWidth(), font:getHeight())
|
||||
end
|
||||
|
||||
love.graphics.setColor(0, 0, 0)
|
||||
love.graphics.print(result)
|
||||
end
|
||||
|
||||
this.benchmarks = benchmarkingThings
|
||||
|
||||
return this
|
140
lib/ease.lua
|
@ -1,140 +0,0 @@
|
|||
local this = {}
|
||||
|
||||
local sqrt = math.sqrt
|
||||
local sin = math.sin
|
||||
local cos = math.cos
|
||||
local pow = math.pow
|
||||
local exp = math.exp
|
||||
local pi = math.pi
|
||||
local abs = math.abs
|
||||
|
||||
function this.linear(t) return t end
|
||||
function this.inQuad(t) return t * t end
|
||||
function this.outQuad(t) return -t * (t - 2) end
|
||||
function this.inOutQuad(t)
|
||||
t = t * 2
|
||||
if t < 1 then
|
||||
return 0.5 * t ^ 2
|
||||
else
|
||||
return 1 - 0.5 * (2 - t) ^ 2
|
||||
end
|
||||
end
|
||||
function this.inCubic(t) return t * t * t end
|
||||
function this.outCubic(t) return 1 - (1 - t) ^ 3 end
|
||||
function this.inOutCubic(t)
|
||||
t = t * 2
|
||||
if t < 1 then
|
||||
return 0.5 * t ^ 3
|
||||
else
|
||||
return 1 - 0.5 * (2 - t) ^ 3
|
||||
end
|
||||
end
|
||||
function this.inQuart(t) return t * t * t * t end
|
||||
function this.outQuart(t) return 1 - (1 - t) ^ 4 end
|
||||
function this.inOutQuart(t)
|
||||
t = t * 2
|
||||
if t < 1 then
|
||||
return 0.5 * t ^ 4
|
||||
else
|
||||
return 1 - 0.5 * (2 - t) ^ 4
|
||||
end
|
||||
end
|
||||
function this.inQuint(t) return t ^ 5 end
|
||||
function this.outQuint(t) return 1 - (1 - t) ^ 5 end
|
||||
function this.inOutQuint(t)
|
||||
t = t * 2
|
||||
if t < 1 then
|
||||
return 0.5 * t ^ 5
|
||||
else
|
||||
return 1 - 0.5 * (2 - t) ^ 5
|
||||
end
|
||||
end
|
||||
function this.inExpo(t) return 1000 ^ (t - 1) - 0.001 end
|
||||
function this.outExpo(t) return 0.999 - 1000 ^ -t end
|
||||
function this.inOutExpo(t)
|
||||
t = t * 2
|
||||
if t < 1 then
|
||||
return 0.5 * 1000 ^ (t - 1) - 0.0005
|
||||
else
|
||||
return 0.9995 - 0.5 * 1000 ^ (1 - t)
|
||||
end
|
||||
end
|
||||
function this.inCirc(t) return 1 - sqrt(1 - t * t) end
|
||||
function this.outCirc(t) return sqrt(-t * t + 2 * t) end
|
||||
function this.inOutCirc(t)
|
||||
t = t * 2
|
||||
if t < 1 then
|
||||
return 0.5 - 0.5 * sqrt(1 - t * t)
|
||||
else
|
||||
t = t - 2
|
||||
return 0.5 + 0.5 * sqrt(1 - t * t)
|
||||
end
|
||||
end
|
||||
|
||||
function this.inElastic(t)
|
||||
t = t - 1
|
||||
return -(pow(2, 10 * t) * sin((t - 0.075) * (2 * pi) / 0.3))
|
||||
end
|
||||
function this.outElastic(t)
|
||||
return pow(2, -10 * t) * sin((t - 0.075) * (2 * pi) / 0.3) + 1
|
||||
end
|
||||
function this.inOutElastic(t)
|
||||
t = t * 2 - 1
|
||||
if t < 0 then
|
||||
return -0.5 * pow(2, 10 * t) * sin((t - 0.1125) * 2 * pi / 0.45)
|
||||
else
|
||||
return pow(2, -10 * t) * sin((t - 0.1125) * 2 * pi / 0.45) * 0.5 + 1
|
||||
end
|
||||
end
|
||||
|
||||
function this.inBack(t) return t * t * (2.70158 * t - 1.70158) end
|
||||
function this.outBack(t)
|
||||
t = t - 1
|
||||
return (t * t * (2.70158 * t + 1.70158)) + 1
|
||||
end
|
||||
function this.inOutBack(t)
|
||||
t = t * 2
|
||||
if t < 1 then
|
||||
return 0.5 * (t * t * (3.5864016 * t - 2.5864016))
|
||||
else
|
||||
t = t - 2
|
||||
return 0.5 * (t * t * (3.5864016 * t + 2.5864016) + 2)
|
||||
end
|
||||
end
|
||||
|
||||
function this.outBounce(t)
|
||||
if t < 1 / 2.75 then
|
||||
return 7.5625 * t * t
|
||||
elseif t < 2 / 2.75 then
|
||||
t = t - 1.5 / 2.75
|
||||
return 7.5625 * t * t + 0.75
|
||||
elseif t < 2.5 / 2.75 then
|
||||
t = t - 2.25 / 2.75
|
||||
return 7.5625 * t * t + 0.9375
|
||||
else
|
||||
t = t - 2.625 / 2.75
|
||||
return 7.5625 * t * t + 0.984375
|
||||
end
|
||||
end
|
||||
function this.inBounce(t) return 1 - this.outBounce(1 - t) end
|
||||
function this.inOutBounce(t)
|
||||
if t < 0.5 then
|
||||
return this.inBounce(t * 2) * 0.5
|
||||
else
|
||||
return this.outBounce(t * 2 - 1) * 0.5 + 0.5
|
||||
end
|
||||
end
|
||||
|
||||
function this.inSine(x)
|
||||
return 1 - cos(x * (pi * 0.5))
|
||||
end
|
||||
|
||||
function this.outSine(x)
|
||||
return sin(x * (pi * 0.5))
|
||||
end
|
||||
|
||||
function this.inOutSine(x)
|
||||
return 0.5 - 0.5 * cos(x * pi)
|
||||
end
|
||||
|
||||
return this
|
491
main.lua
|
@ -1,491 +0,0 @@
|
|||
require 'const'
|
||||
require 'util'
|
||||
|
||||
constr = require 'constructors'
|
||||
|
||||
assets = require 'lib.assets'
|
||||
ease = require 'lib.ease'
|
||||
bench = require 'lib.benchmark'
|
||||
|
||||
sprites = {}
|
||||
sound_path = {}
|
||||
music_path = {}
|
||||
|
||||
debug = false
|
||||
|
||||
food = {}
|
||||
feesh = {}
|
||||
|
||||
local sheets = {}
|
||||
|
||||
local function newAnimation(image, width, height)
|
||||
local animation = {}
|
||||
animation.spriteSheet = image;
|
||||
animation.quads = {};
|
||||
animation.width = width
|
||||
animation.height = height
|
||||
|
||||
for y = 0, image:getHeight() - height, height do
|
||||
for x = 0, image:getWidth() - width, width do
|
||||
table.insert(animation.quads, love.graphics.newQuad(x, y, width, height, image:getDimensions()))
|
||||
end
|
||||
end
|
||||
|
||||
return animation
|
||||
end
|
||||
|
||||
local function fishsprite(size, hungry, anim)
|
||||
-- anim is turn, swim, eat or die
|
||||
if anim == 'die' then hungry = false end
|
||||
|
||||
local spritename = size .. '_' .. (hungry and 'hungry_' or '') .. anim
|
||||
local spr = sprites['fish/' .. spritename]
|
||||
return newAnimation(spr, spr:getWidth()/10, spr:getHeight())
|
||||
end
|
||||
|
||||
function love.load()
|
||||
assets.clear()
|
||||
assets.load('assets')
|
||||
|
||||
sheets.wavecenter = newAnimation(sprites['wave/wavecenter'], sprites['wave/wavecenter']:getWidth(), sprites['wave/wavecenter']:getHeight()/12)
|
||||
sheets.waveside = newAnimation(sprites['wave/waveside'], sprites['wave/waveside']:getWidth(), sprites['wave/waveside']:getHeight()/12)
|
||||
|
||||
sheets.food1 = newAnimation(sprites['food/1'], sprites['food/1']:getWidth()/10, sprites['food/1']:getHeight())
|
||||
|
||||
for i = 1, 10 do
|
||||
table.insert(feesh, constr.fish(math.random(), math.random()))
|
||||
end
|
||||
end
|
||||
|
||||
local frame = 0
|
||||
local unfocusinterval = 5
|
||||
function love.update(dt)
|
||||
frame = frame + 1
|
||||
bench.update()
|
||||
|
||||
bench.startBenchmark('update')
|
||||
bench.startBenchmark('update_food')
|
||||
local fishgoals = {}
|
||||
for i,f in ipairs(food) do
|
||||
f.y = f.y + dt * f.speed
|
||||
f.time = f.time + dt
|
||||
f.y = clamp(f.y, 0, 0.9)
|
||||
|
||||
if f.y == 0.9 then
|
||||
f.deathtimer = f.deathtimer + dt
|
||||
end
|
||||
|
||||
if f.goal == 0 or not f.goal then
|
||||
for i,n in ipairs(feesh) do
|
||||
if not fishgoals[i] and n.eattimer <= 0 then
|
||||
f.goal = i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if f.deathtimer > 1 then
|
||||
table.remove(food, i)
|
||||
else
|
||||
fishgoals[f.goal] = i
|
||||
end
|
||||
end
|
||||
bench.stopBenchmark('update_food')
|
||||
|
||||
bench.startBenchmark('update_fish')
|
||||
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
|
||||
if n.eattimer < -15 then
|
||||
str = str * 1.3
|
||||
end
|
||||
|
||||
if --[[love.mouse.isDown(1) or]] fishgoals[fi] then
|
||||
local mx, my = love.mouse.getPosition()
|
||||
mx = mx / love.graphics.getWidth()
|
||||
my = my / love.graphics.getHeight()
|
||||
|
||||
if fishgoals[fi] and food[fishgoals[fi]] then
|
||||
mx = food[fishgoals[fi]].x
|
||||
my = food[fishgoals[fi]].y
|
||||
end
|
||||
angle = math.deg(math.atan2(my - n.y, mx - n.x)) + math.random(-FISH_FOLLOW_RANDOM, FISH_FOLLOW_RANDOM)
|
||||
end
|
||||
|
||||
local x = math.cos(math.rad(angle)) * str
|
||||
local y = math.sin(math.rad(angle)) * str
|
||||
|
||||
if not (--[[love.mouse.isDown(1) or ]]fishgoals[fi]) 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 = (FOOTER_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
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
if fishgoals[fi] and frame % FISH_COLISSION_CHECK_FREQ == 0 then
|
||||
local f = food[fishgoals[fi]]
|
||||
if f then
|
||||
local dist = math.abs(n.render.x - f.x) + math.abs(n.render.y - f.y)
|
||||
|
||||
if dist < FOOD_HITBOX then
|
||||
table.remove(food, fishgoals[fi])
|
||||
n.eattimer = FISH_FOOD_COOLDOWN
|
||||
n.render.eattimer = 0
|
||||
|
||||
if n.lifetime > FISH_AGE_MEDIUM then
|
||||
n.size = 1
|
||||
end
|
||||
if n.lifetime > FISH_AGE_BIG then
|
||||
n.size = 2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
bench.stopBenchmark('update_fish_position')
|
||||
|
||||
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) * 100) % 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
|
||||
|
||||
n.render.turndir = math.sign(n.render.x - n.render.prevx)
|
||||
|
||||
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')
|
||||
end
|
||||
bench.stopBenchmark('update_fish')
|
||||
bench.stopBenchmark('update')
|
||||
end
|
||||
|
||||
function love.draw()
|
||||
bench.startBenchmark('render')
|
||||
|
||||
bench.startBenchmark('render_tank')
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
|
||||
local sw, sh = love.graphics.getDimensions()
|
||||
local footerheight = FOOTER_HEIGHT * sw/640
|
||||
local yscale = (sh-footerheight)/sh
|
||||
|
||||
local sample = fishsprite('medium', false, 'swim')
|
||||
local spritescale = (math.min(sw, sh)/FISH_SIZE) / math.min(sample.width, sample.height)
|
||||
|
||||
stretchto(sprites['bg/1'], 0, footerheight - FOOTER_HEIGHT, 0, sw, sh - (footerheight - FOOTER_HEIGHT))
|
||||
|
||||
-- waves
|
||||
bench.startBenchmark('render_wave')
|
||||
local wavecount = round(sw / sprites['wave/wavecenter']:getWidth())
|
||||
local wavescale = sw / (wavecount * sprites['wave/wavecenter']:getWidth())
|
||||
for i = 1, wavecount do
|
||||
local a = (i - 1) / wavecount
|
||||
local x = a * sw
|
||||
local frame = round((1 - math.abs(love.timer.getTime()%2-1)) * #sheets.wavecenter.quads)
|
||||
love.graphics.setBlendMode('add')
|
||||
|
||||
local sheet = sheets.wavecenter
|
||||
local sizex = 1
|
||||
if i == 1 or i == wavecount then
|
||||
sheet = sheets.waveside
|
||||
end
|
||||
if i == wavecount then
|
||||
sizex = -1
|
||||
end
|
||||
love.graphics.draw(sheet.spriteSheet, sheet.quads[math.max(frame, 1)], x + (sprites['wave/wavecenter']:getWidth() * wavescale)/2, footerheight + 20, 0, wavescale * sizex, wavescale, sprites['wave/wavecenter']:getWidth()/2)
|
||||
end
|
||||
love.graphics.setBlendMode('alpha')
|
||||
bench.stopBenchmark('render_wave')
|
||||
|
||||
-- shadow
|
||||
bench.startBenchmark('render_shadow')
|
||||
for i, n in ipairs(feesh) do
|
||||
love.graphics.setColor(1, 1, 1, n.render.y + 0.2)
|
||||
love.graphics.draw(sprites['shadow'], n.render.x * sw - (sprites['shadow']:getWidth() * spritescale)/2, sh - sh * 0.18 - (sprites['shadow']:getHeight() * spritescale)/2 + n.render.y * sh * 0.08, 0, spritescale, spritescale)
|
||||
end
|
||||
bench.stopBenchmark('render_shadow')
|
||||
-- all the fish
|
||||
bench.startBenchmark('render_fish')
|
||||
for i, n in ipairs(feesh) do
|
||||
local x = n.render.x * sw
|
||||
local y = n.render.y * sh
|
||||
|
||||
-- rest of feesh
|
||||
local size = 'small'
|
||||
local anim = 'swim'
|
||||
|
||||
local sample = fishsprite('medium', false, 'swim')
|
||||
|
||||
local sizex = 1
|
||||
local turn = n.render.turn
|
||||
if n.render.turndir == -1 then turn = 1 - turn; sizex = -1 end
|
||||
|
||||
local turnframe = math.floor(turn * (#sample.quads - 1)) + 1
|
||||
if #sample.quads == 10 then
|
||||
sizex = -1 * sizex
|
||||
turnframe = 1
|
||||
end
|
||||
|
||||
local frame = math.floor(n.render.swim * (#sample.quads - 1)) + 1
|
||||
|
||||
if turnframe ~= 1 and turnframe ~= 10 then
|
||||
anim = 'turn'
|
||||
frame = turnframe
|
||||
end
|
||||
|
||||
if n.render.eattimer <= 1 then
|
||||
anim = 'eat'
|
||||
frame = math.floor(n.render.eattimer * (#sample.quads - 1)) + 1
|
||||
end
|
||||
|
||||
local angle = n.render.angle
|
||||
if angle > math.pi/2 then
|
||||
angle = angle - math.pi
|
||||
end
|
||||
if angle < -math.pi/2 then
|
||||
angle = angle + math.pi
|
||||
end
|
||||
|
||||
angle = angle * math.max(math.min((-math.abs(angle) + math.pi * 0.5) / (math.pi * 0.5) * 2, 1), 0)
|
||||
angle = angle * 0.5
|
||||
|
||||
if n.size == 0 then
|
||||
size = 'small'
|
||||
elseif n.size == 1 then
|
||||
size = 'medium'
|
||||
elseif n.size == 2 then
|
||||
size = 'big'
|
||||
elseif n.size == 3 then
|
||||
size = 'king'
|
||||
end
|
||||
|
||||
local sheet = fishsprite(size, false, anim)
|
||||
local sadsheet = fishsprite(size, true, anim)
|
||||
|
||||
local alpha = n.render.hungry == 1 and 0 or 1
|
||||
love.graphics.setColor(1, 1, 1, alpha)
|
||||
love.graphics.draw(sheet.spriteSheet, sheet.quads[math.max(math.min(frame, #sample.quads), 1)], x, y, angle, sizex * spritescale, spritescale, sample.width/2, sample.height/2)
|
||||
love.graphics.setColor(1, 1, 1, n.render.hungry)
|
||||
love.graphics.draw(sadsheet.spriteSheet, sheet.quads[math.max(math.min(frame, #sample.quads), 1)], x, y, angle, sizex * spritescale, spritescale, sample.width/2, sample.height/2)
|
||||
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
if debug then love.graphics.print(shrt(n.eattimer), x + 20, y + 20) end
|
||||
|
||||
if debug then
|
||||
for _,e in ipairs(n.eases) do
|
||||
love.graphics.setColor(1, 0, 0, 0.75)
|
||||
love.graphics.line(e.fromx * sw, e.fromy * sh, e.x * sw, e.y * sh)
|
||||
|
||||
love.graphics.setColor(0, 0, 1, 0.75)
|
||||
love.graphics.line(mix(e.fromx, e.x, FISH_EASE(e.a)) * sw, mix(e.fromy, e.y, FISH_EASE(e.a)) * sh, n.render.x * sw, n.render.y * sh)
|
||||
end
|
||||
|
||||
local subdiv = DEBUG_FISH_PATH_SUBDIVISIONS
|
||||
local adv = DEBUG_FISH_PREDICT_AMOUNT
|
||||
local pos = {}
|
||||
local valid = {}
|
||||
|
||||
for i = 1, subdiv do
|
||||
local a = ((i - 1) / (subdiv - 1)) * (adv * 2) - adv
|
||||
|
||||
local sumx = 0
|
||||
local sumy = 0
|
||||
local mina = 0
|
||||
local maxa = 1
|
||||
for _, e in ipairs(n.eases) do
|
||||
local a = e.a + a
|
||||
mina = math.min(mina, a)
|
||||
maxa = math.max(maxa, a)
|
||||
sumx = sumx + mix(e.fromx, e.x, FISH_EASE(a))
|
||||
sumy = sumy + mix(e.fromy, e.y, FISH_EASE(a))
|
||||
end
|
||||
|
||||
table.insert(pos, sumx / #n.eases * sw)
|
||||
table.insert(pos, sumy / #n.eases * sh)
|
||||
table.insert(valid, not (maxa > 1 or mina < 0))
|
||||
end
|
||||
|
||||
for i = 0, #pos/2 - 1 do
|
||||
local x1 = pos[i * 2 + 1]
|
||||
local y1 = pos[i * 2 + 1 + 1]
|
||||
local x2 = pos[i * 2 + 2 + 1]
|
||||
local y2 = pos[i * 2 + 3 + 1]
|
||||
local valid = valid[i + 1]
|
||||
|
||||
if not x2 or not y2 then break end
|
||||
|
||||
love.graphics.setColor(0, 1, 0, 1)
|
||||
if not valid then love.graphics.setColor(0, 0.5, 1, 0.7) end
|
||||
|
||||
love.graphics.line(x1, y1, x2, y2)
|
||||
end
|
||||
end
|
||||
end
|
||||
bench.stopBenchmark('render_fish')
|
||||
|
||||
bench.startBenchmark('render_food')
|
||||
for _,f in ipairs(food) do
|
||||
local sheet = sheets.food1
|
||||
local x = f.x * sw
|
||||
local y = f.y * sh
|
||||
local frame = math.floor((f.time%1) * #sheet.quads) + 1
|
||||
|
||||
love.graphics.setColor(1, 1, 1, 1 - f.deathtimer)
|
||||
|
||||
love.graphics.draw(sheet.spriteSheet, sheet.quads[math.max(math.min(frame, #sheet.quads), 1)], x, y, 0, spritescale, spritescale, sheet.width/2, sheet.height/2)
|
||||
end
|
||||
bench.stopBenchmark('render_food')
|
||||
bench.stopBenchmark('render_tank')
|
||||
|
||||
bench.startBenchmark('render_footer')
|
||||
local base = sprites['footer/base']
|
||||
local size = footerheight / FOOTER_HEIGHT
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.draw(base, 0, 0, 0, size, size)
|
||||
|
||||
-- the game is making me do this. im sorry
|
||||
local x = 19
|
||||
for b = 1, 7 do
|
||||
local hovered = mouseOverBox(x, 3, sprites['footer/buttonbg']:getWidth(), sprites['footer/buttonbg']:getHeight())
|
||||
|
||||
if hovered and love.mouse.isDown(1) then
|
||||
love.graphics.draw(sprites['footer/buttonbg_down'], x, 3)
|
||||
elseif hovered then
|
||||
love.graphics.draw(sprites['footer/buttonbg_hover'], x, 3)
|
||||
else
|
||||
love.graphics.draw(sprites['footer/buttonbg'], x, 3)
|
||||
end
|
||||
|
||||
-- insert sprite of item here
|
||||
-- insert price of item here
|
||||
love.graphics.setBlendMode('add')
|
||||
love.graphics.draw(sprites['footer/reflection'], x, 3)
|
||||
love.graphics.setBlendMode('alpha')
|
||||
-- insert closing/opening animation here
|
||||
|
||||
local incr = 69 -- its like button positions but forcefully shoved into a recursive function :D
|
||||
if b == 2 then incr = 57 end
|
||||
if b >= 3 then incr = 73 end
|
||||
x = x + incr
|
||||
end
|
||||
bench.stopBenchmark('render_footer')
|
||||
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.print('FPS: ' .. 1 / love.timer.getDelta(), 0, sh - 16)
|
||||
|
||||
if debug then bench.renderBenchmark() end
|
||||
bench.stopBenchmark('render')
|
||||
end
|
||||
|
||||
function love.mousepressed(x, y, b)
|
||||
if b == 2 then
|
||||
table.insert(food, constr.food(x/love.graphics.getWidth(), y/love.graphics.getHeight(), 1))
|
||||
end
|
||||
end
|
||||
|
||||
function love.keypressed(key)
|
||||
if key == 'f3' then
|
||||
debug = not debug
|
||||
end
|
||||
end
|
58
util.lua
|
@ -1,58 +0,0 @@
|
|||
function mix(x, y, a)
|
||||
return x * (1 - a) + y * a
|
||||
end
|
||||
function clamp(a, x, y)
|
||||
return math.min(math.max(a, x), y)
|
||||
end
|
||||
function round(x)
|
||||
if x%1 >= 0.5 then return math.ceil(x) end
|
||||
return math.floor(x)
|
||||
end
|
||||
function sum(tbl)
|
||||
local sum = 0
|
||||
for _,v in ipairs(tbl) do
|
||||
sum = sum + v
|
||||
end
|
||||
return sum/#tbl
|
||||
end
|
||||
function shrt(num)
|
||||
return math.floor(num * 10000) / 10000
|
||||
end
|
||||
|
||||
function pointInside(px,py,x,y,w,h)
|
||||
return px > x and px < x+w and py > y and py < y+h
|
||||
end
|
||||
|
||||
function mouseOverBox(x,y,w,h)
|
||||
return pointInside(love.mouse.getX(), love.mouse.getY(), x, y, w, h)
|
||||
end
|
||||
|
||||
function stretchto(sprite, x, y, r, sx, sy, ox, oy)
|
||||
love.graphics.draw(sprite, x, y, r, sx/sprite:getWidth(), sy/sprite:getHeight(), ox, oy)
|
||||
end
|
||||
function drawcenteredquad(sprite, quad, x, y, r, sx, sy, ox, oy)
|
||||
local sw, sh = quad:getTextureDimensions()
|
||||
love.graphics.draw(sprite, quad, x - (sw * (sx or 1))/2, y - (sh * (sy or 1))/2, r, sx, sy, (ox or 0) + sw/2, (oy or 0) + sh/2)
|
||||
end
|
||||
function drawcentered(sprite, x, y, r, sx, sy, ox, oy)
|
||||
love.graphics.draw(sprite, x - (sprite:getWidth() * (sx or 1))/2, y - (sprite:getHeight() * (sy or 1))/2, r, sx, sy, (ox or 0) + sprite:getWidth()/2, (oy or 0) + sprite:getHeight()/2)
|
||||
end
|
||||
|
||||
function table.deepcopy(orig)
|
||||
local orig_type = type(orig)
|
||||
local copy
|
||||
if orig_type == 'table' then
|
||||
copy = {}
|
||||
for orig_key, orig_value in next, orig, nil do
|
||||
copy[table.deepcopy(orig_key)] = table.deepcopy(orig_value)
|
||||
end
|
||||
setmetatable(copy, table.deepcopy(getmetatable(orig)))
|
||||
else -- number, string, boolean, etc
|
||||
copy = orig
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
function math.sign(a)
|
||||
if a >= 0 then return 1 else return -1 end
|
||||
end
|