start replacing arrays with intrusive slists
`add` costs ten cycles. `push_back` isn't actually any better, but bury_the_dead can get pretty bad, especially for large arrays (like the bullets collections). also replacing the kill loop structure with the `strip` call removes a massive amount of code repetition that's costing me a lot of tokens. I think the final result is _probably_ actually slower because of function call overhead per iteration except when there are collisions on many frames; hopefully the headroom bought by the bucket collider is enough because I'm definitely going to need the tokens.
This commit is contained in:
parent
bd67006e3c
commit
1ba869b644
271
updatedshmup.p8
271
updatedshmup.p8
@ -21,6 +21,95 @@ function csv(s)
|
|||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- generate standard "overlay"
|
||||||
|
-- constructor for type tt.
|
||||||
|
-- if more is defined, generated
|
||||||
|
-- new calls more(ret) after
|
||||||
|
-- ret is definitely not nil
|
||||||
|
-- before calling setmetatable.
|
||||||
|
-- use to initialize mutables.
|
||||||
|
function mknew(tt, more)
|
||||||
|
local mt = {__index=tt}
|
||||||
|
-- check "more" only once ever
|
||||||
|
if more then
|
||||||
|
tt.new = function(ret)
|
||||||
|
if (not ret) ret = {}
|
||||||
|
more(ret)
|
||||||
|
setmetatable(ret, mt)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
else
|
||||||
|
tt.new=function(ret)
|
||||||
|
if (not ret) ret = {}
|
||||||
|
setmetatable(ret, mt)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
linked_list = {}
|
||||||
|
mknew(linked_list, function(x)
|
||||||
|
x.next=nil
|
||||||
|
x.tail=x
|
||||||
|
end)
|
||||||
|
|
||||||
|
function linked_list:push_back(x)
|
||||||
|
self.tail.next = x
|
||||||
|
self.tail = x
|
||||||
|
end
|
||||||
|
|
||||||
|
function linked_list:push_front(x)
|
||||||
|
if (not self.next) self.tail = x
|
||||||
|
x.next = self.next
|
||||||
|
self.next = x
|
||||||
|
end
|
||||||
|
|
||||||
|
-- vore eats another linked list
|
||||||
|
-- by appending its contents.
|
||||||
|
-- the ingested linked
|
||||||
|
-- list is no longer valid.
|
||||||
|
function linked_list:vore(x)
|
||||||
|
if (not x.next) return
|
||||||
|
self.tail.next = x.next
|
||||||
|
self.tail = x.tail
|
||||||
|
end
|
||||||
|
|
||||||
|
-- strip calls f(x) for each
|
||||||
|
-- node, removing each node for
|
||||||
|
-- which f(x) returns true. it
|
||||||
|
-- returns the new tail; nil
|
||||||
|
-- if the list is now empty.
|
||||||
|
function linked_list:strip(f)
|
||||||
|
local p, n = self, self.next
|
||||||
|
while n do
|
||||||
|
if f(n) then
|
||||||
|
p.next = n.next
|
||||||
|
else
|
||||||
|
p = n
|
||||||
|
end
|
||||||
|
n = n.next
|
||||||
|
end
|
||||||
|
self.tail = p
|
||||||
|
return p
|
||||||
|
end
|
||||||
|
|
||||||
|
function linked_list:pop_front()
|
||||||
|
local ret = self.next
|
||||||
|
if (not ret) return
|
||||||
|
self.next = ret.next
|
||||||
|
if (not ret.next) ret.tail = nil
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
function linked_list:fix_tail()
|
||||||
|
local p, n = self, self.next
|
||||||
|
while n do
|
||||||
|
p = n
|
||||||
|
n = n.next
|
||||||
|
end
|
||||||
|
self.tail = p
|
||||||
|
end
|
||||||
|
|
||||||
function _init()
|
function _init()
|
||||||
init_bullet_mt()
|
init_bullet_mt()
|
||||||
init_powerup_mt()
|
init_powerup_mt()
|
||||||
@ -47,125 +136,99 @@ function init_hpcols()
|
|||||||
hpcols = hpcols_lut[min(primary_ship.maxhp,6)]
|
hpcols = hpcols_lut[min(primary_ship.maxhp,6)]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function new_linked()
|
||||||
|
local ret = {}
|
||||||
|
ret.tail = ret
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
function wipe_level()
|
function wipe_level()
|
||||||
primary_ship = new_p1()
|
primary_ship = new_p1()
|
||||||
init_hpcols()
|
init_hpcols()
|
||||||
pships = {primary_ship}
|
pships = linked_list:new()
|
||||||
eships = {}
|
pships:push_back(primary_ship)
|
||||||
pbullets = {}
|
eships = linked_list:new()
|
||||||
ebullets = {}
|
pbullets = linked_list:new()
|
||||||
intangibles_fg = {}
|
ebullets = linked_list:new()
|
||||||
intangibles_bg = {}
|
intangibles_fg = linked_list:new()
|
||||||
events = {}
|
intangibles_bg = linked_list:new()
|
||||||
|
events = linked_list:new()
|
||||||
end
|
end
|
||||||
|
|
||||||
function _update60()
|
function _update60()
|
||||||
updategame()
|
updategame()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function call_f(x)
|
||||||
|
return x:f()
|
||||||
|
end
|
||||||
|
|
||||||
|
function call_move(x)
|
||||||
|
return x:move()
|
||||||
|
end
|
||||||
|
|
||||||
function updategame()
|
function updategame()
|
||||||
leveldone = level_frame()
|
leveldone = level_frame()
|
||||||
new_events = {}
|
new_events = new_linked()
|
||||||
local deaths = {}
|
events:strip(call_f)
|
||||||
for i, e in ipairs(events) do
|
events:vore(new_events)
|
||||||
if (e()) add(deaths, i)
|
for _, lst in ipairs{intangibles_bg, pships, eships, pbullets, ebullets} do
|
||||||
end
|
lst:strip(call_move)
|
||||||
bury_the_dead(events, deaths)
|
end
|
||||||
foreach(new_events, function(e)
|
|
||||||
add(events, e)
|
pships:strip(
|
||||||
end)
|
function(ps)
|
||||||
deaths = {}
|
local pbox, pded = hurtbox(ps), false
|
||||||
for i, x in ipairs(intangibles_bg) do
|
eships:strip(
|
||||||
if (x:move()) add(deaths, i)
|
function(es)
|
||||||
end
|
if (~collides(pbox, hurtbox(es))) return
|
||||||
bury_the_dead(intangibles_bg, deaths)
|
pded = pded or ps:hitship(es)
|
||||||
for _, tbl in ipairs({pships, eships, pbullets, ebullets, intangibles}) do
|
return es:hitship(ps)
|
||||||
local deaths = {}
|
end
|
||||||
for i, x in ipairs(tbl) do
|
)
|
||||||
if (x:move()) add(deaths, i)
|
return pded
|
||||||
end
|
end
|
||||||
bury_the_dead(tbl, deaths)
|
)
|
||||||
end
|
pships:strip(
|
||||||
--then, calculate collisions
|
function(ps)
|
||||||
local pdeaths = {}
|
local pbox, pded = hurtbox(ps), false
|
||||||
local edeaths = {}
|
ebullets:strip(
|
||||||
local eskips = {}
|
function(eb)
|
||||||
-- todo: always use a collider,
|
if (~collides(pbox, hurtbox(eb))) return
|
||||||
-- it saves if pships is as low as 2s
|
pded = pded or ps:hitbullet(eb)
|
||||||
-- pships usually contians 1 thing,
|
return eb:hitship(ps)
|
||||||
-- so don't bother with a bucket collider
|
end
|
||||||
for ip, ps in ipairs(pships) do
|
)
|
||||||
for ie, es in ipairs(eships) do
|
return pded
|
||||||
if not eskips[ie] then
|
end
|
||||||
if collides(hurtbox(ps), hurtbox(es)) then
|
)
|
||||||
if (es:hitship(ps)) then
|
|
||||||
add(edeaths, ie)
|
|
||||||
eskips[ie] = true
|
|
||||||
end
|
|
||||||
if ps:hitship(es) then
|
|
||||||
add(pdeaths, ip)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
bury_the_dead(pships, pdeaths)
|
|
||||||
bury_the_dead(eships, edeaths)
|
|
||||||
pdeaths = {}
|
|
||||||
edeaths = {}
|
|
||||||
eskips = {}
|
|
||||||
for ip, ps in ipairs(pships) do
|
|
||||||
for ie, eb in ipairs(ebullets) do
|
|
||||||
if not eskips[ie] then
|
|
||||||
if collides(hurtbox(ps), hurtbox(eb)) then
|
|
||||||
local dead = false
|
|
||||||
if ps:hitbullet(eb) then
|
|
||||||
add(pdeaths, ip)
|
|
||||||
dead = true
|
|
||||||
end
|
|
||||||
if (eb:hitship(ps)) then
|
|
||||||
add(edeaths, ie)
|
|
||||||
eskips[ie] =true
|
|
||||||
end
|
|
||||||
if (dead) break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
bury_the_dead(pships, pdeaths)
|
|
||||||
bury_the_dead(ebullets, edeaths)
|
|
||||||
pdeaths = {}
|
|
||||||
edeaths = {}
|
|
||||||
-- many bullets and many enemy ships;
|
-- many bullets and many enemy ships;
|
||||||
-- use bucket collider for efficiency
|
-- use bucket collider for efficiency
|
||||||
local pbullet_collider = new_collider()
|
local pbullet_collider = new_collider()
|
||||||
for idx, pb in ipairs(pbullets) do
|
local p, n := pbullets, pbullets.next
|
||||||
pb.___pbullets_idx = idx
|
while n do
|
||||||
pbullet_collider:insert(pb)
|
n.prev = p
|
||||||
|
pbullet_collider:insert(n)
|
||||||
|
p = n
|
||||||
|
n = p.next
|
||||||
end
|
end
|
||||||
|
|
||||||
for es_idx, es in ipairs(eships) do
|
eships:strip(
|
||||||
for pb in all(pbullet_collider:get_collisions(es)) do
|
function(es)
|
||||||
local dead = false
|
for pb in all(pbullet_collider:get_collisions(es)) do
|
||||||
if es:hitbullet(pb) then
|
if pb:hitship(es) then
|
||||||
add(edeaths, es_idx)
|
pbullet_collider:hide(pb)
|
||||||
dead=true
|
pb.prev.next = pb.next
|
||||||
|
if (pb.next) pb.next.prev = pb.prev
|
||||||
|
end
|
||||||
|
if (es:hitbullet(pb)) return true
|
||||||
end
|
end
|
||||||
if pb:hitship(es) then
|
|
||||||
add(pdeaths, pb.___pbullets_idx)
|
|
||||||
pbullet_collider:hide(pb)
|
|
||||||
end
|
|
||||||
if (dead) break
|
|
||||||
end
|
end
|
||||||
end
|
)
|
||||||
bury_the_dead(eships, edeaths)
|
|
||||||
bury_the_dead(pbullets, pdeaths)
|
intangibles_fg:strip(call_move)
|
||||||
for i, x in ipairs(intangibles_fg) do
|
|
||||||
if (x:move()) add(deaths, i)
|
|
||||||
end
|
|
||||||
bury_the_dead(intangibles_fg, deaths)
|
|
||||||
|
|
||||||
if leveldone and ((#eships + #ebullets + #events) == 0) then
|
if leveldone and ((#eships + #ebullets + #events) == 0) then
|
||||||
state = win
|
state = win
|
||||||
end
|
end
|
||||||
@ -174,6 +237,8 @@ function updategame()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- XXX BOOKMARK XXX
|
||||||
|
|
||||||
function _draw()
|
function _draw()
|
||||||
drawgame()
|
drawgame()
|
||||||
draw_debug()
|
draw_debug()
|
||||||
|
Loading…
Reference in New Issue
Block a user